Стыковка Splash со Scrapy с использованием фреймворка Scrapy

задняя часть рептилия Scrapy Lua

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

1. Подготовка

Убедитесь, что Splash установлен и работает правильно, а также установлена ​​библиотека Scrapy-Splash.

2. Новые проекты

Сначала создайте новый проект с именем scrapysplashtest, команда выглядит следующим образом:

scrapy startproject scrapysplashtest

Создайте нового Паука, команда выглядит следующим образом:

scrapy genspider taobao www.taobao.com

3. Добавьте конфигурацию

Вы можете обратиться к инструкциям по настройке Scrapy-Splash для пошаговой настройки, ссылка выглядит следующим образом: https://github.com/scrapy-plugins/scrapy-splash#configuration.

Изменить settings.py, настроитьSPLASH_URL. Здесь наш Splash работает локально, поэтому локальный адрес можно настроить напрямую:

SPLASH_URL = 'http://localhost:8050'

Если Splash работает на удаленном сервере, его следует настроить как удаленный адрес. Например, работая на сервере с IP 120.27.34.25, он должен быть настроен как:

SPLASH_URL = 'http://120.27.34.25:8050'

Также нужно настроить несколько Middleware, код такой:

DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}

Здесь настраиваются три промежуточных ПО Downloader и одно промежуточное ПО Spider, которые являются основной частью Scrapy-Splash. Нам больше не нужно внедрять промежуточное программное обеспечение Downloader, такое как стыковка Selenium, библиотека Scrapy-Splash готова для нас, и мы можем настроить ее напрямую.

Вам также необходимо настроить класс дедупликацииDUPEFILTER_CLASS, код выглядит так:

DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'

Наконец, настройте хранилище кэшаHTTPCACHE_STORAGE, код выглядит так:

HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

В-четвертых, новый запрос

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

Давайте рассмотрим пример следующим образом:

yield SplashRequest(url, self.parse_result,
    args={
        # optional; parameters passed to Splash HTTP API
        'wait': 0.5,
        # 'url' is prefilled from request url
        # 'http_method' is set to 'POST' for POST requests
        # 'body' is set to request body for POST requests
    },
    endpoint='render.json', # optional; default is render.html
    splash_url='<url>',     # optional; overrides SPLASH_URL
)

Здесь построенаSplashRequestObject, первые два параметра по-прежнему являются запрошенным URL-адресом и функцией обратного вызова. Кроме того, мы также можемargsПередайте некоторые параметры рендеринга, такие как время ожиданияwaitд., а также согласноendpointПараметр указывает интерфейс рендеринга. Дополнительные параметры см. в документации: https://github.com/scrapy-plugins/scrapy-splash#requests.

Кроме того, мы также можем сгенерировать объект Request, и конфигурация Splash передается черезmetaСвойства можно настроить, код такой:

yield scrapy.Request(url, self.parse_result, meta={
    'splash': {
        'args': {
            # set rendering arguments here
            'html': 1,
            'png': 1,
            # 'url' is prefilled from request url
            # 'http_method' is set to 'POST' for POST requests
            # 'body' is set to request body for POST requests
        },
        # optional parameters
        'endpoint': 'render.json',  # optional; default is render.json
        'splash_url': '<url>',      # optional; overrides SPLASH_URL
        'slot_policy': scrapy_splash.SlotPolicy.PER_DOMAIN,
        'splash_headers': {},       # optional; a dict with headers sent to Splash
        'dont_process_response': True, # optional, default is False
        'dont_send_headers': True,  # optional, default is False
        'magic_response': False,    # optional, default is True
    }
})

SplashRequestобъект черезargsнастраивать и запрашивать объекты черезmetaПри настройке эффект, достигаемый двумя методами, одинаков.

В этом разделе нам нужно сканировать информацию о продуктах Taobao, что включает в себя такие операции, как ожидание загрузки страницы и имитация щелчка для перелистывания страниц. Сначала мы можем определить сценарий Lua для реализации функций загрузки страницы и имитации щелчка для перелистывания страниц.Код выглядит следующим образом:

function main(splash, args)
  args = {
    url="https://s.taobao.com/search?q=iPad",
    wait=5,
    page=5
  }
  splash.images_enabled = false
  assert(splash:go(args.url))
  assert(splash:wait(args.wait))
  js = string.format("document.querySelector('#mainsrp-pager div.form > input').value=%d;document.querySelector('#mainsrp-pager div.form > span.btn.J_Submit').click()", args.page)
  splash:evaljs(js)
  assert(splash:wait(args.wait))
  return splash:png()
end

Определяем три параметра: запрашиваемая ссылкаurl,время ожиданияwait, номер страницы пагинацииpage. Затем отключите загрузку изображений, запросите страницу со списком продуктов Taobao, перейдитеevaljs()Метод вызывает код JavaScript для реализации заполнения номера страницы и кликов по перелистыванию страниц и, наконец, возвращает к скриншоту страницы. Мы помещаем скрипт в Splash для запуска и обычно получаем скриншот страницы, как показано на следующем рисунке.

Операция перелистывания страниц также успешно реализована, как показано на следующем рисунке, номер текущей страницы и номер страницы, который мы передали вpageПараметры те же.

Нам просто нужно использовать в SpiderSplashRequestПросто пристыкуйте сценарий Lua, как показано ниже:

from scrapy import Spider
from urllib.parse import quote
from scrapysplashtest.items import ProductItem
from scrapy_splash import SplashRequest

script = """
function main(splash, args)
  splash.images_enabled = false
  assert(splash:go(args.url))
  assert(splash:wait(args.wait))
  js = string.format("document.querySelector('#mainsrp-pager div.form > input').value=%d;document.querySelector('#mainsrp-pager div.form > span.btn.J_Submit').click()", args.page)
  splash:evaljs(js)
  assert(splash:wait(args.wait))
  return splash:html()
end
"""

class TaobaoSpider(Spider):
    name = 'taobao'
    allowed_domains = ['www.taobao.com']
    base_url = 'https://s.taobao.com/search?q='

    def start_requests(self):
        for keyword in self.settings.get('KEYWORDS'):
            for page in range(1, self.settings.get('MAX_PAGE') + 1):
                url = self.base_url + quote(keyword)
                yield SplashRequest(url, callback=self.parse, endpoint='execute', args={'lua_source': script, 'page': page, 'wait': 7})

Мы определяем скрипт Lua как длинную строку,SplashRequestизargsДля передачи параметров интерфейс изменен наexecute. Кроме того,argsЕсть еще один параметрlua_sourceПоля используются для указания содержимого скрипта Lua. Таким образом, мы успешно построилиSplashRequest, работа по стыковке Splash завершена.

Другие конфигурации изменять не нужно.Такие настройки, как Item и Item Pipeline, аналогичны способу подключения к Selenium в предыдущем разделе.parse()Функция обратного вызова точно такая же.

5. Операция

Затем мы запускаем сканер с помощью следующей команды:

scrapy crawl taobao

Результат работы показан на рисунке ниже.

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

Наконец, мы смотрим на результаты MongoDB, как показано на следующем рисунке.

Результаты также обычно сохраняются в MongoDB.

6. Код в этом разделе

Кодовый адрес этого раздела: https://github.com/Python3WebSpider/ScrapySplashTest.

7. Заключение

Поэтому в Scrapy рекомендуется использовать Splash для обработки динамически отображаемых страниц JavaScript. Это не разрушит процесс асинхронной обработки в Scrapy и значительно повысит эффективность сканирования. При этом установка и настройка Splash относительно проста, а разделение модулей реализовано через API-вызовы, да и развертывание масштабного краулинга тоже удобнее.