Вебскрапінг контенту з нескінченною прокруткою за допомогою Scrapy та Splash

Вебскрапінг контенту з нескінченною прокруткою за допомогою Scrapy та Splash

Тут я покажу, як це налаштувати Scrapy with Splash, впоратися з нескінченною прокруткою, завантажувати динамічний контент і розв'язувати типові проблеми вебскрапінгу. Давайте зануримося в це й подивимося, як це робиться, крок за кроком.

Навіщо вебскрапити контент із нескінченною прокруткою?

Нескінченне прокручування часто трапляється на сайтах електронної комерції, у соціальних мережах і в новинних агрегаторах, де додаткові елементи підвантажуються під час прокручування вниз. Звичайного HTML-парсера недостатньо, щоб виконувати вебскрапінг такого сайту, оскільки новий контент з’являється лише після прокручування. Тут у гру вступають браузери без графічного інтерфейсу на кшталт Splash, які допомагають імітувати прокручування та завантажувати динамічний контент для ефективного вебскрапінгу.

Основи Scrapy та Splash

Scrapy Це фреймворк із відкритим кодом для вебскрапінгу на Python, відомий швидкістю, простотою та розширюваністю. Він забезпечує структурований спосіб організовувати код і вилучати інформацію з вебсайтів.

Splash Браузер без графічного інтерфейсу, спеціально створений для вебскрапінгу. Він може виконувати JavaScript і відображати HTML-сторінки. Інтегрований зі Scrapy як Scrapy-Splash, він дає змогу виконувати вебскрапінг сайтів, що покладаються на JavaScript для завантаження контенту, зокрема тих, де є нескінченне прокручування.

Обійдіть нескінченну прокрутку у вебскрапінгу — отримуйте дані

Нижче перелічено найкращі сайти з наборами даних, подивіться на них, якщо ваш проєкт надто складний і ви не хочете марнувати час:

  1. Bright Data — Налаштовувані та готові набори даних для різних галузей.
  2. Statista — Розширена статистика та звіти для бізнесу й досліджень.
  3. Datarade — Маркетплейс преміальних продуктів з даними від різних постачальників.
  4. AWS Data Exchange — Набори даних від сторонніх постачальників, інтегровані з сервісами AWS.
  5. Zyte — Вебскрапінг і індивідуальні набори даних, адаптовані до потреб бізнесу.
  6. Data & Sons — Відкритий маркетплейс для купівлі та продажу різноманітних наборів даних.
  7. Coresignal — Аналітика робочої сили з великим обсягом даних, пов’язаних із працевлаштуванням.
  8. Oxylabs — Спеціалізовані дані про компанії та послуги вебскрапінгу.
  9. Bloomberg Enterprise Data Catalog — Фінансові дані для корпоративного використання.
  10. Kaggle — Безплатні публічні набори даних і інструменти для науки про дані.

Крок 1: Налаштування Scrapy із Splash

Щоб почати використовувати Splash із Scrapy, виконайте такі початкові кроки налаштування.

1. Install Scrapy-Splash Відкрийте термінал і встановіть пакет scrapy-splash:

pip install scrapy-splash

2. Запустіть Splash у Docker Оскільки Splash для ефективної роботи потребує Docker, переконайтеся, що Docker встановлено і він запущений на вашій машині. Виконайте таку команду, щоб завантажити Docker-образ Splash:

docker pull scrapinghub/splash

Потім запустіть сервер Splash:

docker run -it -p 8050:8050 - rm scrapinghub/splash

Now, Splash will be available at http://localhost:8050, ready to render JavaScript for your Scrapy spider.

Крок 2: Написання Lua-скрипта для прокрутки

Функція Lua-скриптингу у Splash дає змогу керувати браузером, прокручувати вниз і чекати, поки завантажиться новий контент. Наведений нижче Lua-скрипт прокручує сторінку донизу, чекає на контент і повторює цей процес кілька разів.

Lua-скрипт для прокручування

function main(splash, args)
splash:go(args.url)
splash:wait(args.wait)
local scroll_to = splash:jsfunc('window.scrollTo')
local get_body_height = splash:jsfunc([[
function() {
return document.body.scrollHeight;
}
]])
local scroll_count = 0
for _ = 1, args.max_scrolls do
scroll_count = scroll_count + 1
scroll_to(0, get_body_height())
splash:wait(args.scroll_delay)
end
return {
html = splash:html(),
scroll_count = scroll_count
}
end

У цьому скрипті:

  • splash:go(args.url) loads the target URL.
  • splash:wait(args.wait) pauses to allow initial page elements to load.
  • The for loop scrolls the page multiple times, waiting briefly (args.scroll_delay) after each scroll to allow new content to load.

Крок 3: Інтеграція Lua-скрипта у Scrapy-павука

Коли Lua-скрипт готовий, наступний крок — налаштувати спайдер Scrapy для його виконання. Цей спайдер надсилає запит Splash до цільового сайту та передає Lua-скрипт.

Spider Code

