В предыдущем разделе мы реализовали процесс стыковки 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
)
Здесь построенаSplashRequest
Object, первые два параметра по-прежнему являются запрошенным 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-вызовы, да и развертывание масштабного краулинга тоже удобнее.