news 2026/5/11 2:04:57

Scrapy与Splash结合爬取JavaScript渲染页面

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Scrapy与Splash结合爬取JavaScript渲染页面

在网络爬虫的开发过程中,我们经常会遇到一类 “棘手” 的目标网站 —— 基于 JavaScript 动态渲染的页面。这类网站不会在初始 HTML 中直接返回完整数据,而是通过前端脚本异步加载、渲染内容。传统的 Scrapy 爬虫直接解析响应文本,往往只能拿到空壳结构,无法获取有效信息。此时,将ScrapySplash结合,就成为了攻克这类网站的高效方案。

一、核心原理:为什么需要 Splash?

Scrapy 是 Python 生态中功能强大的爬虫框架,它以高效的异步请求、灵活的数据处理流程著称,但它的短板在于无法执行 JavaScript 代码。当爬虫向目标网站发送请求时,得到的响应是未经渲染的原始 HTML,其中动态加载的列表、数据、按钮等元素都尚未生成。

Splash 则是一个专门用于渲染 JavaScript 页面的轻量级工具,它本质是一个带有 HTTP API 的无界面浏览器,基于 Qt5 和 WebKit 内核。Splash 可以模拟真实浏览器的行为:加载页面、执行 JS 脚本、等待 DOM 渲染完成,然后返回渲染后的完整 HTML 页面,甚至可以截取页面截图、获取页面加载的 HAR 数据。

Scrapy 与 Splash 的结合逻辑非常清晰:

  1. Scrapy 不再直接向目标网站发送请求,而是将请求参数发送给 Splash 服务;
  2. Splash 接收请求后,模拟浏览器加载目标页面,完成 JS 渲染;
  3. Splash 将渲染后的 HTML 页面返回给 Scrapy;
  4. Scrapy 对渲染后的 HTML 进行解析,提取目标数据。

二、环境准备:安装与配置

在开始编写爬虫之前,我们需要完成基础环境的搭建,主要分为Splash 服务部署Python 依赖安装两步。

2.1 部署 Splash 服务

Splash 支持多种部署方式,最推荐的是Docker 容器部署,这种方式无需处理复杂的依赖关系,一键即可启动服务。

  1. 确保本地已安装 Docker 环境,执行以下命令拉取 Splash 镜像:

    bash

    运行

    docker pull scrapinghub/splash
  2. 启动 Splash 容器,映射端口(默认端口为 8050):

    bash

    运行

    docker run -p 8050:8050 scrapinghub/splash
  3. 验证服务是否启动成功:打开浏览器访问http://localhost:8050,若能看到 Splash 的测试页面,则说明部署成功。

2.2 安装 Python 依赖库

需要安装scrapy-splash库,它是 Scrapy 与 Splash 通信的桥梁,提供了专门的下载器中间件和请求类。

bash

运行

pip install scrapy-splash

三、Scrapy 项目配置:接入 Splash

创建一个新的 Scrapy 项目后,我们需要修改settings.py配置文件,让 Scrapy 能够使用 Splash 服务。

3.1 核心配置项

打开项目根目录下的settings.py,添加或修改以下配置:

python

运行

# 1. 配置Splash服务的地址 SPLASH_URL = 'http://localhost:8050' # 2. 启用Splash相关的下载器中间件 DOWNLOADER_MIDDLEWARES = { 'scrapy_splash.SplashCookiesMiddleware': 723, 'scrapy_splash.SplashMiddleware': 725, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810, } # 3. 配置Splash的去重过滤器 DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter' # 4. 配置缓存存储(可选,用于缓存Splash的响应) HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

这些配置的核心作用是让 Scrapy 的请求走 Splash 通道,并处理 Splash 响应的去重和缓存问题。

四、编写爬虫:实战爬取 JS 渲染页面

接下来,我们以一个简单的 JS 渲染页面为例,编写完整的爬虫代码。假设目标网站的动态数据是通过 Ajax 加载的商品列表,我们需要提取商品名称和价格。

4.1 创建爬虫文件

在项目的spiders目录下创建js_spider.py,代码如下:

python

运行

import scrapy from scrapy_splash import SplashRequest class JsRenderSpider(scrapy.Spider): name = 'js_render_spider' allowed_domains = ['example.com'] # 替换为目标域名 start_urls = ['https://example.com/js-render-page'] # 替换为目标URL # 定义Splash的Lua脚本:用于控制页面渲染过程 lua_script = """ function main(splash, args) -- 设置页面加载超时时间 splash:set_timeout(10) -- 加载目标页面 assert(splash:go(args.url)) -- 等待页面渲染完成(等待5秒,或等待指定元素出现) assert(splash:wait(5)) -- 返回渲染后的页面HTML return { html = splash:html(), -- 可选:返回页面截图 -- png = splash:png(), } end """ def start_requests(self): for url in self.start_urls: # 使用SplashRequest替代scrapy.Request yield SplashRequest( url=url, callback=self.parse, endpoint='execute', # 指定Splash的执行端点 args={ 'lua_source': self.lua_script, # 传入Lua脚本 'wait': 2 # 额外的等待参数 } ) def parse(self, response): # 解析渲染后的HTML(与普通Scrapy解析方式一致) products = response.xpath('//div[@class="product-item"]') for product in products: yield { 'name': product.xpath('.//h3/text()').get().strip(), 'price': product.xpath('.//span[@class="price"]/text()').get().strip() }

