Puppeteer 是什么:掌控 Chrome 与 Firefox 的 JavaScript 自动化利器
导读:本文以 docs/guides/what-is-puppeteer.md 为骨架,系统解读 Puppeteer 的核心定位、两大浏览器自动化协议(DevTools Protocol 与 WebDriver BiDi)、Headless 运行方式与六大典型能力场景,并结合本仓库的源码、API 文档与示例代码深入印证其底层实现。阅读后你将理解 Puppeteer 的架构全貌、默认协议选择逻辑与适用边界,并能立即写出第一个可运行的浏览器自动化脚本。
Puppeteer 是什么
Puppeteer 是一个 JavaScript 库,它对外提供一套高层级 API,用于通过 DevTools Protocol(简称 CDP)或 WebDriver BiDi 协议控制 Chrome 或 Firefox 浏览器。作为对比,同样是自动化工具,WebDriver Classic 要求必须独立启动浏览器进程再连接,而 Puppeteer 从设计上就与浏览器的启动、页面创建、交互操作流程深度绑定,开箱即用。
在协议选择上,Puppeteer 采取了“自动择优”的策略,而这一策略在仓库源码中写得非常直白。在 BrowserLauncher.ts 中可以看到:
let {protocol} = options;
// Default to 'webDriverBiDi' for Firefox.
if (this.#browser === 'firefox' && protocol === undefined) {
protocol = 'webDriverBiDi';
}
...
if (this.#browser === 'firefox' && protocol === 'cdp') {
throw new Error('Connecting to Firefox using CDP is no longer supported');
}
从中可以提炼出两条关键事实:
- Firefox 默认走 WebDriver BiDi,且显式指定 Firefox + CDP 组合会直接抛出错误(即通过 CDP 连接 Firefox 已不再被支持);
- Chrome 默认走 CDP,因为 WebDriver BiDi 尚未覆盖全部 CDP 特性,需要时你可以通过
protocol: 'webDriverBiDi'显式切换。
默认无头,可选有头
Puppeteer 默认以 headless(无界面)模式运行浏览器,这意味着你不需要一个真实的显示器或桌面环境,非常适合跑在 CI、服务器与容器中;同时它也完全支持配置成可见的 “headful”(有头)浏览器运行,便于在开发调试阶段观察页面实际表现。关于这一主题的完整配置方法,可阅读仓库内文档 Headless mode。
Puppeteer 能做什么
正如原文档强调的:“大多数你在浏览器里手动能做的事情,都可以用 Puppeteer 自动化完成。” 结合仓库内的配套指南(见 docs/guides 目录),它的能力主要覆盖以下六大方向。
1. 自动化交互与 UI 测试
自动化完成表单提交、UI 测试、键盘输入、鼠标点击、滚动、拖拽等一整套“真人操作”。
- 相关 API 文档:page.click、page.type、page.hover、page.locator、page.select
- 仓库还专门维护了页面交互指南 page-interactions.md 与页面内 JavaScript 执行指南 javascript-execution.md,是学习这些 API 的第一手资料。
2. 构建自动化测试环境
你可以直接用最新的 JavaScript 与浏览器特性来搭建端到端测试环境。Puppeteer 不会因为运行在自动化脚本里就限制你用新的语言特性——它会把 page.evaluate() 中的代码直接在浏览器环境执行。
本仓库自带的测试工程位于 test/src,包含 76 个 TypeScript 测试文件,覆盖了从页面跳转、网络拦截到截图对比等大量行为;同时 test/TestExpectations.json、test/TestSuites.json 与 test/CanaryTestExpectations.json 构成了跨浏览器、跨协议的测试矩阵,可作为构建大型自动化测试基础设施时的参考。
3. 采集 Timeline Trace 做性能诊断
可以对站点抓取 Timeline trace(时间线轨迹),用于定位页面加载与运行时性能瓶颈。这类底层能力在 CDP 协议下通过 Tracing 域实现,对应的 Puppeteer 封装为 Tracing(提供 start/stop 方法)。
4. 测试 Chrome 扩展
Puppeteer 支持自动化测试 Chrome 扩展:可以安装扩展、打开扩展页面、访问其 popup 逻辑。仓库内有专门文档 chrome-extensions.md,还提供了一个可直接运行的完整示例工程 examples/puppeteer-in-extension(内含 manifest.json、扩展页面与配套脚本),相关 API 见 browser.installextension 与 browser.extensions。
5. 生成页面截图与 PDF
对页面进行截图(含整页长截图)以及生成 PDF 文件,是 Puppeteer 被使用最广的能力之一:
- 截图指南见 screenshots.md,可直接运行仓库示例 examples/screenshot.js 与 examples/screenshot-fullpage.js;
- PDF 生成指南见 pdf-generation.md,对应示例为 examples/pdf.js。
6. 爬取 SPA 并生成预渲染内容
Puppeteer 可以爬取 SPA(单页应用) 并抓取其真实渲染后的 DOM,从而生成预渲染(pre-rendered)内容——也就是常说的 “SSR”(Server-Side Rendering)的一种实现路径。这让搜索引擎爬虫与低 JS 环境也能拿到完整内容。
7. 更多领域能力(仓库印证)
在上述六大方向之外,本仓库的 docs/guides 还沉淀了围绕 Puppeteer 周边生态的完整指南,例如:
- 浏览器管理:browser-management.md(多页面、多 BrowserContext、多 Target 的组织方式)
- 网络请求拦截与日志:network-interception.md、network-logging.md,配套示例 examples/block-images.js、examples/proxy.js、examples/custom-event.js
- Cookie 管理:cookies.md
- 跨浏览器运行:cross-browser.js 演示了同一套脚本在 Chrome 与 Firefox 下的运行方式
- 配置与调试:configuration.md、debugging.md
- 容器化部署:docker.md,配套 docker/Dockerfile 与冒烟测试 docker/test/smoke-test.js
深入理解两大自动化协议
理解 “What is Puppeteer” 的关键,是弄清楚它背后的双协议架构。
CDP(DevTools Protocol)
DevTools Protocol 是 Chrome 为开发者工具提供的调试协议,历史最悠久、功能覆盖最全。Puppeteer 以 CDP 为默认协议连接 Chrome,并在其上封装出截图、性能追踪、网络拦截等丰富能力。仓库中对应的协议实现位于 packages/puppeteer-core/src/cdp,你可以直接读到 Page、Browser、Connection 等在 CDP 层上的具体实现。
WebDriver BiDi
WebDriver BiDi 是 W3C 正在推进的新一代跨浏览器自动化协议,目标是融合 WebDriver “Classic” 与 CDP 双方优点:支持双向通信(bi-directional communication),从而默认就具备低延迟、快速度的特性,同时提供低层级的精细控制。它让“一套 API 同时驱动 Chrome 与 Firefox”成为现实——Firefox 侧甚至已经关闭了 CDP 通道,全面转向 WebDriver BiDi。
仓库对 WebDriver BiDi 的实现位于 packages/puppeteer-core/src/bidi。关于“哪些 Puppeteer 特性已完整支持 BiDi、哪些暂不支持”的详细能力矩阵,请以仓库内文档 docs/webdriver-bidi.md 为准——其中的关键提示是:当某个特性在 WebDriver BiDi 下尚未支持时,调用会抛出 UnsupportedOperation 错误,而不是静默失败。
例如,通过 BiDi 同时驱动 Firefox 与 Chrome 的最小示例为:
import puppeteer from 'puppeteer';
// Firefox:默认即使用 WebDriver BiDi
const firefoxBrowser = await puppeteer.launch({
browser: 'firefox',
});
const page = await firefoxBrowser.newPage();
// ...
await firefoxBrowser.close();
// Chrome:显式声明使用 WebDriver BiDi(否则默认走 CDP)
const chromeBrowser = await puppeteer.launch({
browser: 'chrome',
protocol: 'webDriverBiDi',
});
// ...
await chromeBrowser.close();
关于支持的浏览器与系统版本约束,可查看 supported-browsers.md 与 system-requirements.md。
Headless 模式:默认与三种用法
“Puppeteer 默认 headless 运行” 这句话包含了丰富的细节。官方文档 headless-modes.md 给出了三种明确的启动方式:
// 1. 默认:等价于 {headless: true},即新版 Headless 模式
const browser = await puppeteer.launch();
// 2. 旧版独立产物 chrome-headless-shell(更轻量、纯自动化场景性能更优)
const browser = await puppeteer.launch({headless: 'shell'});
// 3. 有头(headful)模式:可见的浏览器窗口,便于人眼调试
const browser = await puppeteer.launch({headless: false});
从源码结构看,在 v22 之前 Puppeteer 默认使用旧版 Headless 模式;如今旧版被拆分为独立的 chrome-headless-shell 二进制。它不会完全复刻完整版 Chrome 的全部行为,但在不需要完整浏览器特性的纯自动化任务里性能表现更好——如果你的场景对性能更敏感,优先选择 'shell'。该选项在 LaunchOptions.ts 中被定义为 headless?: boolean | 'shell',与文档描述完全对应。
同理,启动时支持的浏览器、协议等参数统一定义在 LaunchOptions.ts(LaunchOptions extends ConnectOptions)中,其中浏览器类型字段位于 LaunchOptions.ts。
快速上手:安装与第一个脚本
两个 npm 包,如何选择
npm i puppeteer # 完整方案:安装时自动下载配套的 Chrome
npm i puppeteer-core # 轻量方案:只装库,不下载浏览器(需自带浏览器)
puppeteer:附带浏览器下载逻辑,对新手最友好,开箱即用;puppeteer-core:适合你已有浏览器安装或需要精确控制浏览器版本的高级场景。
需要特别留意:现代包管理器(npm、pnpm、Yarn、Bun、Deno 等)默认会拦截依赖安装脚本。如果安装脚本被拦截,Puppeteer 将不会在安装阶段下载浏览器,运行时会因此报错。此时你可以手动执行:
npx puppeteer browsers install
或者把 "puppeteer" 加入 npm 配置的 "allowScripts" 中以放行安装脚本。本仓库 README.md 对此有完整说明。
第一个完整示例
下面的示例完整复现了仓库 README.md 的入门脚本——它演示了浏览器启动、页面导航、视口设置、键盘输入、ARIA 可访问性选择器、文本定位与页面求值等一整套核心 API:
import puppeteer from 'puppeteer';
// 或:import puppeteer from 'puppeteer-core';
// 启动浏览器并打开空白页
const browser = await puppeteer.launch();
const page = await browser.newPage();
// 导航到目标页面
await page.goto('https://developer.chrome.com/');
// 设置屏幕尺寸
await page.setViewport({width: 1080, height: 1024});
// 用键盘触发搜索菜单
await page.keyboard.press('/');
// 通过可访问名称定位输入框并填充
await page.locator('::-p-aria(Search)').fill('automate beyond recorder');
// 等待并点击第一条结果
await page.locator('.devsite-result-item-link').click();
// 用唯一文本定位标题元素并读取其文本
const textSelector = await page
.locator('::-p-text(Customize and automate)')
.waitHandle();
const fullTitle = await textSelector?.evaluate(el => el.textContent);
// 输出完整标题
console.log('The title of this blog post is "%s".', fullTitle);
await browser.close();
这段脚本同时展示了 Puppeteer 在设计上的一个独特亮点:::-p-aria / ::-p-text 这类 P 选择器。它们让定位器(Locator)不再只能依赖脆弱的 CSS 类名,而是可以直接面向 ARIA 可访问性角色或可见文本进行定位,使自动化代码更接近真实用户的操作语义。
在仓库中继续探索
本仓库是一个标准的 Puppeteer monorepo,各模块之间边界清晰,非常适合按需精读:
- packages/puppeteer-core/src/api:对外暴露的高层 API 定义(Page、Browser、Frame、ElementHandle 等),是了解“API 能做什么”的最佳入口;
- packages/puppeteer-core/src/cdp 与 packages/puppeteer-core/src/bidi:CDP 与 WebDriver BiDi 两套协议的底层实现,可对照研读“同一 API 如何映射到两种协议”;
- packages/puppeteer-core/src/node:浏览器启动器与启动参数解析,BrowserLauncher.ts 中的协议默认逻辑(Firefox 默认 BiDi)正是在这里实现的;
- packages/browsers:独立的浏览器下载/安装/版本管理工具,
npx puppeteer browsers install便依赖它; - examples:一组可立即运行的真实示例(截图、PDF、网络拦截、跨浏览器、扩展测试等);
- docs/api:全量 API 参考文档,docs/api/index.md 是查阅入口;
- test/src 与 test:跨浏览器、跨协议的测试套件与期望矩阵,是理解每个 API 实际行为(含 WebDriver BiDi 下的行为差异)的权威依据。
使用前提与边界
在把 Puppeteer 引入项目之前,有几个需要明确的前提与边界:
- 浏览器依赖:使用
puppeteer包时安装脚本会下载 Chrome;若用puppeteer-core,则需要你自行准备浏览器二进制,并保证其存在(否则启动时会抛Browser was not found错误,BrowserLauncher.ts 中可以看到该检查逻辑); - 协议差异:WebDriver BiDi 尚未覆盖全部 CDP 特性,某些 API(如各种 emulation、Coverage、Tracing、拖拽专用 API 等)在 BiDi 下会抛
UnsupportedOperation,完整支持矩阵请参阅 docs/webdriver-bidi.md; - 环境约束:具体支持哪些浏览器与系统版本,请以 supported-browsers.md 与 system-requirements.md 为准。
小结
一句话概括:Puppeteer 是一个把 Chrome/Firefox 的底层自动化协议(CDP 与 WebDriver BiDi)封装成直观 JavaScript 高层 API 的库——它默认无头运行、可按需切换有头或更轻量的 chrome-headless-shell,并覆盖表单与 UI 自动化、端到端测试、性能轨迹采集、扩展测试、截图/PDF、SPA 预渲染等几乎全部浏览器自动化场景。理解它的协议架构与默认行为(Firefox→BiDi、Chrome→CDP),是后续深入使用、排障乃至阅读其源码的第一步。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0630
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00