Scrapy и бесконечная прокрутка: как настроить сбор данных?

Что такое Scrapy и зачем он нужен?

Scrapy — это мощный фреймворк для парсинга веб-страниц, написанный на Python. Он предоставляет все необходимые инструменты для извлечения структурированных данных с веб-сайтов: от автоматической обработки запросов до удобного сохранения полученной информации. Scrapy идеально подходит для задач, требующих автоматизации сбора данных: анализ цен конкурентов, сбор новостей, мониторинг социальных сетей, агрегация данных для машинного обучения и многое другое. В отличие от простых библиотек, таких как requests и BeautifulSoup, Scrapy предлагает более структурированный и масштабируемый подход, облегчая разработку сложных парсеров.

Проблема бесконечной прокрутки при парсинге

Многие современные веб-сайты используют механизм бесконечной прокрутки (infinite scroll) для динамической подгрузки контента. Вместо традиционной пагинации, когда данные разбиваются на страницы, сайт добавляет новую порцию информации по мере того, как пользователь прокручивает страницу вниз. Это создает значительные трудности для стандартных методов парсинга, поскольку данные не загружаются сразу, а появляются постепенно, часто через AJAX-запросы. Простой переход по ссылкам страниц здесь не работает.

Обзор статьи: что мы будем настраивать

В этой статье мы рассмотрим различные способы обхода бесконечной прокрутки с использованием Scrapy. Мы научимся анализировать сетевые запросы, находить API, отвечающие за подгрузку данных, и настраивать Scrapy-паука для автоматической пагинации. Также мы рассмотрим альтернативный подход с использованием Selenium для сайтов, активно использующих JavaScript для рендеринга контента.

Анализ сайта с бесконечной прокруткой

Инструменты разработчика: находим запросы к API

Первым шагом является анализ сетевых запросов, которые выполняет сайт при прокрутке. Для этого используем инструменты разработчика в браузере (обычно открываются клавишей F12). Переходим во вкладку «Network» и начинаем прокручивать страницу. Мы должны увидеть новые запросы, появляющиеся в списке. Ищем запросы типа XHR (XMLHttpRequest) или Fetch/XHR — это запросы, которые отправляются в фоновом режиме для получения данных. Обратите внимание на URL этих запросов.

Изучение структуры JSON-ответа (если есть)

Если запрос возвращает данные в формате JSON, изучаем его структуру. Это поможет нам понять, какие поля содержат интересующую нас информацию, и как правильно ее извлечь. Инструменты разработчика позволяют удобно просматривать JSON-ответ в древовидном формате.

Например, ответ может иметь следующую структуру:

{
  "items": [
    {
      "id": 1,
      "title": "Заголовок 1",
      "description": "Описание 1"
    },
    {
      "id": 2,
      "title": "Заголовок 2",
      "description": "Описание 2"
    }
  ],
  "has_next": true,
  "next_page_token": "token_for_next_page"
}

Здесь items — это массив объектов, каждый из которых содержит информацию об отдельном элементе. has_next указывает, есть ли следующая страница данных, а next_page_token — токен, необходимый для запроса следующей страницы.

Определение параметров запроса для пагинации

Важно понять, какие параметры передаются в запросе к API для управления пагинацией. Часто это параметры, такие как номер страницы (page), размер страницы (limit), смещение (offset) или токен (next_page_token). Определив эти параметры, мы сможем программно формировать запросы для получения всех данных.

Настройка Scrapy-паука для обработки бесконечной прокрутки

Создание Scrapy-проекта и паука

Сначала создадим новый Scrapy-проект:

scrapy startproject myproject
cd myproject
scrapy genspider myspider example.com

Это создаст базовую структуру проекта и паука с именем myspider для домена example.com.

Формирование запросов к API с помощью Scrapy

В Scrapy мы используем scrapy.Request для отправки запросов. Для формирования запросов к API с пагинацией, мы должны использовать данные, полученные на этапе анализа (параметры пагинации, URL API).

import scrapy
import json
from typing import Dict, Any