4.2 代码核心解析

  1. SplashRequest 替代 Request:这是与普通爬虫的核心区别,SplashRequest会将请求发送到 Splash 服务,并携带 Lua 脚本控制渲染流程。
  2. Lua 脚本的作用:Lua 脚本是 Splash 的灵魂,它可以实现复杂的页面操作:
    • splash:go(args.url):加载目标 URL;
    • splash:wait(5):等待 5 秒,确保 JS 脚本执行完毕、数据加载完成;
    • splash:html():获取渲染后的 HTML 源码;
    • 除此之外,还可以实现click(点击元素)、fill(填写表单)、scroll_position(滚动页面)等操作。
  3. 解析响应:经过 Splash 渲染后的响应,与普通 HTML 响应的解析方式完全一致,我们可以使用 XPath 或 CSS 选择器轻松提取数据。

五、高级技巧:优化渲染与爬取效率

在实际爬取过程中,我们需要根据目标网站的特性优化爬虫,避免出现超时、漏数据等问题。

5.1 智能等待:替代固定等待时间

固定的splash:wait(5)不够灵活,页面加载快时会浪费时间,加载慢时会导致渲染不完整。我们可以通过等待指定元素出现来优化:

lua

-- 等待class为"product-list"的元素出现,超时时间10秒 assert(splash:wait_for_element('div.product-list', 10))

5.2 处理动态加载的分页

对于无限滚动的分页页面,可以通过 Lua 脚本模拟滚动操作,触发更多数据加载:

lua

function main(splash, args) splash:go(args.url) splash:wait(2) -- 模拟向下滚动3次,每次滚动后等待2秒 for i=1,3 do splash:evaljs("window.scrollTo(0, document.body.scrollHeight)") splash:wait(2) end return splash:html() end

5.3 禁用图片加载:提升爬取速度

如果不需要页面截图,禁用图片、CSS 等资源的加载,可以大幅提升 Splash 的渲染速度:

lua

function main(splash, args) splash.images_enabled = false -- 禁用图片加载 splash:go(args.url) splash:wait(3) return splash:html() end

六、常见问题与解决方案

  1. Splash 服务连接失败

    • 检查 Docker 容器是否正常运行:docker ps
    • 确认SPLASH_URL配置正确,防火墙未拦截 8050 端口。
  2. 渲染后的页面仍无目标数据

    • 延长等待时间或使用wait_for_element等待关键元素;
    • 检查目标网站是否有反爬机制,可通过splash:set_user_agent()设置浏览器 UA。
  3. 爬虫效率过低

    • 禁用图片、CSS 加载;
    • 调整 Scrapy 的并发数(CONCURRENT_REQUESTS),避免 Splash 服务过载。

七、总结

Scrapy 与 Splash 的组合,完美解决了 JavaScript 渲染页面的爬取难题。Scrapy 负责请求调度、数据解析和持久化,Splash 负责模拟浏览器渲染,两者分工明确,极大拓展了爬虫的适用场景。在实际开发中,我们需要根据目标网站的特性编写灵活的 Lua 脚本,同时优化配置和爬取策略,才能在效率和稳定性之间找到最佳平衡点。

需要注意的是,爬虫开发应遵守目标网站的robots.txt协议,避免对服务器造成过大压力,做一个合规的开发者。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 14:41:48

PyTorch 2.8新特性体验:3步云端部署,1块钱起立即试用

PyTorch 2.8新特性体验:3步云端部署,1块钱起立即试用 你是不是也遇到过这种情况:想写一篇关于最新AI框架的技术评测文章,结果光是本地环境就折腾了一整天?各种CUDA版本不匹配、PyTorch依赖冲突、编译报错满屏飞……最…

作者头像 李华
网站建设 2026/5/10 20:07:42

Qwen3-VL vs LLaVA多模态对比:云端GPU 3小时省心评测

Qwen3-VL vs LLaVA多模态对比:云端GPU 3小时省心评测 你是不是也遇到过这种情况:AI实验室要选一个视觉理解模型做项目,但手头只有笔记本,跑不动动辄几十亿参数的大模型?想用云服务吧,按周租太贵&#xff0…

作者头像 李华
网站建设 2026/5/10 23:48:54

亲测有效!VibeVoice-TTS网页端实现多人对话语音合成

亲测有效!VibeVoice-TTS网页端实现多人对话语音合成 1. 背景与需求:为什么需要多角色长时语音合成? 在播客、有声书、虚拟客服和AI角色对话等应用场景中,传统文本转语音(TTS)系统长期面临三大瓶颈&#x…

作者头像 李华
网站建设 2026/5/9 19:24:15

从部署到推理:PaddleOCR-VL-WEB实现本地图片与PDF精准识别

从部署到推理:PaddleOCR-VL-WEB实现本地图片与PDF精准识别 1. 引言:为何选择PaddleOCR-VL-WEB进行文档解析 在当前AI驱动的智能文档处理场景中,高效、准确且支持多语言的OCR系统成为企业与开发者的核心需求。尽管市场上已有多种OCR解决方案…

作者头像 李华
网站建设 2026/5/6 9:52:49

Qwen3-VL无法识别图标?GUI元素检测调优实战教程

Qwen3-VL无法识别图标?GUI元素检测调优实战教程 1. 引言:GUI自动化中的视觉模型挑战 在当前智能代理与自动化任务快速发展的背景下,视觉语言模型(VLM)正逐步承担起“操作界面”的能力。Qwen3-VL-2B-Instruct 作为阿里…

作者头像 李华
网站建设 2026/5/4 8:52:38

JLink驱动安装方法:新手必看的Windows入门教程

手把手教你搞定JLink驱动安装:从踩坑到畅通无阻的Windows实战指南你有没有遇到过这样的场景?新买了一块STM32开发板,兴冲冲地连上J-Link调试器,结果设备管理器里只看到一个“未知设备”;或者Keil点了下载却提示“Canno…

作者头像 李华