Loading...

文章背景图

Splash:Scrapinghub 开源的 JavaScript 渲染服务|Docker 部署与 HTTP API 全指南

2026-11-06
0
- 字
- 分钟
|

Splash:Scrapinghub 开源的 JavaScript 渲染服务|Docker 部署与 HTTP API 全指南

Splash 是一个带 HTTP API 的轻量级浏览器渲染服务,用 Python 3 + Twisted + Qt5 实现,无状态、易分布式部署。本文按官方 README 与文档站,梳理 Docker 一键启动、默认端口 8050、render.html / render.png / execute 端点、Lua 脚本接口与 Scrapy 集成。

1. 项目简介与定位

Splash 是一个 JavaScript 渲染服务,对外暴露 HTTP API。它本质上是一个带 HTTP 接口的轻量级浏览器,用 Python 3 实现,基于 Twisted 与 Qt5(QtWebKit)。它的特点是快、轻量、无状态——这让它非常容易在多台机器上水平分发。

Splash 适合:你不想在每个抓取脚本里都内嵌一个完整浏览器,而是想把"渲染 JS、等页面加载、截图、抓 HAR"这一类需求集中到一个自托管的 HTTP 服务上,让上游的 Scrapy / requests / Go 程序通过 URL 参数调用它。

1.1 核心信息一览

项 内容
项目名 Splash
仓库 https://github.com/scrapinghub/splash
文档站 https://splash.readthedocs.io/
出品方 Scrapinghub(现 Zyte)
主语言 Python 3 / Twisted / Qt5(QtWebKit)
部署形态 Docker 镜像 scrapinghub/splash
默认端口 8050(HTTP)
许可证 BSD 3-Clause
脚本接口 Lua(在页面上下文里执行自定义逻辑)

1.2 适用场景

  • 给 Scrapy 爬虫提供 JS 渲染能力(配合 scrapy-splash)
  • 输入一个 URL,直接拿到渲染后的 HTML / PNG / JPEG / HAR
  • 用 Lua 脚本编排:等某个元素出现、滚动页面、点按钮、抽数据
  • 作为内网渲染服务,被多个抓取 / 监控 / 截图程序共享

1.3 能力边界(官方口径)

Splash 用的是 QtWebKit,不是完整的 Chrome / Chromium。它能跑绝大多数传统 JS 站点,但对非常新的 Web API、ES2022+、复杂 SPA 框架(重度依赖最新 V8)可能渲染不全。需要完整 Chrome 行为时,请改用 Playwright / Puppeteer 自托管服务。Splash 官方 README 也提示:商业支持由 Scrapinghub 提供。

2. 开源协议

Splash 采用 BSD 3-Clause License。详见 https://github.com/scrapinghub/splash/blob/master/LICENSE 。

3. 官方仓库链接

4. 前置要求

依赖 版本要求 说明
Docker 17 或更新 官方文档明确要求
操作系统 Linux / macOS(Docker Desktop) Windows 走 Docker Desktop
端口 8050(默认) 宿主机需可访问;生产建议只对内网开放
内存 建议 1 GB+ 每个并发渲染页面都会占用 QtWebKit 渲染进程
网络 可访问目标站点 Splash 服务器需能直连被抓取 URL

不要把 Splash 直接暴露到公网——它没有身份认证,任何人都能用它渲染任意 URL,会被当作开放代理滥用。生产环境务必放在内网,或在前面加反向代理 + Basic Auth / IP 白名单。

5. 安装部署(Docker 一键启动)

