Scrapy Sitemap Spider: Как создать эффективный парсер сайтов?

Что такое Sitemap и зачем он нужен для парсинга?

Sitemap — это XML-файл, содержащий список URL-адресов сайта, предназначенный для информирования поисковых систем о структуре и доступных страницах. Для парсинга Sitemap предоставляет структурированный и полный список всех URL, что позволяет избежать необходимости обхода всего сайта вручную.

Преимущества использования Sitemap Spider

  • Полнота: Sitemap содержит практически все важные URL сайта.
  • Структурированность: XML формат обеспечивает удобный и предсказуемый способ извлечения URL.
  • Эффективность: Избегаем перебора всех ссылок на сайте, фокусируясь только на целевых страницах.
  • Актуальность: Sitemap часто обновляется, отражая изменения на сайте.

Недостатки и ограничения Sitemap Spider

  • Неполные Sitemap: Некоторые сайты могут предоставлять неполные Sitemap, пропуская отдельные страницы.
  • Устаревшие данные: Sitemap может содержать устаревшие или неработающие URL.
  • Сложность структуры: Sitemap может быть сложным и содержать несколько файлов или индексов, требующих дополнительной обработки.
  • Зависимость от доступности Sitemap: Если Sitemap недоступен или возвращает ошибки, парсинг невозможен.

Создание Scrapy проекта и установка зависимостей

Создание нового Scrapy проекта

Создайте новый проект Scrapy с помощью команды:

scrapy startproject my_project
cd my_project

Настройка файла settings.py

В settings.py настройте основные параметры Scrapy:

# settings.py

BOT_NAME = 'my_project'

SPIDER_MODULES = ['my_project.spiders']
NEWSPIDER_MODULE = 'my_project.spiders'

# Configure item pipelines
ITEM_PIPELINES = {
    'my_project.pipelines.MyProjectPipeline': 300,
}

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'ru-RU,en;q=0.5',
}

ROBOTSTXT_OBEY = False позволяет игнорировать robots.txt (использовать с осторожностью).

Разработка Sitemap Spider: Практический пример

Определение структуры Sitemap и целевых URL

Предположим, что Sitemap сайта содержит URL следующего вида:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com/product1</loc>
    <lastmod>2023-10-26</lastmod>
  </url>
  <url>
    <loc>https://example.com/product2</loc>
    <lastmod>2023-10-25</lastmod>
  </url>
</urlset>

Наша цель — извлечь URL продуктов (https://example.com/product1, https://example.com/product2).

Написание spider’а для разбора Sitemap

Создайте spider sitemap_spider.py:

import scrapy
from scrapy.spiders import SitemapSpider

class MySitemapSpider(SitemapSpider):
    name = 'my_sitemap_spider'
    sitemap_urls = ['https://example.com/sitemap.xml']
    sitemap_rules = [('/product/', 'parse_product')]

    def parse_product(self, response: scrapy.http.Response):
        """Parses product pages."""
        title = response.css('h1::text').get()
        price = response.css('.price::text').get()

        yield {
            'url': response.url,
            'title': title,
            'price': price,
        }

Здесь sitemap_urls содержит список Sitemap URL. sitemap_rules — список правил, определяющих, какие URL и каким методом обрабатывать. В данном случае, все URL, содержащие /product/, будут обработаны методом parse_product.

Реализация логики парсинга контента со страниц (Item pipelines)

Создайте items.py для определения структуры данных:

Реклама
# items.py
import scrapy

class ProductItem(scrapy.Item):
    url = scrapy.Field()
    title = scrapy.Field()
    price = scrapy.Field()

В pipelines.py определите, что делать с извлеченными данными:

# pipelines.py
class MyProjectPipeline:
    def process_item(self, item: ProductItem, spider) -> ProductItem:
        """Processes each scraped item."""
        # Example: Save to file
        with open('output.txt', 'a') as f:
            f.write(f"{item['url']} - {item['title']} - {item['price']}\n")
        return item

Обработка ошибок и исключений

Добавьте обработку ошибок в spider:

import scrapy
from scrapy.spiders import SitemapSpider

class MySitemapSpider(SitemapSpider):
    name = 'my_sitemap_spider'
    sitemap_urls = ['https://example.com/sitemap.xml']
    sitemap_rules = [('/product/', 'parse_product')]

    def parse_product(self, response: scrapy.http.Response):
        """Parses product pages, handling potential errors."""
        try:
            title = response.css('h1::text').get()
            price = response.css('.price::text').get()

            yield {
                'url': response.url,
                'title': title,
                'price': price,
            }
        except Exception as e:
            self.logger.error(f"Error parsing {response.url}: {e}")

Настройка и запуск Sitemap Spider

Запуск spider’а из командной строки

Запустите spider из командной строки:

scrapy crawl my_sitemap_spider

Сохранение результатов парсинга (CSV, JSON, база данных)

Для сохранения в JSON используйте команду:

scrapy crawl my_sitemap_spider -o output.json

Для сохранения в CSV:

scrapy crawl my_sitemap_spider -o output.csv

Для сохранения в базу данных, нужно настроить соответствующий pipeline.

Настройка параллельности и оптимизация скорости парсинга

В settings.py настройте параллельность:

# settings.py
CONCURRENT_REQUESTS = 32  # Adjust as needed
DOWNLOAD_DELAY = 0 # Adjust as needed

CONCURRENT_REQUESTS — количество параллельных запросов.
DOWNLOAD_DELAY — задержка между запросами (в секундах). Уменьшайте DOWNLOAD_DELAY осторожно, чтобы не перегрузить сервер.

Продвинутые техники и решения проблем

Обработка Sitemap с несколькими файлами или индексами

Если Sitemap содержит индекс (sitemapindex вместо urlset), используйте:

from scrapy.spiders import SitemapSpider

class MySitemapSpider(SitemapSpider):
    name = 'my_sitemap_spider'
    sitemap_urls = ['https://example.com/sitemap_index.xml'] # Sitemap index
    sitemap_rules = [('/product/', 'parse_product')]

Scrapy автоматически обработает все Sitemap, указанные в индексе.

Обход защиты от парсинга (User-Agent, задержки, прокси)

  • User-Agent: Измените User-Agent в settings.py:
# settings.py
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
  • Задержки: Используйте DOWNLOAD_DELAY и RANDOMIZE_DOWNLOAD_DELAY.
  • Прокси: Используйте прокси-серверы для обхода блокировок. Можно использовать middleware для случайного выбора прокси из списка.

Динамическая загрузка контента (Selenium integration)

Если контент загружается динамически (JavaScript), интегрируйте Scrapy с Selenium:

  1. Установите Selenium и драйвер для браузера (например, ChromeDriver).
  2. Используйте Selenium в вашем spider для загрузки страниц и получения HTML.
# Example with Selenium
from selenium import webdriver
import scrapy

class MySeleniumSpider(scrapy.Spider):
    name = 'my_selenium_spider'
    start_urls = ['https://example.com']

    def __init__(self):
        self.driver = webdriver.Chrome() # Or Firefox, etc.

    def parse(self, response):
        self.driver.get(response.url)
        # Wait for content to load (e.g., using WebDriverWait)
        html = self.driver.page_source
        # Parse html with BeautifulSoup or Scrapy selectors
        # ...
        self.driver.quit()

Добавить комментарий