import scrapy
from scrapy_splash import SplashRequest
class InfiniteScrollSpider(scrapy.Spider):
name = 'infinite_scroll_spider'
allowed_domains = ['example.com']
start_urls = ['http://example.com/target_page']
lua_script = """
function main(splash, args)
splash:go(args.url)
splash:wait(args.wait)
local scroll_to = splash:jsfunc('window.scrollTo')
local get_body_height = splash:jsfunc([[
function() {
return document.body.scrollHeight;
}
]])
local scroll_count = 0
for _ = 1, args.max_scrolls do
scroll_count = scroll_count + 1
scroll_to(0, get_body_height())
splash:wait(args.scroll_delay)
end
return {
html = splash:html(),
scroll_count = scroll_count
}
end
"""
def start_requests(self):
yield SplashRequest(
self.start_urls[0],
self.parse,
endpoint='execute',
args={
'lua_source': self.lua_script,
'wait': 2,
'scroll_delay': 1,
'max_scrolls': 8
}
)
def parse(self, response):
for item in response.css('.item-selector'):
yield {
'name': item.css('.name::text').get(),
'price': item.css('.price::text').get()
}

Explanation:

  • The spider sends a SplashRequest with lua_source pointing to the Lua script.
  • Arguments like wait, scroll_delay, and max_scrolls define the script’s scroll behavior.
  • Функція parse витягує дані елементів (назву та ціну) з кожної ітерації прокручування.

Крок 4: Обробка пагінації та кнопок «Показати ще»

Багато сторінок із нескінченною прокруткою використовують приховану кнопку «Load More», яка активується, коли користувач прокручує сторінку донизу. Lua-скрипт Splash може обробити це, натискаючи кнопку «Load More», коли вона з’являється.

Модифікований Lua-скрипт для кнопки «Показати ще»

function main(splash, args)
splash:go(args.url)
splash:wait(args.wait)
local scroll_to = splash:jsfunc('window.scrollTo')
local get_body_height = splash:jsfunc([[
function() {
return document.body.scrollHeight;
}
]])
local scroll_count = 0
for _ = 1, args.max_scrolls do
scroll_count = scroll_count + 1
scroll_to(0, get_body_height())
splash:wait(args.scroll_delay)
local load_more = splash:select('.load-more-button')
if load_more then
load_more:mouse_click()
splash:wait(1)
end
end
return splash:html()
end

Here, the load_more variable locates the “Load More” button using its selector. If found, it simulates a click, waits for content to load, and repeats scrolling.

Крок 5: Обхід антибот-захисту

Сторінки з нескінченним прокручуванням часто мають антибот-захист, зокрема CAPTCHA, обмеження частоти запитів і блокування IP-адрес. До способів обходу належать:

  1. Proxy Rotation: Зміна IP-адрес допомагає уникнути виявлення. Сервіси на кшталт ZenRows і ScraperAPI пропонують ротацію IP-адрес із мінімальним налаштуванням.
  2. User-Agent Rotation: Уникайте виявлення, випадково змінюючи рядок User-Agent для кожного запиту.
  3. Headless Browser: Splash працює в headless-режимі, завдяки чому ваші запити більше схожі на трафік реального користувача.

Ось як можна реалізувати ротаційний проксі за допомогою ZenRows:

import scrapy
class InfiniteScrollSpider(scrapy.Spider):
name = 'proxy_spider'
allowed_domains = ['example.com']
def start_requests(self):
proxy = 'http://<YOUR_ZENROWS_API_KEY>@api.zenrows.com:8001'
url = 'http://example.com/target_page'
yield scrapy.Request(
url,
callback=self.parse,
meta={'proxy': proxy}
)
def parse(self, response):
# parsing logic

Цей приклад налаштовує Scrapy на використання ZenRows як проксі для кожного запиту.

Крок 6: Зводимо все докупи

Ось повний код Scrapy-павука для нескінченної прокрутки, з інтеграцією Splash, Lua-скриптом і ротацією проксі:

import scrapy
from scrapy_splash import SplashRequest
class FullInfiniteScrollSpider(scrapy.Spider):
name = 'full_infinite_scroll'
allowed_domains = ['example.com']
start_urls = ['http://example.com/target_page']
lua_script = """
function main(splash, args)
splash:go(args.url)
splash:wait(args.wait)
local scroll_to = splash:jsfunc('window.scrollTo')
local get_body_height = splash:jsfunc([[
function() {
return document.body.scrollHeight;
}
]])
for _ = 1, args.max_scrolls do
scroll_to(0, get_body_height())
splash:wait(args.scroll_delay)
local load_more = splash:select('.load-more-button')
if load_more then
load_more:mouse_click()
splash:wait(1)
end
end
return splash:html()
end
"""
def start_requests(self):
yield SplashRequest(
self.start_urls[0],
self.parse,
endpoint='execute',
args={
'lua_source': self.lua_script,
'wait': 2,
'scroll_delay': 1,
'max_scrolls': 10
}
)
def parse(self, response):
for item in response.css('.item-selector'):
yield {
'name': item.css('.name::text').get(),
'price': item.css('.price::text').get()
}

Conclusion

Під час вебскрапінгу сторінок із нескінченним прокручуванням я вважаю поєднання Scrapy зі Splash дуже вдалим. Це чудова зв'язка, яка без зусиль дає змогу впоратися навіть із найскладнішими динамічними сайтами. За допомогою Splash я можу обробляти рендеринг JavaScript, тоді як Scrapy чудово справляється з вилученням даних. Lua-скриптинг Splash дає змогу взаємодіяти з елементами на сторінці та завантажувати додатковий вміст так, ніби я був користувачем, що прокручує сторінку.

Схожі записи