下面的命令来自官方安装文档(https://splash.readthedocs.io/en/stable/install.html )。

5.1 拉取镜像

docker pull scrapinghub/splash

5.2 启动容器

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

启动后 Splash 监听 0.0.0.0:8050(HTTP)。本机访问 http://localhost:8050/ 会看到一个 Web 调试界面,可以在里面直接输入 URL 测试渲染。

5.3 后台常驻 + 资源限制

docker run -d --name splash \
  -p 127.0.0.1:8050:8050 \
  --restart=unless-stopped \
  --memory=2g --cpus=2 \
  scrapinghub/splash \
  --max-timeout=60 --disable-lua-sandbox

常用启动参数(来自官方文档 "Passing Custom Options"):

参数 作用
-p 8050:8050 映射 HTTP 端口
--max-timeout=N 单页最大渲染秒数(默认 30,可调大到 60)
--disable-lua-sandbox 关闭 Lua 沙箱,允许更全的系统能力
--proxy PROXY_URL 全局出站代理
-v /path/to/profiles:/etc/splash/proxy-profiles 挂载代理配置目录
-v /path/to/filters:/etc/splash/request-filter-profiles 挂载请求过滤器

5.4 自建镜像(可选)

git clone https://github.com/scrapinghub/splash.git
cd splash
docker build -t my-local-splash .
# 带 Jupyter 的实验镜像
docker build -t my-local-splash-jupyter -f dockerfiles/splash-jupyter/Dockerfile .

6. 最小示例:HTTP API 调用

Splash 的核心端点如下(来自官方 HTTP API 文档目录):

端点 返回 用途
GET /render.html HTML 文本 渲染后页面的源代码
GET /render.png PNG 图片 整页截图
GET /render.jpeg JPEG 图片 整页截图(更小体积)
GET /render.har HAR JSON 网络请求日志
GET /render.json JSON 同时返回 HTML / 截图 / HAR / 自定义 JS 结果
POST /execute JSON 运行自定义 Lua 脚本
GET /run 视 Lua 返回值 运行 Lua 脚本(GET 形式)
GET /_ping ok + 内存 健康检查
GET /_debug JSON 当前请求、队列、对象统计
POST /_gc — 手动触发垃圾回收

6.1 渲染并取 HTML

curl 'http://localhost:8050/render.html?url=https://example.com&wait=2'
  • url:目标 URL(必填)
  • wait:渲染后额外等待多少秒,让 setTimeout / setInterval 回调有机会执行。官方文档提示:如果页面里有定时器,wait=0 时这些回调不会跑;做 PNG / JPEG 全页截图时也需要非零 wait。
  • proxy:代理 profile 名或 [user:pass@]host:port 形式的代理 URL。

6.2 截图

# 整页 PNG
curl 'http://localhost:8050/render.png?url=https://example.com&wait=2&width=1280&height=800' -o shot.png

# JPEG
curl 'http://localhost:8050/render.jpeg?url=https://example.com&wait=2&quality=80' -o shot.jpg

6.3 一次拿多种结果(render.json)

curl 'http://localhost:8050/render.json?url=https://example.com&wait=2&html=1&png=1&har=1'

6.4 健康检查

curl http://localhost:8050/_ping
# {"status": "ok", "maxrss": ...}

7. Lua 脚本接口(execute)

/execute 是 Splash 最强大的端点:你写一段 Lua,Splash 在页面上下文里按你的编排执行。下面这段官方常见模式:打开页面、等某个选择器出现、读文本、返回 JSON。

function main(splash, args)
  splash:set_user_agent('Mozilla/5.0 (compatible; MyBot/1.0)')
  splash:autoclose_onerror(false)
  assert(splash:go(args.url))
  splash:wait(2.0)

  -- 滚动到底部触发懒加载
  splash:evaljs("window.scrollTo(0, document.body.scrollHeight)")
  splash:wait(1.0)

  local title = splash:evaljs("document.title")
  local items = splash:evaljs([[
    Array.from(document.querySelectorAll('a.item')).map(a => a.href)
  ]])

  return {
    title = title,
    links = items,
    html = splash:html(),
    png = splash:png{width=1280, height=800},
  }
end

调用方式(POST,lua_source 字段传脚本):

curl 'http://localhost:8050/execute' \
  -F 'url=https://example.com' \
  -F 'lua_source=@myscript.lua'

Lua API 完整参考见 https://splash.readthedocs.io/en/stable/scripting-ref.html 。常用对象:splash(浏览器)、args(URL 参数)、request / response、element、cookies_enabled、resource_timeout、images_enabled 等。

8. 配置项

配置 作用 默认
默认监听端口 HTTP 服务端口 8050
--max-timeout 单请求最大秒数 30
--timeout 默认超时 由 --max-timeout 约束
--wait(请求参数) 渲染后额外等待秒 0
--proxy(启动参数) 全局出站代理 无
proxy(请求参数) 单请求代理 profile 或 URL 无
resource_timeout(Lua) 单个资源加载超时 无
images_enabled(Lua) 是否加载图片(关掉可加速) 开
http_method(请求参数) 出站 GET 或 POST GET
save_args 把长参数缓存起来,后续请求用 SHA1 引用 无
/etc/splash/proxy-profiles/ 代理 profile 配置目录 容器内默认存在
/etc/splash/request-filter-profiles/ 请求过滤器目录 容器内默认存在

9. 与 Scrapy 集成

官方 README 直接指向 scrapy-splash。在 Scrapy `settings.py` 里:

SPLASH_URL = 'http://localhost:8050'
DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'

在 spider 里用 SplashRequest 代替 scrapy.Request:

from scrapy_splash import SplashRequest

class MySpider(scrapy.Spider):
    def start_requests(self):
        yield SplashRequest(
            url='https://example.com',
            callback=self.parse,
            args={'wait': 2, 'html': 1},
        )

10. 常见问题

Q1:启动后访问 8050 打不开? A:确认 docker ps 里容器在跑、端口映射是 0.0.0.0:8050->8050/tcp;云服务器安全组 / 防火墙要放行 8050(或建议只绑 127.0.0.1,再用 Nginx 加 Basic Auth)。

Q2:渲染出来的 HTML 里没有我要的内容? A:加大 wait=,或在 Lua 里 splash:wait_for_element('#foo');也可能是站点用了 QtWebKit 不支持的新 Web API,这种情况请改用 Playwright / Chromium 类服务。

Q3:内存越用越大? A:Splash 文档提供 POST /_gc 手动回收;长期跑建议配 --max-timeout 限制单页渲染时间、挂 --memory 限制容器内存,必要时定时重启容器。

Q4:怎么加代理? A:启动时 --proxy http://host:port 全局加;或在 /etc/splash/proxy-profiles/ 下放 *.ini 定义命名 profile,请求时 ?proxy=myprofile。

Q5:能不能关掉图片加载加速? A:Lua 脚本里 splash.images_enabled = false,整页就不会加载图片,渲染速度明显提升。

Q6:Splash 与 Playwright / Puppeteer 自托管怎么选? A:Splash 轻、无状态、HTTP + Lua 接口简单,适合传统站点和 Scrapy 流水线;Playwright / Puppeteer 基于完整 Chromium,能跑现代 SPA,但资源占用大、需要自己写服务封装。

11. 与同类工具对比

维度 Splash Playwright 自托管 Puppeteer + Express Selenium Grid
浏览器内核 QtWebKit 完整 Chromium / Firefox / WebKit Chromium 各浏览器 driver
接口 HTTP + Lua 语言 SDK(需自己包 HTTP) 自己写 HTTP W3C WebDriver 协议
资源占用 小 大 中 中
无状态 / 易横向扩 是 需自己做 需自己做 是(Grid)
现代 SPA 支持 弱 强 强 强
默认端口 8050 自定义 自定义 4444

12. 许可

BSD 3-Clause。详见 https://github.com/scrapinghub/splash/blob/master/LICENSE 。商业支持由 Scrapinghub(Zyte)提供。

13. 责任使用声明

使用 Splash 渲染或抓取任何站点时,请遵守目标站点的 robots.txt 与服务条款(ToS)。请合理控制并发数与请求频率,在请求之间加入延时,避免对目标服务器造成压力。请勿用 Splash 绕过登录验证、付费墙、验证码或反爬系统。请勿批量抓取、存储或传播个人隐私数据。本工具仅应用于公开数据的合法研究、自身业务的页面渲染与截图、授权范围内的自动化任务。请尊重网页内容的版权,二次发布抓取结果需获得权利人许可。

评论交流

文章目录