简介:适用于Windows 64位平台的Chrome无头浏览器压缩包(版本133.0.6943.53),无需图形界面即可运行,面向Web开发者、测试工程师与爬虫开发者,适用于自动化测试、页面渲染和数据抓取等场景。压缩包共125个文件,以核心可执行程序、pak资源文件、hyb数据、dll运行库、json配置和js脚本为主,整体约101.94MB,解压后可直接使用,共同构成完整的无头浏览器运行环境。已有241人学习下载,适合需要快速搭建无头浏览器环境的开发者。借助该工具,可在不打开完整窗口的前提下完成网页交互测试、批量采集与性能监控,节省系统资源并提升自动化稳定性;同时支持最新CSS、HTML与JavaScript标准,基于Chrome稳定版构建,在性能、安全性和兼容性上均有保障,便于开发者在自动化流程中高效复用浏览器能力。
1. 从 chrome-headless-shell-win64 这个 zip 看 Chrome 无头化的两条路线
chrome-headless-shell-win64-133.0.6943.53.zip 这个文件名里最难读的部分是 chrome-headless-shell。它不是完整 Chrome 的压缩包,而是 Chrome 团队为自动化任务单独编译的无头浏览器可执行文件。Chrome 112 之后,无头模式分成两条线:普通 chrome.exe 内置的新无头模式,以及独立编译的 chrome-headless-shell。我在 Windows Server 上做定时截图、页面巡检和 PDF 报表都用后者,启动快、不吃界面资源、不加载扩展,行为也更贴近旧 headless 语义。这里就从解压、验证版本开始,讲到截图、DOM 导出、PDF 和 CDP 自动化,最后落在版本钉死与排错上。适合写采集、做 UI 自动化、维护脚本化 Chrome 环境的工程师。
2. win64 下解压 chrome-headless-shell 并验证版本的最小命令
2.1 解压后看什么:目录结构与命名差异
官方 Chrome for Testing 下载的压缩包本来叫 chrome-headless-shell-win64.zip,版本号在外层路径里;你手上这个带 133.0.6943.53 的命名,通常是镜像站归档时自己加的,或者按路径规则手工改的名。解压后是一个同名目录,里面没有完整 Chrome 那套 locales、资源包和默认扩展,主体就是 chrome-headless-shell.exe,配上少量运行库。这个结构决定了它的体积和启动速度都优于完整浏览器,也意味着你没法在里面用 --load-extension 加载扩展。
Expand-Archive -Path .\chrome-headless-shell-win64-133.0.6943.53.zip -DestinationPath .\chrome-headless-shell ls .\chrome-headless-shell\chrome-headless-shell-win64\第一行把 zip 解压到指定目录,第二行确认目录内容,看到 chrome-headless-shell.exe 再继续。在 Windows 上解压 exe 类工具最常见的坑是文件被 Mark of the Web 拦截:右键 zip 属性,勾选“解除锁定”,再重新解压,否则后面可能出现不明不白的权限报错。
2.2 版本校验:不启动浏览器的前置断言
$shell = ".\chrome-headless-shell\chrome-headless-shell-win64\chrome-headless-shell.exe" & $shell --version输出里应该同时包含 “Chrome Headless Shell” 字样和 133.0.6943.53。--version 不会启动完整浏览器进程,只是把可执行文件的版本信息打出来,用来验证解压完整性、运行库依赖是否能加载。如果报缺少 DLL 或者版本对不上,先别往下走,重新解压或换下载源,后续所有行为都依赖这个版本与归档名一致。我在脚本里习惯把它做成前置断言:版本不匹配直接退出,而不是让任务带着错误的浏览器跑完再报错。
2.3 第一张截图:六个参数各管什么事
& $shell --headless --disable-gpu --hide-scrollbars ` --window-size=1280,800 ` --screenshot="$PWD\home.png" ` --virtual-time-budget=5000 ` https://example.com这是 chrome-headless-shell 的最小可复现任务,逐项说清楚:
- --headless 在 chrome-headless-shell 上其实是默认语义,但保留它,方便以后把这组参数直接换到完整 Chrome 的新无头模式上;
- --disable-gpu 关闭 GPU 合成。远程桌面断开、无显示设备的 Windows 容器里,GPU 进程经常是报错源头,服务器环境默认加上;
- --window-size=1280,800 决定视口尺寸。截图尺寸、页面媒体查询、懒加载策略都受它影响,宁可设大再裁切;
- --screenshot 接收输出 PNG 路径,路径含空格时用引号包起来;
- --virtual-time-budget=5000 让页面虚拟时钟快进 5 秒。它与 sleep 的本质区别是:setTimeout、requestAnimationFrame 会被加速执行,而不是真等 5 秒,所以跑完通常比真实等待快得多。
执行成功时终端不会打印“截图成功”之类的提示,检查方式是看 home.png 是否存在且非空。失败时最常见的两个原因是参数拼写错误,以及 https://example.com 在内网出口受限的环境里解析不了。
2.4 chrome-headless-shell 高频参数速查表
| 参数 | 作用 | 使用建议 |
|---|---|---|
| --headless | 无头开关 | 保留,便于和完整 Chrome 共用参数 |
| --disable-gpu | 禁用 GPU 合成 | 服务器、容器默认加 |
| --no-sandbox | 关闭渲染沙箱 | 仅服务账户受限时加,别随手加 |
| --window-size=W,H | 视口宽高 | 截图和 PDF 前必设 |
| --hide-scrollbars | 隐藏滚动条 | 截图更干净 |
| --virtual-time-budget=MS | 虚拟时间预算 | 依赖定时器的页面配置 |
| --dump-dom | DOM 输出到 stdout | 配 budget 抓首屏 |
| --print-to-pdf=FILE | 导出 PDF | 配 --no-pdf-header-footer |
| --user-data-dir=DIR | 用户数据目录 | 并发实例必须独立 |
| --remote-debugging-port=PORT | CDP 监听端口 | 自动化、调试时开启 |
这张表是后面的公共底座。接下来看三类高频任务各自怎么组合这些参数。
3. chrome-headless-shell 的三个高频任务:DOM 导出、PDF 与整页截图
3.1 --dump-dom 抓首屏 DOM:预算、编码与重定向
& $shell --dump-dom --virtual-time-budget=3000 https://example.com | Out-File -Encoding utf8 page.html--dump-dom 把页面渲染完成后的 DOM 序列化到 stdout,和 curl 抓 HTML 的区别在于它执行了脚本:SPA 里由 fetch 和模板渲染出来的节点,只要在预算内完成,就会出现在输出里。注意别用 PowerShell 默认的>重定向,它会把文本编码成 UTF-16,抓下来的 HTML 在编辑器里是一堆空字节,这里用 Out-File -Encoding utf8 显式指定编码。
预算给多少?我一般 3000 起步,页面有多轮接口请求就往上加。但有一点要记得:预算管不到真实网络耗时,接口响应慢的时候预算耗尽 DOM 还是空壳,这个在第五章给轮询兜底方案。
3.2 --print-to-pdf 生成报表:页眉页脚与打印背景
& $shell --print-to-pdf="D:\reports\daily.pdf" --no-pdf-header-footer ` --virtual-time-budget=5000 https://example.com--print-to-pdf 走的是打印渲染管线,和截图不是一条路径:CSS 里的 @page 规则、A4 分页、page-break 都会生效。默认生成的 PDF 带浏览器页眉页脚,内容包含标题、日期和 URL,出正式报告很难看,--no-pdf-header-footer 把它们关掉,这个参数在 Chrome 120 之后可用。
命令行版没有“打印背景”开关,深色站点或需要背景色的报告,生成的 PDF 背景是白的。两条出路:在 CSS 里给根元素加 -webkit-print-color-adjust: exact;或者走 CDP 的 Page.printToPDF,把 printBackground 设成 true。后者参数更全,能同时控制纸型、边距和 scale,第四章会看到同一套调用方式。
3.3 整页截图:窗口高度与 captureBeyondViewport 的取舍
默认 --screenshot 只截视口,也就是 window-size 那么大。要整页,暴力做法是把窗口高度拉大:
& $shell --hide-scrollbars --window-size=1280,20000 --screenshot=long.png https://example.com页面在 20000 像素以内都能截到,超出就截断。这个办法的优点是命令简单,缺点是高度写死,页面内容一变就截断。稳定做法是用 CDP 的 Page.captureScreenshot 加 captureBeyondViewport: true,返回的图片以完整内容高度为准。命令行入门用前者,生产环境建议用后者。
3.4 任务与参数组合对照
| 任务 | 参数组合 | 常见失误 |
|---|---|---|
| 首屏截图 | --screenshot --window-size --hide-scrollbars | 不设 window-size 拿到 800x600 默认图 |
| 整页截图 | 拉高 window-size 或 CDP captureBeyondViewport | 高度写死导致截断 |
| DOM 导出 | --dump-dom --virtual-time-budget | 不加预算抓到空壳 |
| PDF 生成 | --print-to-pdf --no-pdf-header-footer | 忘关页眉页脚 |
| 需要登录态的页面 | 复用固定 --user-data-dir | 每次新临时目录导致会话丢失 |
4. 用 CDP 把 chrome-headless-shell 接进 Python 自动化
4.1 启动常驻实例并确认协议端点
& $shell --remote-debugging-port=9222 --user-data-dir="D:\tmp\ch-profile" --disable-gpu about:blank起一个常驻进程,之后不再用命令行一次一个任务,而是通过 Chrome DevTools Protocol 动态创建页面、执行脚本、截图。参数里 --remote-debugging-port=9222 打开 CDP 监听,--user-data-dir 指定专用目录,避免污染真实用户配置。起好后用浏览器访问 http://127.0.0.1:9222/json/version,看到 Browser 字段是 133.0.6943.53 就说明协议层就绪。Windows 10 以上自带 curl,也可以直接curl.exe http://127.0.0.1:9222/json/version在命令行确认。
4.2 Python 最小 CDP 截图脚本
import base64 import json import time import urllib.request import websocket # pip install websocket-client # 通过 HTTP 端点新建一个标签页,返回 target 信息 req = urllib.request.Request( "http://127.0.0.1:9222/json/new?https://example.com", method="PUT", ) with urllib.request.urlopen(req) as resp: target = json.loads(resp.read()) ws = websocket.create_connection(target["webSocketDebuggerUrl"], timeout=30) def cdp(method, params=None, msg_id=1): ws.send(json.dumps({"id": msg_id, "method": method, "params": params or {}})) while True: frame = json.loads(ws.recv()) if frame.get("id") == msg_id: return frame cdp("Page.enable") time.sleep(3) # 演示用等待;生产环境监听 Page.loadEventFired shot = cdp("Page.captureScreenshot", {"format": "png", "captureBeyondViewport": True}) with open("cdp_full.png", "wb") as f: f.write(base64.b64decode(shot["result"]["data"])) ws.close()逻辑说明:/json/new 创建新标签页并返回 JSON,里面的 webSocketDebuggerUrl 就是该页面的 CDP 通道;WebSocket 上跑的是 JSON-RPC 风格的请求,每条消息带自增 id 用来配对响应;Page.captureScreenshot 返回 base64 编码的 PNG,写文件前要 decode。captureBeyondViewport 设为 true 表示截整页而不是视口。
两个容易踩的协议细节:/json/new 在新版本要求 PUT 方法,用 GET 会拿到 405;CDP 响应不保证顺序返回,所以 cdp() 里必须按 id 匹配,不能简单接收第一条。这个函数骨架可以扩展成通用客户端,Runtime.evaluate、Page.printToPDF、Network.setBlockedURLs 都是同一套调用方式。
4.3 与 Selenium、Playwright、Puppeteer 的边界在哪
chrome-headless-shell 不实现 WebDriver 协议,只暴露 CDP。Selenium 的 ChromeDriver 期望后端是完整 Chrome,把 binary 指到这个 exe 会在 session 创建阶段失败。想沿用现成框架,常见做法是 Playwright 的 connectOverCDP,或者 puppeteer-core 指定 executablePath:
const puppeteer = require('puppeteer-core'); const browser = await puppeteer.launch({ executablePath: 'C:\\tools\\chrome-headless-shell-win64\\chrome-headless-shell.exe', headless: 'shell' });说明:puppeteer-core 不会自动下载浏览器,executablePath 指向你解压出来的 exe;headless: 'shell' 是 Puppeteer 21+ 里专门配对旧无头壳的取值,不要写成 true。用 Playwright 的话更直接:实例起好后 chromium.connectOverCDP('http://127.0.0.1:9222') 接管,连 executablePath 都不用传。
4.4 生产环境启动模板:随机端口与 DevToolsActivePort
$base = "D:\tools\chrome-headless-shell-win64" $profile = "D:\tmp\profile-$PID" & "$base\chrome-headless-shell.exe" ` --headless --disable-gpu --no-first-run --no-default-browser-check ` --user-data-dir=$profile --remote-debugging-port=0 about:blank--remote-debugging-port=0 让系统分配随机空闲端口,端口号写入 $profile\DevToolsActivePort 文件的第一行。CI 并发跑多个实例时,不用自己维护端口分配逻辑,读这个文件就能拿到各自实例的地址。--no-first-run 和 --no-default-browser-check 去掉首次启动的提示干扰。$PID 确保每批任务的 profile 目录互不相同,避免进程间抢同一个目录锁。任务结束把这个目录删掉即可。
5. 版本钉死、多实例与三个高频问题的现场处置
5.1 为什么 133.0.6943.53 值得写进 CI 清单
Chrome 大版本决定了 DOM、CSS 和 CDP 协议的默认行为,版本漂移是自动化脚本“昨天还好好的”的最大来源。把 133.0.6943.53 写死在依赖清单里,和锁 npm 版本一个道理。启动前的断言写成这样:
$v = & $shell --version if ($v -notmatch "133\.0\.6943\.53") { throw "chrome-headless-shell 版本漂移: $v" }升级策略是显式的:先升级 puppeteer-core 或 websocket 客户端,再换 shell 版本,顺序反了容易踩协议不兼容。
5.2 多实例并发与 profile 锁
一个常驻实例就是一个进程树加一个 profile 目录。两个进程用同一个 user-data-dir 时,后启动的会因 SingletonLock 直接退出。批量任务里每个实例用独立 profile 目录,端口交给 --remote-debugging-port=0 分配。内存规划我按这个量级起步,具体以任务页面复杂度为准:
| 机器内存 | 建议并发实例数 | 观察指标 |
|---|---|---|
| 8GB | 4 | 进程树总内存接近 3.5GB 就排队 |
| 16GB | 6-8 | 标签页多时单实例可达 800MB-1.2GB |
| 32GB | 10-12 | 先看 CPU 再看内存 |
5.3 三个高频坑及排查顺序
第一,budget 不等于等待网络。慢接口页面的正确姿势是轮询 DOM 而不是无限开大预算:
for _ in range(20): r = cdp("Runtime.evaluate", {"expression": "document.querySelectorAll('tr.item').length"}) if r["result"]["result"].get("value", 0) >= 100: break time.sleep(0.5)第二,中文字体豆腐块。Windows Server 默认不带微软雅黑时截图全是方框。装完字体要换一个新的 user-data-dir 重启实例,字体缓存不会自动刷新。判断方法很直接:看 C:\Windows\Fonts 下有没有 msyh.ttc。
第三,远程桌面断开后的 GPU 报错。断了 RDP 的服务器上 GPU 进程有时起不来,表现是启动卡住或 stderr 出现 GPU 相关错误。保持 --disable-gpu,不要额外加 --use-gl 之类的参数。改完任何参数都先跑一遍 --version 再跑任务,把启动问题和页面问题分开定位。排查顺序固定为:先看 stderr,再看产物文件是否非空,最后怀疑参数组合。日志里出现 panic 或 DLL 加载失败,通常不是参数问题,是文件没下全。另外记得实例退出前调 Browser.close 而不是直接 kill 进程树,profile 里的锁文件才能正常释放,这是并发场景里最容易被忽略的收尾动作。
本文还有配套的精品资源,点击获取