class MySpider(scrapy.Spider):
    name = 'myspider'
    allowed_domains = ['example.com']
    api_url = 'https://example.com/api/items'
    start_token = ''  # Initial token or page number

    def start_requests(self):
        yield scrapy.Request(f'{self.api_url}?token={self.start_token}', self.parse_api)

    def parse_api(self, response):
        data: Dict[str, Any] = json.loads(response.text)

        # Extract items from the JSON response
        for item in data.get('items', []):
            yield item  # Or yield a Scrapy Item object

        # Check if there is a next page and create a new request
        if data.get('has_next'):
            next_token = data.get('next_page_token')
            yield scrapy.Request(f'{self.api_url}?token={next_token}', self.parse_api)
Реклама

Обработка ответов и извлечение данных

В методе parse_api мы обрабатываем JSON-ответ, извлекаем интересующие нас данные и создаем Scrapy Item объекты. Scrapy Items позволяют удобно структурировать и сохранять данные.

Реализация логики пагинации (переход к следующей странице)

Ключевым моментом является реализация логики пагинации. Мы проверяем, есть ли следующая страница (например, по наличию поля has_next или next_page_token в JSON-ответе) и, если да, формируем новый запрос с соответствующими параметрами для получения следующей порции данных.

Обработка динамического контента и JavaScript

Использование Selenium с Scrapy (если API недоступен)

Если сайт активно использует JavaScript для рендеринга контента, и API недоступен или его сложно анализировать, можно использовать Selenium с Scrapy. Selenium — это инструмент для автоматизации браузера, который позволяет имитировать действия пользователя, такие как прокрутка страницы.

Настройка Selenium для имитации прокрутки

Для использования Selenium, необходимо установить библиотеку selenium и драйвер для вашего браузера (например, ChromeDriver для Chrome):

pip install selenium

Затем, в коде паука, мы можем инициализировать Selenium WebDriver и использовать его для прокрутки страницы:

from selenium import webdriver
from selenium.webdriver.common.by import By
import scrapy
from scrapy.selector import Selector

class SeleniumSpider(scrapy.Spider):
    name = 'selenium_spider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com']

    def __init__(self):
        options = webdriver.ChromeOptions()
        options.add_argument('headless') # Run Chrome in headless mode
        self.driver = webdriver.Chrome(options=options)
        super().__init__()

    def close(self, spider):
        self.driver.close()

    def parse(self, response):
        self.driver.get(response.url)
        # Simulate scrolling to load more content
        for _ in range(3):  # Scroll 3 times
            self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
            time.sleep(2) # Wait for content to load

        html = self.driver.page_source
        sel = Selector(text=html)
        # Now you can use Scrapy selectors to extract the data
        items = sel.xpath('//div[@class="item"]') # Example XPATH
        for item in items:
            yield {
                'title': item.xpath('.//h2/text()').get(),
                'description': item.xpath('.//p/text()').get()
            }

Извлечение данных после загрузки контента JavaScript

После того, как Selenium подгрузил контент, мы можем использовать Scrapy-селекторы (XPath или CSS) для извлечения данных из DOM.

Практические советы и оптимизация

Задержки между запросами и избежание блокировок

Важно соблюдать задержки между запросами, чтобы не перегружать сервер и избежать блокировки. Scrapy предоставляет механизм DOWNLOAD_DELAY в настройках проекта.

# settings.py
DOWNLOAD_DELAY = 0.5  # Delay of 0.5 seconds between requests

Также можно использовать прокси-серверы и менять User-Agent.

Обработка ошибок и повторные попытки

Необходимо обрабатывать возможные ошибки при запросах (например, таймауты или ошибки сервера) и реализовывать механизм повторных попыток. Scrapy автоматически выполняет повторные попытки для некоторых ошибок, но можно настроить это поведение более детально.

Сохранение данных в формате JSON/CSV

Scrapy позволяет легко сохранять извлеченные данные в различных форматах, таких как JSON или CSV. Это можно сделать с помощью Feed Exporters.

scrapy crawl myspider -o output.json -t json
scrapy crawl myspider -o output.csv -t csv

Заключение: дальнейшие шаги и ресурсы

В этой статье мы рассмотрели основные способы обработки бесконечной прокрутки с помощью Scrapy. Помните, что каждый сайт уникален, и может потребоваться адаптация описанных методов. Для дальнейшего изучения рекомендую обратиться к документации Scrapy и Selenium, а также к примерам кода и статьям в интернете.

Успешного парсинга!


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