使用 Scrapy 和 Splash 抓取无限滚动内容

使用 Scrapy 和 Splash 抓取无限滚动内容

在这里,我将带你了解如何将 ScrapySplash 配置起来,应对无限滚动,获取动态内容,并处理常见的抓取挑战。让我们一步步深入看看具体怎么做。

为什么要抓取无限滚动内容?

无限滚动常见于电商网站、社交媒体平台和新闻聚合网站,当用户向下滚动时会加载更多内容。基础的 HTML 解析器不足以抓取这类网站,因为新内容只有在滚动操作之后才会出现。像 Splash 这样的无头浏览器就能派上用场,它可以帮助模拟滚动并加载动态内容,从而实现有效抓取。

Scrapy 和 Splash 基础

Scrapy 是一个用 Python 编写的开源网页抓取框架,以速度快、简单易用和可扩展性强而闻名。它提供了一种结构化方式来组织代码并从网站中提取信息。

Splash 是专门为网页抓取而构建的无头浏览器。它可以执行 JavaScript 并渲染 HTML 页面。当它以 Scrapy-Splash 的形式与 Scrapy 集成时,我们就可以抓取依赖 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. 安装 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 爬虫渲染 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

在这个脚本中:

  • splash:go(args.url) 会加载目标 URL。

  • splash:wait(args.wait) 会暂停,以便初始页面元素加载完成。

  • for 循环会多次滚动页面,并在每次滚动后短暂等待(args.scroll_delay),让新内容加载出来。

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

准备好 Lua 脚本后,下一步是设置一个 Scrapy spider 来执行它。这个 spider 会向目标站点发送 Splash 请求,并传入 Lua 脚本。

Spider 代码

复制代码
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()

}

说明

  • 该 spider 会发送一个 SplashRequest,其中 lua_source 指向 Lua 脚本。

  • wait、scroll_delay 和 max_scrolls 等参数定义了脚本的滚动行为。

  • parse 函数会从每次滚动迭代中提取商品数据(名称和价格)。

步骤 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:绕过反机器人防护

无限滚动页面通常会有反机器人措施,包括 CAPTCHA、速率限制和 IP 封禁。绕过这些措施的技术包括:

  1. 代理轮换:更换 IP 地址可以防止被检测到。ZenRows 和 ScraperAPI 等服务提供 IP 轮换,并且设置成本很低。

  2. User-Agent 轮换:通过在每次请求中随机化你的 User-Agent 字符串来避免被检测。

  3. 无头浏览器:Splash 以无头模式运行,使你的请求看起来更像真实用户流量。

下面是如何使用 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 spider 的完整代码,包含 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 脚本让你可以与页面上的元素交互,像用户滚动浏览一样加载更多内容。

有任何问题吗?请在评论里告诉我!

对其他网页抓取指南感兴趣

想看更多精彩文章,请访问我的主页 --- Data Journal ❤️

相关推荐
Minner-Scrapy18 小时前
Scrapy 2.17 源码解析:Scheduler 调度器与磁盘/内存双队列
java·爬虫·python·scrapy·网络爬虫·twisted
tang777891 天前
Scrapy框架动态IP自动轮换集成配置教程
爬虫·tcp/ip·scrapy·架构·爬虫代理·动态ip
鬼手点金8 天前
Scrapy 网络爬虫框架
爬虫·python·scrapy·ajax·html·json·requsts
鬼手点金8 天前
Scrapy + Playwright 完整示例(JS 动态渲染网页)
开发语言·javascript·爬虫·python·scrapy·html·json
Data_Journal13 天前
如何使用 Java 和 Jsoup 解析 HTML
大数据·开发语言·数据库·python·scrapy
张小凡vip17 天前
python--爬虫--成熟的爬虫框架Scrapy
爬虫·python·scrapy
kisloy19 天前
【爬虫入门第13讲】Scrapy 框架深度解析(四)核心配置与自定义扩展
网络·爬虫·scrapy
kisloy23 天前
【爬虫入门第10讲】Scrapy 框架深度解析(一):五大组件与中间件
爬虫·scrapy·中间件
q567315231 个月前
Scrapy 框架集成稳定 HTTP 代理:中间件配置与断线重试实战
爬虫·网络协议·scrapy·http·中间件·http代理