splash 返回空 html 最常见原因是未等 js 执行完就返回,应使用 wait_for='css-selector' 或 lua 脚本控制交互与等待,而非仅依赖硬等待;需正确配置中间件、去重器及并发参数。

Splash 不是万能的“JS 执行器”,它本质是 WebKit 内核的无头浏览器服务,和 Chrome DevTools 协议无关。能否成功渲染,取决于目标页面是否真依赖 JS 生成 DOM、以及你是否正确控制了等待时机和资源加载行为。
为什么 SplashRequest 返回的 HTML 还是空的?
最常见原因是没等 JS 执行完就返回了——Splash 默认只等 DOMContentLoaded,不等异步数据或滚动触发的懒加载。
-
args={'wait': 2}是硬等待,但页面 JS 执行时间波动大,2 秒可能不够,也可能浪费资源 - 更可靠的是用
args={'wait_for': 'css-selector'},比如wait_for='#product-list li',等关键元素出现再返回 - 如果目标元素由滚动触发(如无限下拉),必须配合
script参数执行滚动操作,纯wait无效 -
images_enabled=False可加快渲染,但某些页面靠图片加载后才触发 JS 回调,关掉反而失败
如何用 Lua 脚本点击按钮或模拟滚动?
Splash 的核心控制能力在 Lua 脚本里,不是靠 Python 参数堆砌。Scrapy 发送的 SplashRequest 中 script 字段传入 Lua 函数,Splash 在浏览器上下文中执行它。
调用 Cutout.Pro 视觉处理 API 进行背景移除、人像抠图和照片增强,支持文件上传与图片 URL 输入。
- 脚本必须返回字典,例如
{html=splash:html(), png=splash:png()},否则response拿不到内容 - 点击按钮:用
splash:runjs("document.querySelector('button.load-more').click()"),之后要splash:wait(1)等新 DOM 渲染 - 滚动到底部:
splash:evaljs("window.scrollTo(0, document.body.scrollHeight)"),再splash:wait(1.5) - 避免超时:加上
timeout=30到args,否则默认 15 秒超时后返回空响应
scrapy-splash 的中间件配置容易漏哪几项?
只加 SplashMiddleware 不够,Cookie 和去重逻辑必须同步适配,否则登录态丢失、重复请求爆炸。
-
'scrapy_splash.SplashCookiesMiddleware': 723必须启用,否则Splash渲染时的 Cookie 不会回传给后续请求 -
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'必须设置,否则带不同wait或script的相同 URL 会被当成重复请求丢弃 -
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'如果开了缓存,这个也要改,不然缓存键没包含 Splash 参数 -
SPLASH_URL必须是可连通地址,Docker 容器内访问宿主机用host.docker.internal,不是localhost
渲染性能差、并发上不去,问题通常出在哪?
Splash 是单进程服务,默认只处理一个渲染任务。并发高时排队严重,不是 Scrapy 的锅。
- Docker 启动时加
-e SPLASH_ARGS="-s 4"可开 4 个渲染进程(需足够内存) - 避免在脚本里用
splash:go()多次跳转,每次跳转都算一次完整渲染,开销大 - 静态资源(CSS/JS)加载慢拖慢整体,用
resources_timeout=10主动放弃卡死的资源 - 不要对每个请求都开
png或har,它们额外消耗 CPU 和磁盘 IO,仅调试时启用
Splash “等到什么才算完成”。它不会猜你想要哪个元素,也不会自动滚动或点按钮——所有交互都得你用 Lua 明确写出来。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










