使用 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:使用 Splash 设置 Scrapy

要开始使用带有 Scrapy 的 Splash,请遵循以下初始设置步骤。

1.安装 Scrapy-Splash 打开终端,安装 scrapy-splash 软件包:

pip install scrapy-splash

2.在 Docker 中运行 Splash 由于 Splash 需要 Docker 才能有效运行,因此请确保 Docker 已在您的计算机上安装并运行。使用以下命令提取 Splash Docker 映像:

docker pull scrapinghub/splash

然后启动 Splash 服务器:

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

现在,Splash 可在 http://localhost:8050 上为您的 Scrapy spider 渲染 JavaScript。

步骤 2:编写用于滚动的 Lua 脚本

通过 Splash 的 Lua 脚本功能,您可以操作浏览器、向下滚动并等待加载新内容。下面的 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

In this script:

  • splash:go(args.url) 加载目标 URL。
  • splash:wait(args.wait) 暂停,以便加载初始页面元素。
  • for 循环会多次滚动页面,每次滚动后都会短暂等待(args.scroll_delay),以便加载新内容。

步骤 3:在 Scrapy Spider 中集成 Lua 脚本

Lua 脚本准备就绪后,下一步就是设置 Scrapy 蜘蛛来执行它。该蜘蛛会向目标网站发送一个 Splash 请求,并将 Lua 脚本传入。

蜘蛛代码

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()
}

说明:

  • 蜘蛛会发送一个 SplashRequest,其中的 lua_source 指向 Lua 脚本。
  • wait、scroll_delay 和 max_scrolls 等参数定义了脚本的滚动行为。
  • 解析函数从每次滚动迭代中提取项目数据(名称和价格)。

步骤 4:处理分页和 "加载更多 "按钮

许多无限滚动页面都会使用一个隐藏的 "加载更多 "按钮,当用户滚动到底部时该按钮就会被激活。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)
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

在这里,load_more 变量使用其选择器定位 "加载更多 "按钮。如果找到了,它就会模拟点击,等待加载内容,并重复滚动。

步骤 5:绕过反僵尸保护程序

无限滚动页面通常有反机器人措施,包括验证码、速率限制和 IP 禁止。绕过这些措施的技巧包括

  1. 代理轮换: 更改 IP 地址可防止被检测到。ZenRows 和 ScraperAPI 等服务只需最少的设置即可提供 IP 轮换功能。
  2. 用户代理轮换: 在每次请求时随机化 User-Agent 字符串,以避免被检测到。
  3. 无头浏览器 Splash 以无头模式运行,使您的请求看起来更像真实的用户流量。

以下是使用 ZenRows 实现旋转代理的方法:

import scrapy
class InfiniteScrollSpider(scrapy.Spider):
name = 'proxy_spider'
allowed_domains = ['example.com]
def start_requests(self):
proxy = 'http://@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()
}

结论

我发现 Scrapy 与 Splash 的结合非常有吸引力。这是一个很棒的设置,即使是最棘手的动态网站也能轻松应对。有了 Splash,我可以处理 JavaScript 渲染,而 Scrapy 则擅长数据提取部分。Splash 的 Lua 脚本可以与页面上的元素进行交互,加载额外的内容,就像用户滚动浏览一样。

类似文章