Doramagic 项目包 · 项目说明书
puppeteer 项目
生成时间:2026-05-16 04:41:15 UTC
Puppeteer项目概览
Puppeteer是一个由Google维护的Node.js库,它提供了高级API来通过Chrome DevTools Protocol控制无头Chrome或Chromium浏览器。Puppeteer本质上是Chrome浏览器的自动化工具,允许开发者以编程方式执行通常需要手动操作的任务。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
1. 项目简介
Puppeteer是一个由Google维护的Node.js库,它提供了高级API来通过Chrome DevTools Protocol控制无头Chrome或Chromium浏览器。Puppeteer本质上是Chrome浏览器的自动化工具,允许开发者以编程方式执行通常需要手动操作的任务。
1.1 核心功能
| 功能类别 | 说明 |
|---|---|
| 页面导航 | 加载网页、访问URL、处理导航事件 |
| 内容抓取 | 提取页面DOM、获取元素内容、截图 |
| 用户交互 | 模拟键盘输入、鼠标点击、表单提交 |
| 性能监控 | 跟踪网络请求、测量页面性能 |
| 设备模拟 | 模拟移动设备、iPhone、Android等 |
| 浏览器扩展 | 支持加载Chrome扩展程序 |
资料来源:README.md:1-15
2. 项目架构
Puppeteer采用monorepo架构,主要由核心包和配套工具组成。
2.1 核心包结构
graph TD
A[Puppeteer] --> B[puppeteer-core]
A --> C[@puppeteer/browsers]
A --> D[@puppeteer/ng-schematics]
B --> E[API层]
B --> F[CDP通信层]
B --> G[公共组件]
E --> H[Page]
E --> I[Browser]
E --> J[BrowserContext]
G --> K[Configuration]
G --> L[Device]
G --> M[LazyArg]
G --> N[Debug]2.2 主要包说明
| 包名 | 用途 |
|---|---|
puppeteer | 完整包,包含浏览器下载功能 |
puppeteer-core | 轻量级核心库,不自动下载浏览器 |
@puppeteer/browsers | 浏览器管理和下载CLI工具 |
@puppeteer/ng-schematics | Angular集成工具 |
资料来源:README.md:1-10
3. 安装与配置
3.1 安装方式
# 完整安装(自动下载Chrome)
npm i puppeteer
# 仅安装核心库(不下载浏览器)
npm i puppeteer-core
3.2 启动选项配置
Puppeteer支持丰富的浏览器启动配置选项:
| 选项 | 类型 | 默认值 | 说明 | |
|---|---|---|---|---|
executablePath | string | - | 指定浏览器可执行文件路径 | |
ignoreDefaultArgs | `boolean \ | string[]` | false | 是否忽略默认启动参数 |
enableExtensions | `boolean \ | string[]` | - | 启用Chrome扩展 |
handleSIGINT | boolean | true | Ctrl+C时关闭浏览器 | |
handleSIGTERM | boolean | true | SIGTERM时关闭浏览器 | |
handleSIGHUP | boolean | true | SIGHUP时关闭浏览器 | |
timeout | number | 30000 | 启动超时时间(毫秒) |
资料来源:packages/puppeteer-core/src/node/LaunchOptions.ts:1-50
3.3 全局配置
Configuration接口定义了全局配置选项:
interface Configuration {
defaultBrowser?: SupportedBrowser;
temporaryDirectory?: string;
skipDownload?: boolean;
logLevel?: 'silent' | 'error' | 'warn';
experiments?: ExperimentsConfiguration;
chrome?: ChromeSettings;
firefox?: FirefoxSettings;
}
| 配置项 | 说明 |
|---|---|
defaultBrowser | 默认浏览器类型,默认chrome |
temporaryDirectory | 临时文件目录,默认为os.tmpdir() |
skipDownload | 安装时跳过浏览器下载 |
logLevel | 日志级别,默认warn |
chrome | Chrome特定配置 |
资料来源:packages/puppeteer-core/src/common/Configuration.ts:1-40
4. 核心API
4.1 Page类
Page类是Puppeteer最核心的类,继承自EventEmitter,负责页面操作和交互。
graph LR
A[Page] --> B[事件监听]
A --> C[页面导航]
A --> D[元素查询]
A --> E[函数暴露]#### 4.1.1 常用方法
| 方法 | 说明 |
|---|---|
goto(url) | 导航到指定URL |
waitForSelector(selector) | 等待元素出现 |
click(selector) | 点击元素 |
type(selector, text) | 输入文本 |
evaluate(fn) | 在页面上下文执行JavaScript |
screenshot() | 页面截图 |
setViewport() | 设置视口大小 |
#### 4.1.2 事件系统
Page类继承EventEmitter模式,支持以下典型事件:
page.once('load', () => console.log('Page loaded!'));
function logRequest(interceptedRequest) {
console.log('A request was made:', interceptedRequest.url());
}
page.on('request', logRequest);
page.off('request', logRequest);
资料来源:packages/puppeteer-core/src/api/Page.ts:1-80
4.2 exposeFunction方法
exposeFunction允许将Node.js函数暴露给浏览器页面调用:
page.exposeFunction('readfile', async filePath => {
return fs.readFile(filePath, 'utf8');
});
await page.evaluate(async () => {
const content = await window.readfile('/etc/hosts');
console.log(content);
});
资料来源:packages/puppeteer-core/src/api/Page.ts:100-140
4.3 Locators API
Locators是实验性的定位器API,提供更可靠的元素定位方式:
// 使用ARIA文本定位
await page.locator('::-p-aria(Search)').fill('automate beyond recorder');
// 使用文本内容定位
await page.locator('::-p-text(Customize and automate)').waitHandle();
// 使用组合选择器
await page.locator('.devsite-result-item-link').click();
5. 设备模拟
Puppeteer内置了丰富的设备模拟功能,通过KnownDevices对象提供:
import {KnownDevices} from 'puppeteer';
const iPhone = KnownDevices['iPhone 15 Pro'];
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.emulate(iPhone);
| 设备类别 | 示例设备 |
|---|---|
| iPhone系列 | iPhone 12, iPhone 15 Pro |
| iPad系列 | iPad Mini, iPad Pro |
| Android | Android Phone, Android Tablet |
资料来源:packages/puppeteer-core/src/common/Device.ts:1-30
6. @puppeteer/browsers CLI
@puppeteer/browsers包提供浏览器管理的命令行工具:
6.1 常用命令
# 安装Chrome稳定版
npx @puppeteer/browsers install chrome@stable
# 安装指定版本
npx @puppeteer/browsers install [email protected]
# 安装ChromeDriver
npx @puppeteer/browsers install chromedriver@canary
# 列出已安装浏览器
npx @puppeteer/browsers list
# 清除所有已安装浏览器
npx @puppeteer/browsers clear
6.2 系统要求
| 平台 | 依赖 |
|---|---|
| Linux/MacOS | unzip |
| Windows | tar.exe |
| Firefox下载(Linux) | xz, bzip2 |
| Firefox下载(MacOS) | hdiutil |
资料来源:packages/browsers/README.md:1-60
7. 工作流程示例
7.1 基础使用流程
graph TD
A[启动浏览器] --> B[创建页面]
B --> C[设置视口]
C --> D[导航到URL]
D --> E[执行操作]
E --> F[提取数据]
F --> G[关闭浏览器]
D -.->|网络请求| H[request事件]
E -.->|控制台| I[console事件]
F -.->|截图| J[screenshot]7.2 完整示例代码
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({width: 1080, height: 1024});
await page.goto('https://developer.chrome.com/');
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();
资料来源:README.md:15-40
8. 调试功能
Puppeteer提供内置调试支持,通过__PUPPETEER_DEBUG环境变量控制:
# 开启所有日志
window.__PUPPETEER_DEBUG='*';
# 仅记录Page通道
window.__PUPPETEER_DEBUG='Page';
# 记录所有以Page开头的通道
window.__PUPPETEER_DEBUG='Page*';
调试输出示例:
const log = debug('Page');
log('new page created');
// 输出: "Page: new page created"
资料来源:packages/puppeteer-core/src/common/Debug.ts:1-30
9. 项目组织结构
puppeteer/
├── packages/
│ ├── puppeteer-core/ # 核心API包
│ │ └── src/
│ │ ├── api/ # Page、Browser等API
│ │ ├── cdp/ # Chrome DevTools Protocol通信
│ │ └── common/ # 公共组件
│ ├── browsers/ # 浏览器管理CLI
│ └── ng-schematics/ # Angular集成
├── examples/ # 示例代码
├── docker/ # Docker配置
└── tools/ # 开发工具(ESLint等)
10. 相关资源
| 资源 | 链接 |
|---|---|
| 官方文档 | pptr.dev |
| 示例集合 | pptr.dev/examples |
| 选择器指南 | pptr.dev/guides/page-interactions#selectors |
| MCP支持 | chrome-devtools-mcp |
| WebMCP | pptr.dev/guides/webmcp |
资料来源:[README.md:1-15]()
安装与入门指南
Puppeteer 是一个流行的 Node.js 库,它提供了高级 API 来通过 DevTools 协议控制 Chromium、Chrome 或 Firefox 浏览器。Puppeteer 主要用于网页自动化、网页抓取、生成截图、生成 PDF、测试 Web 应用等场景。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Puppeteer 是一个流行的 Node.js 库,它提供了高级 API 来通过 DevTools 协议控制 Chromium、Chrome 或 Firefox 浏览器。Puppeteer 主要用于网页自动化、网页抓取、生成截图、生成 PDF、测试 Web 应用等场景。
本指南将详细介绍 Puppeteer 的安装方式、系统要求、浏览器配置以及快速入门方法,帮助开发者快速上手使用 Puppeteer。
安装方式
使用 npm 安装
Puppeteer 提供两个主要的 npm 包,开发者可以根据需求选择合适的版本:
| 包名 | 说明 | 适用场景 |
|---|---|---|
puppeteer | 完整版,包含浏览器下载功能 | 标准使用,需要自动下载 Chrome |
puppeteer-core | 精简版,不包含浏览器 | 已在环境中安装浏览器,或使用自定义浏览器 |
标准安装命令如下:
npm i puppeteer
此命令会在安装过程中自动下载与 Puppeteer 版本兼容的 Chrome 浏览器。
如果只需要将 Puppeteer 作为库使用,而不包含浏览器:
npm i puppeteer-core
资料来源:README.md:Installation
使用 puppeteer-core 的注意事项
使用 puppeteer-core 时,需要在 puppeteer.launch() 方法中通过 executablePath 参数指定浏览器可执行文件路径:
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.launch({
executablePath: '/path/to/chromium',
// 其他配置选项
});
系统要求
Node.js 版本要求
Puppeteer 对 Node.js 版本有特定要求,具体版本信息请参考 package.json 中的 engines 字段。建议使用 LTS(长期支持)版本的 Node.js 以确保稳定性。
资料来源:packages/browsers/README.md:1-10
浏览器下载的系统依赖
不同的浏览器下载需要不同的系统工具支持:
#### Firefox 下载要求
| 操作系统 | 必需工具 |
|---|---|
| Linux | xz 和 bzip2 工具(用于解压 .tar.gz 和 .tar.bz2 归档文件) |
| macOS | hdiutil(用于解压 .dmg 归档文件) |
#### Chrome 下载要求
| 操作系统 | 必需工具 |
|---|---|
| Linux/macOS | unzip |
| Windows | tar.exe |
资料来源:packages/browsers/README.md:System requirements
浏览器管理
@puppeteer/browsers 包
@puppeteer/browsers 是官方提供的浏览器管理工具,支持从命令行界面(CLI)或编程方式管理浏览器和驱动。
核心命令
#### 安装浏览器
# 下载最新的 Stable 频道 Chrome for Testing
npx @puppeteer/browsers install chrome@stable
# 下载指定版本的 Chrome for Testing
npx @puppeteer/browsers install [email protected]
# 下载指定里程碑的最新版本
npx @puppeteer/browsers install chrome@117
# 下载最新的 ChromeDriver(Canary 频道)
npx @puppeteer/browsers install chromedriver@canary
# 下载指定版本的 ChromeDriver
npx @puppeteer/browsers install chromedriver@116
#### 列出已安装的浏览器
npx @puppeteer/browsers list
#### 清除所有已安装的浏览器
npx @puppeteer/browsers clear
#### 获取帮助信息
# 获取所有命令的帮助
npx @puppeteer/browsers --help
# 获取特定命令的帮助
npx @puppeteer/browsers install --help
npx @puppeteer/browsers launch --help
版本指定方式
| 指定方式 | 示例 | 说明 |
|---|---|---|
latest | chrome@latest | 下载最新稳定版 |
| 里程碑版本 | chrome@117 | 下载该里程碑的最新版本 |
| 完整版本号 | [email protected] | 下载指定精确版本 |
| 频道 | chromedriver@canary | 下载指定频道的最新版本 |
资料来源:packages/browsers/README.md:CLI
浏览器管理 API
除了 CLI,还可以编程方式使用 @puppeteer/browsers:
import {install, launch, clear, list} from '@puppeteer/browsers';
// 列出已安装的浏览器
const installed = await list({});
// 安装浏览器
await install({
browser: 'chrome',
channel: 'stable',
});
// 启动浏览器
const process = await launch({
browser: 'chrome',
channel: 'stable',
});
快速入门
基本示例
以下是一个完整的 Puppeteer 使用示例,展示了打开浏览器、导航到网页、模拟用户交互的基本流程:
import puppeteer from 'puppeteer';
async function main() {
// 启动浏览器并打开新的空白页
const browser = await puppeteer.launch();
const page = await browser.newPage();
// 导航到目标 URL
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();
}
main();
资料来源:README.md:Example
核心概念说明
#### 浏览器实例(Browser)
通过 puppeteer.launch() 创建浏览器实例,这是所有浏览器操作的基础。
const browser = await puppeteer.launch({
headless: true, // 是否使用无头模式
args: ['--no-sandbox'], // 浏览器启动参数
timeout: 30000, // 启动超时时间(毫秒)
});
#### 页面(Page)
通过 browser.newPage() 创建新的页面实例,Page 类继承自 EventEmitter,支持丰富的事件机制:
page.on('console', msg => console.log('PAGE LOG:', msg.text()));
page.on('request', request => console.log('REQUEST:', request.url()));
page.on('load', () => console.log('Page loaded!'));
#### 定位器(Locator)
Puppeteer 推荐使用 Locator API 进行元素定位和交互,Locator 提供了更强大的等待和重试机制:
// 使用文本内容定位
await page.locator('::-p-text(Submit)').click();
// 使用 ARIA 属性定位
await page.locator('::-p-aria(Search)').fill('query');
// 使用 CSS 选择器定位
await page.locator('.button.primary').click();
#### 元素操作
| 操作 | 方法 | 说明 |
|---|---|---|
| 点击 | locator.click() | 单击元素 |
| 输入 | locator.fill() | 填充输入框 |
| 获取文本 | evaluate(el => el.textContent) | 获取元素文本 |
| 获取属性 | locator.getAttribute() | 获取元素属性值 |
| 截图 | page.screenshot() | 截取页面截图 |
| 生成 PDF | page.pdf() | 生成 PDF 文档 |
资料来源:packages/puppeteer-core/src/api/Page.ts:$$eval
运行示例项目
环境准备
- 克隆仓库并安装依赖
git clone https://github.com/puppeteer/puppeteer.git
cd puppeteer
npm install
- 构建 Puppeteer
npm run build
运行单个示例
构建完成后,使用以下命令运行单个示例脚本:
NODE_PATH=../ node examples/search.js
示例脚本位于 examples/ 目录下,提供了多种使用场景的参考实现,包括网页搜索、截图、PDF 生成等功能。
选择器语法参考
Puppeteer 专用选择器
| 选择器类型 | 语法格式 | 示例 |
|---|---|---|
| 文本选择器 | ::-p-text(<文本>) | page.locator('::-p-text(Submit)') |
| ARIA 选择器 | ::-p-aria(<角色>[name=<名称>]) | page.locator('::-p-aria(Button)') |
| XPath 选择器 | ::-p-xpath(<xpath>) | page.locator('::-p-xpath(//button)') |
| Shadow DOM | >>> <选择器> | page.locator('>>> .custom-element') |
Angular Schematics 选择器对照
对于从 Angular/Protractor 迁移的用户,以下是选择器语法对照:
| Protractor | Puppeteer |
|---|---|
$(by.id('id')) | page.$('#id') |
$(by.cssContainingText('css', 'text')) | page.$('css ::-p-text(text)') |
$(by.deepCss('css')) | page.$(':scope >>> css') |
$(by.xpath('xpath')) | page.$('::-p-xpath(xpath)') |
资料来源:packages/ng-schematics/README.md:Selectors
MCP 集成
Puppeteer 支持 Model Context Protocol (MCP),可以用于 AI 驱动的浏览器自动化:
安装 chrome-devtools-mcp
npm install chrome-devtools-mcp
WebMCP 支持
Puppeteer 还支持实验性的 WebMCP API,为基于 Web 的 AI 代理提供浏览器自动化能力。
资料来源:README.md:MCP
故障排除
常见安装问题
#### 浏览器下载失败
如果浏览器下载失败,可以尝试:
- 手动下载浏览器并使用
executablePath指定路径 - 使用已安装系统的浏览器
- 检查网络连接和代理设置
#### 权限错误
在 Linux 或容器环境中,可能需要添加额外参数:
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
调试模式
启用 Puppeteer 调试日志:
# 设置调试环境变量
window.__PUPPETEER_DEBUG='*'; // 记录所有日志
window.__PUPPETEER_DEBUG='Page'; // 只记录 Page 频道
window.__PUPPETEER_DEBUG='foo*'; // 记录所有以 foo 开头的频道
在代码中使用调试日志:
import {debug} from '@puppeteer/puppeteer-core';
const log = debug('Page');
log('new page created');
资料来源:packages/puppeteer-core/src/common/Debug.ts:Debug
下一步
完成安装和入门后,建议进一步了解以下内容:
- 页面交互:深入学习页面点击、表单填写、键盘输入等交互操作
- 网络请求拦截:掌握请求和响应的监控、修改和模拟
- 性能分析:使用 Puppeteer 进行页面性能测试和优化
- 无头模式与有头模式:了解不同模式下的使用场景和配置
- 高级配置:学习浏览器启动参数、代理设置、用户数据目录等高级特性
如需更多示例和详细文档,请访问 pptr.dev/examples。
资料来源:[README.md:Installation]()
Puppeteer系统架构
Puppeteer是一个由Google维护的Node.js库,它提供了高级API来通过DevTools协议控制Chrome或Firefox浏览器。该项目的核心设计围绕浏览器自动化、网页抓取和性能监控等场景展开,采用分层架构以实现良好的模块化和可扩展性。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Puppeteer是一个由Google维护的Node.js库,它提供了高级API来通过DevTools协议控制Chrome或Firefox浏览器。该项目的核心设计围绕浏览器自动化、网页抓取和性能监控等场景展开,采用分层架构以实现良好的模块化和可扩展性。
Puppeteer的架构主要分为以下几个层次:
| 层次 | 描述 | 主要模块 |
|---|---|---|
| 用户API层 | 面向开发者的TypeScript/JavaScript接口 | Page、Browser、Frame |
| 协议抽象层 | 封装浏览器通信协议 | CDP (Chrome DevTools Protocol) |
| 核心引擎层 | 实现核心自动化逻辑 | puppeteer-core |
| 节点运行时层 | Node.js环境特定功能 | LaunchOptions、PuppeteerNode |
| 工具层 | 辅助功能 | 设备模拟、调试、配置管理 |
资料来源:packages/puppeteer-core/src/api/Page.ts:310-320
核心模块架构
1. 包结构
Puppeteer项目采用monorepo结构,主要包含以下npm包:
| 包名 | 用途 |
|---|---|
puppeteer | 完整的Puppeteer包,包含浏览器下载 |
puppeteer-core | 核心库,不包含浏览器二进制文件 |
@puppeteer/browsers | 浏览器管理和启动CLI工具 |
@puppeteer/ng-schematics | Angular schematics集成 |
资料来源:README.md:1-10
2. Page类架构
Page是Puppeteer中最核心的类之一,它继承自EventEmitter并提供了丰富的浏览器页面操作能力。
graph TD
EventEmitter --> Page
Page --> |extends| CDPPage
Page --> |extends| WebDriverPage
Page --> |使用| TimeoutSettings
Page --> |管理| RequestHandlers
Page --> |发出| PageEvents
subgraph "Page核心功能"
exposeFunction
evaluate
goto
setContent
locator
endPage类的关键内部状态:
abstract class Page extends EventEmitter<PageEvents> {
_isDragging = false; // 拖拽状态
_timeoutSettings = new TimeoutSettings(); // 超时设置
_tabId = ''; // 标签页标识符
#requestHandlers = new WeakMap<>(); // 请求处理器
#inflight$ = new ReplaySubject<number>(1); // 进行中的请求
}
资料来源:packages/puppeteer-core/src/api/Page.ts:290-305
3. 抽象设计与实现分离
Puppeteer采用了抽象基类的设计模式,定义了清晰的接口契约。这种设计允许不同的协议实现共存:
graph LR
subgraph "抽象层"
Page
Browser
Frame
end
subgraph "CDP实现"
CDPPage
CDPBrowser
CDPFrame
end
subgraph "WebDriver实现"
WebDriverPage
WebDriverBrowser
WebDriverFrame
end
Page --> CDPPage
Page --> WebDriverPage配置系统
Configuration接口
Puppeteer提供了灵活的配置系统,支持多种自定义选项:
interface Configuration {
defaultBrowser?: SupportedBrowser; // 默认浏览器
temporaryDirectory?: string; // 临时目录
skipDownload?: boolean; // 跳过下载
logLevel?: 'silent' | 'error' | 'warn'; // 日志级别
experiments?: ExperimentsConfiguration; // 实验性选项
chrome?: ChromeSettings; // Chrome特定设置
firefox?: FirefoxSettings; // Firefox特定设置
}
资料来源:packages/puppeteer-core/src/common/Configuration.ts:30-60
环境变量覆盖
配置选项可以通过环境变量进行覆盖:
| 配置属性 | 环境变量 | 默认值 |
|---|---|---|
temporaryDirectory | PUPPETEER_TMP_DIR | os.tmpdir() |
skipDownload | PUPPETEER_SKIP_DOWNLOAD | false |
Chrome skipDownload | PUPPETEER_CHROME_SKIP_DOWNLOAD | false |
Chrome downloadBaseUrl | PUPPETEER_CHROME_DOWNLOAD_BASE_URL | storage.googleapis.com |
执行上下文与代码注入
ExecutionContext执行上下文
Puppeteer通过ExecutionContext类封装了CDP的Runtime.evaluate和Runtime.callFunctionOn方法:
sequenceDiagram
用户代码 ->> Page: evaluate(pageFunction)
Page ->> ExecutionContext: evaluate(pageFunction)
ExecutionContext ->> CDPClient: Runtime.evaluate
CDPClient -->> ExecutionContext: remoteObject
ExecutionContext ->> ExecutionContext: createCdpHandle
ExecutionContext -->> 用户代码: JSHandle核心评估逻辑:
// 处理字符串表达式
if (isString(pageFunction)) {
const expressionWithSourceUrl = `${expression}\n${sourceUrlComment}\n`;
const {exceptionDetails, result: remoteObject} = await client.send(
'Runtime.evaluate', {
expression: expressionWithSourceUrl,
contextId,
returnByValue,
awaitPromise: true,
userGesture: true,
}
);
}
资料来源:packages/puppeteer-core/src/cdp/ExecutionContext.ts:45-75
LazyArg延迟参数机制
LazyArg是Puppeteer用于在页面上下文中延迟解析参数的机制:
class LazyArg<T, Context = PuppeteerUtilWrapper> {
static create = <T>(
get: (context: PuppeteerUtilWrapper) => Promise<T> | T
): T => {
return new LazyArg(get) as unknown as T;
};
async get(context: Context): Promise<T> {
return await this.#get(context);
}
}
这个机制确保了传递给页面函数的参数在被实际使用时才进行求值,避免了闭包捕获问题。
资料来源:packages/puppeteer-core/src/common/LazyArg.ts:20-35
设备模拟系统
KnownDevices预定义设备
Puppeteer内置了丰富的设备模拟配置,通过KnownDevices对象提供:
export const KnownDevices = Object.freeze(knownDevicesByName);
支持的设备包括各种iPhone、Android设备和桌面浏览器的预设配置,涵盖视口尺寸、用户代理字符串和触摸能力等属性。
资料来源:packages/puppeteer-core/src/common/Device.ts:180-190
设备模拟使用流程
graph LR
A[获取设备配置] --> B[创建Browser]
B --> C[创建Page]
C --> D[page.emulate]
D --> E[导航到目标URL]启动选项与浏览器管理
LaunchOptions启动配置
LaunchOptions接口定义了浏览器启动时的各项参数:
| 选项 | 类型 | 默认值 | 描述 | |
|---|---|---|---|---|
executablePath | string | - | 使用指定的浏览器可执行文件 | |
ignoreDefaultArgs | `boolean \ | string[]` | false | 忽略默认启动参数 |
enableExtensions | `boolean \ | string[]` | - | 启用浏览器扩展 |
handleSIGINT | boolean | true | Ctrl+C关闭浏览器 | |
handleSIGTERM | boolean | true | SIGTERM关闭浏览器 | |
handleSIGHUP | boolean | true | SIGHUP关闭浏览器 | |
timeout | number | 30000 | 启动超时(ms) |
资料来源:packages/puppeteer-core/src/node/LaunchOptions.ts:25-60
信号处理机制
Puppeteer实现了健壮的进程信号处理:
graph TD
SIGINT --> handleSIGINT --> browser.close
SIGTERM --> handleSIGTERM --> browser.close
SIGHUP --> handleSIGHUP --> browser.close调试系统
Debug模块架构
Puppeteer提供了灵活的调试日志系统,支持Node.js和浏览器环境:
export const debug = (prefix: string): ((...args: unknown[]) => void) => {
if (isNode) {
return async (...logArgs: unknown[]) => {
if (captureLogs) {
capturedLogs.push(prefix + logArgs);
}
(await importDebug())(prefix)(logArgs);
};
}
return (...logArgs: unknown[]): void => {
// 浏览器环境使用console.log
console.log(`${prefix}:`, ...logArgs);
};
};
调试通道配置
通过window.__PUPPETEER_DEBUG环境变量控制调试输出:
| 值 | 行为 |
|---|---|
'*' | 记录所有通道 |
'Page' | 仅记录Page通道 |
'Page*' | 记录所有以Page开头的通道 |
资料来源:packages/puppeteer-core/src/common/Debug.ts:30-60
事件系统
PageEvent事件类型
Page类继承自EventEmitter,使用标准的事件发布-订阅模式:
// 订阅事件
page.on('request', logRequest);
// 取消订阅
page.off('request', logRequest);
// 单次事件监听
page.once('load', () => console.log('Page loaded!'));
常见的页面事件包括:load、domcontentloaded、request、response、console等。
资料来源:packages/puppeteer-core/src/api/Page.ts:1-50
查询选择器系统
Puppeteer支持多种选择器类型,实现灵活的元素定位:
| 选择器类型 | 语法示例 | 描述 |
|---|---|---|
| CSS选择器 | page.$('div.class') | 标准CSS选择器 |
| ARIA选择器 | ::-p-aria(Search) | 无障碍角色和名称 |
| 文本选择器 | ::-p-text(Submit) | 按文本内容匹配 |
| XPath选择器 | ::-p-xpath(//button) | XPath表达式 |
| Pierce选择器 | ::p-deep(div) | 穿透Shadow DOM |
资料来源:packages/ng-schematics/README.md:40-60
典型工作流程
graph TD
A[启动浏览器] --> B[创建新页面]
B --> C[设置视口和用户代理]
C --> D[导航到URL]
D --> E[执行自动化操作]
E --> F{是否需要交互}
F -->|是| G[执行交互操作]
G --> H[等待条件满足]
H --> E
F -->|否| I[提取数据]
I --> J[关闭浏览器]安全考虑
沙箱模式
Docker运行Puppeteer时需要特殊权限:
docker run -i --init --rm --cap-add=SYS_ADMIN \
--name puppeteer-chrome puppeteer-chrome-linux \
node -e "..."
--cap-add=SYS_ADMIN用于启用Chrome沙箱安全机制,或使用--no-sandbox标志禁用沙箱。
总结
Puppeteer的系统架构体现了以下设计原则:
- 抽象与实现分离:通过抽象基类支持CDP和WebDriver等多种协议实现
- 模块化设计:核心功能与特定运行时环境解耦
- 灵活的配置系统:支持代码配置和环境变量覆盖
- 事件驱动架构:基于EventEmitter的统一事件系统
- 跨平台支持:同时支持Node.js和浏览器环境的调试能力
这种架构使得Puppeteer能够适应各种复杂的浏览器自动化场景,同时保持代码的可维护性和可扩展性。
资料来源:[packages/puppeteer-core/src/api/Page.ts:310-320]()
协议实现:CDP与WebDriver BiDi
Puppeteer 同时支持两种浏览器自动化协议:CDP(Chrome DevTools Protocol) 和 WebDriver BiDi(WebDriver Bi-Directional)。这种双协议支持使 Puppeteer 能够提供跨浏览器兼容性和向后兼容性。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Puppeteer 同时支持两种浏览器自动化协议:CDP(Chrome DevTools Protocol) 和 WebDriver BiDi(WebDriver Bi-Directional)。这种双协议支持使 Puppeteer 能够提供跨浏览器兼容性和向后兼容性。
| 协议 | 类型 | 支持浏览器 | 用途 |
|---|---|---|---|
| CDP | Chrome 专有 | Chrome、Chromium | 提供最完整的 Chrome 控制能力 |
| WebDriver BiDi | W3C 标准 | Chrome、Firefox、Edge | 跨浏览器兼容性 |
资料来源:packages/puppeteer-core/src/node/PuppeteerNode.ts
架构设计
双协议架构
Puppeteer 的协议实现采用分层架构,抽象层将底层协议细节与高级 API 解耦:
graph TB
subgraph "高级API层"
P[Page]
B[Browser]
T[Target]
end
subgraph "协议抽象层"
CDPA[CDP Browser]
BiDiA[BiDi Browser]
end
subgraph "连接层"
CDPC[CDP Connection]
BiDiC[BiDi Connection]
end
P --> CDPA
P --> BiDiA
B --> CDPA
B --> BiDiA
T --> CDPA
T --> BiDiA
CDPA --> CDPC
BiDiA --> BiDiCCDP over BiDi 混合模式
当使用 CDP 连接时,Puppeteer 可以选择性地将 BiDi 协议叠加在 CDP 连接之上:
const bidiOnly = process.env['PUPPETEER_WEBDRIVER_BIDI_ONLY'] === 'true';
const BiDi = await import('../bidi/bidi.js');
const bidiConnection = await BiDi.connectBidiOverCdp(cdpConnection);
资料来源:packages/puppeteer-core/src/node/BrowserLauncher.ts:45-48
CDP 实现
CDP Browser
CDP Browser 类负责管理基于 Chrome DevTools Protocol 的浏览器实例。CDP 协议提供对 Chrome 内部功能的深度控制,包括:
- 完整的 JavaScript 执行环境
- 网络请求拦截和修改
- 性能分析
- 页面截图和 PDF 生成
- DOM 操作
CDP Connection
CDP Connection 实现了基于 WebSocket 的 CDP 通信机制:
| 组件 | 职责 |
|---|---|
| WebSocket 传输 | 底层双向通信 |
| 命令分发 | 将 API 调用转换为 CDP 命令 |
| 事件监听 | 转发浏览器事件到上层 |
| 会话管理 | 管理多个 CDP 会话 |
CDP 连接支持通过 puppeteer.connect() 方法进行远程连接,实现浏览器控制与浏览器进程的分离。
WebDriver BiDi 实现
BiDi 协议核心
WebDriver BiDi 是 W3C 标准化的一种双向协议,设计目标是提供跨浏览器统一的自动化接口。Puppeteer 的 BiDi 实现位于 packages/puppeteer-core/src/bidi/core/ 目录。
#### 设计原则
BiDi 核心实现遵循以下原则:
- 遵循规范:
bidi/core严格遵循 WebDriver BiDi 规范,而非 Puppeteer 特定需求 - 全面性:按图结构实现所有节点和边,不跳过任何中间步骤
- 最小化:仅实现协议必需的功能,避免过度设计
资料来源:packages/puppeteer-core/src/bidi/core/README.md
BiDi Browser
BiDi Browser 类提供基于 WebDriver BiDi 协议的浏览器控制:
return await BiDi.BidiBrowser.create({
connection: bidiConnection,
// 当启用 BiDi-only 模式时不传递 CDP 连接
cdpConnection: bidiOnly ? undefined : cdpConnection,
closeCallback,
process: browserProcess.nodeProcess,
defaultViewport: opts.defaultViewport,
acceptInsecureCerts: opts.acceptInsecureCerts,
networkEnabled: opts.networkEnabled,
issuesEnabled: opts.issuesEnabled,
});
资料来源:packages/puppeteer-core/src/node/BrowserLauncher.ts:50-60
BiDi Connection
BiDi Connection 负责 WebSocket 双向通信,处理 BiDi 协议的握手和消息传递。
BiDi Core 模块
bidi/core 模块是 WebDriver BiDi 协议的纯规范实现:
| 模块 | 功能 |
|---|---|
| core.ts | 协议核心逻辑、命令处理、事件分发 |
| EventEmitter | 双向事件传输 |
| Browsing Context | 浏览器上下文管理 |
| Script | JavaScript 执行域 |
#### 事件图结构
BiDi 协议中的事件遵循严格的图结构。例如,导航事件必须按以下顺序触发:
fragment navigation → navigation → browsing context
不允许跳过中间节点,也不允许存在组合边(如同时存在上述路径和 fragment navigation → browsing context)。
资料来源:packages/puppeteer-core/src/bidi/core/README.md
协议选择与配置
环境变量控制
| 环境变量 | 作用 | 值 |
|---|---|---|
PUPPETEER_WEBDRIVER_BIDI_ONLY | 启用纯 BiDi 模式 | true 或 false |
当 PUPPETEER_WEBDRIVER_BIDI_ONLY=true 时,Browser 对象不会持有 CDP 连接引用,强制使用 BiDi 端点:
cdpConnection: bidiOnly ? undefined : cdpConnection,
资料来源:packages/puppeteer-core/src/node/BrowserLauncher.ts:55
启动配置
通过 LaunchOptions 可自定义浏览器启动行为:
| 选项 | 说明 | 默认值 |
|---|---|---|
| executablePath | 浏览器可执行文件路径 | 自动检测 |
| ignoreDefaultArgs | 跳过默认参数 | false |
| enableExtensions | 启用扩展支持 | false |
| timeout | 启动超时(ms) | 30000 |
| protocolTimeout | 协议超时(ms) | undefined |
资料来源:packages/puppeteer-core/src/node/LaunchOptions.ts
Target 抽象
Puppeteer 通过 Target 抽象统一管理不同类型的浏览器目标:
graph TD
T[Target 抽象]
CDPT[CDP Target]
BiDiT[BiDi Target]
CDPT --> CDPT_Browser[CDP Browser Target]
CDPT --> CDPT_Page[CDP Page Target]
BiDiT --> BiDiT_Browser[BiDi Browser Target]
BiDiT --> BiDiT_Page[BiDi Page Target]
T --> CDPT
T --> BiDiTBiDi Target 实现
BiDi Target 类体系包括:
| 类 | 类型 | 说明 |
|---|---|---|
| BidiBrowserTarget | TargetType.BROWSER | 浏览器级别目标 |
| BidiPageTarget | TargetType.PAGE | 页面级别目标 |
| BidiFrameTarget | TargetType.FRAME | 帧级别目标 |
| BidiWorkerTarget | TargetType.WORKER | Web Worker 目标 |
export class BidiBrowserTarget extends Target {
override type(): TargetType {
return TargetType.BROWSER;
}
override browser(): BidiBrowser {
return this.#browser;
}
}
资料来源:packages/puppeteer-core/src/bidi/Target.ts
协议特性对比
| 特性 | CDP | WebDriver BiDi |
|---|---|---|
| 标准化程度 | Chrome 专有 | W3C 标准 |
| 浏览器支持 | 仅 Chrome | Chrome、Firefox、Edge |
| API 完整性 | 完整 | 部分功能 |
| 跨浏览器兼容 | ✗ | ✓ |
| 网络拦截 | 完整支持 | 基础支持 |
| 性能分析 | 深度支持 | 有限支持 |
| JavaScript 执行 | 完整上下文 | 受限沙箱 |
使用场景建议
选择 CDP 的场景
- 需要完整的 Chrome 特性支持
- 进行性能分析和调试
- 需要精细的网络请求控制
- 仅针对 Chrome/Chromium 环境
选择 WebDriver BiDi 的场景
- 需要跨浏览器兼容性
- 遵循标准化协议要求
- 与 Selenium 等工具集成
- 测试环境包含多种浏览器
扩展机制
协议扩展
Puppeteer 支持通过自定义 Provider 扩展浏览器下载和安装机制:
import {install} from '@puppeteer/browsers';
await install({
browser: Browser.CHROMEDRIVER,
cacheDir: './cache',
providers: [new CustomProvider()],
});
资料来源:packages/browsers/src/install.ts
总结
Puppeteer 的双协议架构提供了灵活性和兼容性的平衡:
- CDP 协议 提供最深度的 Chrome 控制能力,适合需要高级功能的项目
- WebDriver BiDi 提供跨浏览器标准化接口,适合需要多浏览器支持的项目
- 混合模式 允许在 CDP 连接上叠加 BiDi 协议,兼顾功能完整性和标准化
- 严格规范遵循 确保 BiDi 实现的可移植性和正确性
资料来源:[packages/puppeteer-core/src/node/PuppeteerNode.ts](packages/puppeteer-core/src/node/PuppeteerNode.ts)
浏览器启动与管理
Puppeteer 的浏览器启动与管理模块是整个项目的核心组件之一,负责协调浏览器的生命周期、进程管理和资源分配。该模块通过抽象统一的 API,支持 Chrome、Firefox 等多种浏览器的启动、配置和销毁操作,同时提供细粒度的信号控制、超时管理和多上下文隔离机制。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Puppeteer 的浏览器启动与管理模块是整个项目的核心组件之一,负责协调浏览器的生命周期、进程管理和资源分配。该模块通过抽象统一的 API,支持 Chrome、Firefox 等多种浏览器的启动、配置和销毁操作,同时提供细粒度的信号控制、超时管理和多上下文隔离机制。
浏览器启动系统的设计遵循以下核心原则:
- 跨平台兼容性:统一处理不同操作系统(Linux、macOS、Windows)上的浏览器启动差异
- 进程生命周期管理:通过信号处理机制确保浏览器进程能够被正确终止
- 可扩展性:支持自定义可执行路径、浏览器参数和实验性功能配置
- 资源隔离:通过 BrowserContext 实现多浏览器上下文隔离
资料来源:packages/puppeteer-core/src/node/BrowserLauncher.ts:1-50
架构设计
核心组件关系
Puppeteer 的浏览器启动架构采用分层设计,各层职责分明:
graph TD
A[用户调用 puppeteer.launch] --> B[BrowserLauncher 抽象基类]
B --> C[ChromeLauncher]
B --> D[FirefoxLauncher]
C --> E[Chrome/Chromium 进程]
D --> F[Firefox 进程]
G[Configuration 配置] --> B
H[LaunchOptions 启动选项] --> B| 层级 | 组件 | 职责 |
|---|---|---|
| 接口层 | BrowserLauncher | 定义浏览器启动的统一接口和流程 |
| 实现层 | ChromeLauncher | 处理 Chrome/Chromium 特定启动逻辑 |
| 实现层 | FirefoxLauncher | 处理 Firefox 特定启动逻辑 |
| 配置层 | Configuration | 全局默认配置和浏览器特定设置 |
| 选项层 | LaunchOptions | 用户指定的运行时启动参数 |
资料来源:packages/puppeteer-core/src/node/BrowserLauncher.ts
启动流程时序
浏览器启动涉及多个阶段的协调操作:
sequenceDiagram
participant U as 用户代码
participant P as Puppeteer
participant L as BrowserLauncher
participant B as 浏览器进程
participant C as CDP/WebDriver
U->>P: puppeteer.launch(options)
P->>L: 创建 Launcher 实例
L->>L: 解析配置和选项
L->>B: 启动浏览器进程
B-->>L: 进程已启动
L->>C: 建立连接
C-->>L: 连接就绪
L-->>P: 返回 Browser 实例
P-->>U: 返回 Browser 实例资料来源:packages/browsers/src/launch.ts:1-100
支持的浏览器类型
浏览器枚举
Puppeteer 通过 SupportedBrowser 枚举定义支持的浏览器类型:
| 枚举值 | 浏览器 | 说明 |
|---|---|---|
chrome | Chrome for Testing | 默认浏览器,Puppeteer 主要支持的浏览器 |
chrome-headless-shell | Chrome Headless Shell | 无头 Chrome 精简版,体积更小 |
firefox | Firefox | Mozilla Firefox 浏览器 |
配置接口中指定默认浏览器为 chrome:
Defines the default browser to use.
@defaultValue chrome
资料来源:packages/puppeteer-core/src/common/Configuration.ts:1-50
浏览器特定配置
每种浏览器都有独立的配置命名空间:
interface Configuration {
chrome?: ChromeSettings;
['chrome-headless-shell']?: ChromeHeadlessShellSettings;
firefox?: FirefoxSettings;
}
Chrome 设置参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
skipDownload | boolean | false | 跳过浏览器下载 |
downloadBaseUrl | string | https://storage.googleapis.com/chrome-for-testing-public | 下载基础 URL |
executablePath | string | 自动推断 | 自定义可执行文件路径 |
Firefox 设置参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
skipDownload | boolean | true | 跳过浏览器下载 |
downloadBaseUrl | string | https://archive.mozilla.org/pub/firefox/releases | 下载基础 URL |
version | string | Puppeteer 固定的版本 | 指定 Firefox 版本 |
资料来源:packages/puppeteer-core/src/common/Configuration.ts:50-150
启动选项详解
LaunchOptions 接口定义了启动浏览器时可配置的所有参数:
基础配置参数
| 参数 | 类型 | 默认值 | 说明 | |
|---|---|---|---|---|
executablePath | string | 捆绑浏览器 | 指定自定义浏览器可执行文件路径 | |
ignoreDefaultArgs | `boolean \ | string[]` | false | 是否忽略默认参数或排除指定参数 |
enableExtensions | `boolean \ | string[]` | false | 启用扩展支持 |
If true, avoids passing default arguments to the browser that would prevent extensions from being enabled. Passing a list of strings will load the provided paths as unpacked extensions.
资料来源:packages/puppeteer-core/src/node/LaunchOptions.ts:1-60
进程信号控制
Puppeteer 提供了完善的进程信号处理机制,确保在不同终止场景下浏览器进程能被正确关闭:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
handleSIGINT | boolean | true | 接收到 Ctrl+C 时关闭浏览器 |
handleSIGTERM | boolean | true | 接收到 SIGTERM 信号时关闭浏览器 |
handleSIGHUP | boolean | true | 接收到 SIGHUP 信号时关闭浏览器 |
超时配置
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
timeout | number | 30_000 (30秒) | 浏览器启动超时时间(毫秒),设为 0 禁用超时 |
Maximum time in milliseconds to wait for the browser to start. Pass 0 to disable the timeout.
资料来源:packages/puppeteer-core/src/node/LaunchOptions.ts:60-100
其他启动参数
| 参数 | 类型 | 说明 |
|---|---|---|
pipe | boolean | 使用管道而非 WebSocket 连接 |
dumpio | boolean | 将浏览器 stdout/stderr 导出到进程 |
userDataDir | string | 用户数据目录(-profile 路径) |
env | Record<string, string> | 浏览器进程环境变量 |
Browser 类 API
Browser 类是浏览器实例的抽象表示,封装了所有浏览器操作:
核心方法
| 方法 | 返回值 | 说明 | |
|---|---|---|---|
newPage() | Promise<Page> | 创建新页面 | |
pages() | Promise<Page[]> | 获取所有打开的页面 | |
createIncognitoBrowserContext() | Promise<BrowserContext> | 创建私有浏览器上下文 | |
browserContexts() | BrowserContext[] | 获取所有浏览器上下文 | |
version() | Promise<string> | 获取浏览器版本 | |
process() | `ChildProcess \ | null` | 获取浏览器进程对象 |
close() | Promise<void> | 关闭浏览器 |
资料来源:packages/puppeteer-core/src/api/Browser.ts:1-100
浏览器进程管理
通过 process() 方法可以访问底层的 Node.js 子进程:
const browser = await puppeteer.launch();
const proc = browser.process();
if (proc) {
console.log(`Browser PID: ${proc.pid}`);
proc.kill(); // 强制终止
}
版本检测
const browser = await puppeteer.launch();
const version = await browser.version();
console.log(`Browser version: ${version}`);
BrowserContext 浏览器上下文
BrowserContext 提供了浏览器实例的隔离机制,类似于浏览器中的"无痕模式":
特性说明
- 每个 BrowserContext 拥有独立的 cookie 存储
- 每个 BrowserContext 拥有独立的会话存储
- 不同 BrowserContext 之间的页面完全隔离
- 共享进程但通过不同 CDP 会话隔离
graph LR
A[Browser] --> B[BrowserContext A]
A --> C[BrowserContext B]
A --> D[BrowserContext C]
B --> E[Page 1]
B --> F[Page 2]
C --> G[Page 3]
D --> H[Page 4]
style B fill:#e1f5fe
style C fill:#e1f5fe
style D fill:#e1f5fe上下文 API
| 方法 | 说明 |
|---|---|
createPage() | 在当前上下文中创建新页面 |
pages() | 获取当前上下文中的所有页面 |
close() | 关闭浏览器上下文 |
overridePermissions() | 覆盖指定源的权限 |
clearPermissionOverrides() | 清除所有权限覆盖 |
资料来源:packages/puppeteer-core/src/api/BrowserContext.ts:1-80
使用示例
// 创建两个隔离的浏览器上下文
const context1 = await browser.createIncognitoBrowserContext();
const context2 = await browser.createIncognitoBrowserContext();
const page1 = await context1.newPage();
const page2 = await context2.newPage();
// 两个页面的 cookie 完全隔离
await page1.goto('https://example.com');
await page2.goto('https://example.com');
// 关闭上下文时释放资源
await context1.close();
生命周期管理
启动阶段
flowchart TD
A[调用 launch] --> B{是否指定 executablePath}
B -->|是| C[验证可执行文件存在]
B -->|否| D[从缓存目录查找]
C --> E{文件存在?}
D --> E
E -->|否| F[抛出错误]
E -->|是| G[应用默认参数]
G --> H[启动子进程]
H --> I[建立 CDP 连接]
I --> J[等待浏览器就绪]
J --> K[返回 Browser 实例]关闭阶段
| 关闭方式 | 触发条件 | 行为 |
|---|---|---|
| 正常关闭 | 调用 browser.close() | 优雅关闭所有页面和上下文 |
| SIGINT | Ctrl+C | 触发正常关闭流程 |
| SIGTERM | 系统终止信号 | 触发正常关闭流程 |
| SIGHUP | 终端挂起 | 触发正常关闭流程 |
| 强制终止 | process.exit() | 浏览器进程可能残留 |
错误处理
浏览器启动失败时,Puppeteer 会根据失败原因抛出详细的错误信息:
Could not find Firefox (rev. ${browserVersion}). This can occur if either
1. you did not perform an installation for Firefox before running the script (e.g. npx puppeteer browsers install firefox) or
2. your cache path is incorrectly configured
资料来源:packages/puppeteer-core/src/node/BrowserLauncher.ts:80-100
配置管理
环境变量覆盖
Puppeteer 支持通过环境变量覆盖配置:
| 环境变量 | 配置属性 | 说明 |
|---|---|---|
PUPPETEER_SKIP_DOWNLOAD | skipDownload | 跳过浏览器下载 |
PUPPETEER_TMP_DIR | temporaryDirectory | 临时文件目录 |
PUPPETEER_CACHE_DIR | cacheDirectory | 浏览器缓存目录 |
PUPPETEER_CHROME_SKIP_DOWNLOAD | chrome.skipDownload | 跳过 Chrome 下载 |
PUPPETEER_FIREFOX_SKIP_DOWNLOAD | firefox.skipDownload | 跳过 Firefox 下载 |
配置文件方式
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
// 启动选项
timeout: 60000,
headless: true,
// 浏览器特定配置
chrome: {
executablePath: '/custom/chrome/path',
args: ['--disable-dev-shm-usage']
}
});
实际使用示例
基础启动
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await browser.close();
自定义配置启动
const browser = await puppeteer.launch({
headless: false,
executablePath: '/path/to/chrome',
args: [
'--disable-gpu',
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage'
],
timeout: 60000,
handleSIGINT: true,
handleSIGTERM: true
});
多上下文隔离
const browser = await puppeteer.launch();
// 用户 A 的上下文
const contextA = await browser.createIncognitoBrowserContext();
const pageA = await contextA.newPage();
await pageA.goto('https://login.example.com');
await pageA.type('#username', 'user_a');
// 用户 B 的上下文
const contextB = await browser.createIncognitoBrowserContext();
const pageB = await contextB.newPage();
await pageB.goto('https://login.example.com');
await pageB.type('#username', 'user_b');
// 独立验证,不会互相干扰
await Promise.all([
pageA.click('#submit'),
pageB.click('#submit')
]);
await contextA.close();
await contextB.close();
await browser.close();
最佳实践
资源管理
- 始终关闭浏览器:使用
try...finally或await browser.close()确保资源释放 - 限制页面数量:避免创建过多页面导致资源耗尽
- 使用上下文隔离:需要隔离操作时使用
BrowserContext而非启动多个浏览器实例
稳定性建议
| 场景 | 推荐配置 |
|---|---|
| Docker/容器环境 | 添加 --no-sandbox、--disable-dev-shm-usage 参数 |
| CI/CD 环境 | 使用 headless: true 并设置合理的 timeout |
| 资源受限环境 | 使用 chrome-headless-shell 减少内存占用 |
| 需要扩展支持 | 设置 enableExtensions 为 true |
调试技巧
- 查看浏览器日志:
dumpio: true可捕获浏览器输出 - 使用自定义用户数据目录:便于检查浏览器状态
- 禁用默认参数调试:
ignoreDefaultArgs: true后手动添加所需参数
相关命令
浏览器管理 CLI
通过 @puppeteer/browsers 包管理已安装的浏览器:
# 列出已安装的浏览器
npx @puppeteer/browsers list
# 安装 Chrome Stable
npx @puppeteer/browsers install chrome@stable
# 安装指定版本 Chrome
npx @puppeteer/browsers install [email protected]
# 安装最新 ChromeDriver
npx @puppeteer/browsers install chromedriver@canary
# 清理所有已安装浏览器
npx @puppeteer/browsers clear
资料来源:packages/browsers/README.md:1-80
总结
Puppeteer 的浏览器启动与管理模块通过统一的抽象层,优雅地解决了跨浏览器、跨平台的启动管理问题。其核心设计包括:
- 统一接口:
BrowserLauncher抽象基类为不同浏览器提供一致的操作体验 - 灵活配置:通过
LaunchOptions和Configuration支持细粒度的参数控制 - 进程安全:完善的信号处理机制确保浏览器进程在各种场景下都能正确关闭
- 上下文隔离:
BrowserContext提供会话级隔离,适合多用户模拟场景 - 错误友好:详细的错误信息帮助开发者快速定位问题
掌握这些机制,能够帮助开发者构建更加稳定、可靠的浏览器自动化应用。
资料来源:[packages/puppeteer-core/src/node/BrowserLauncher.ts:1-50]()
Page页面操作API
Page页面操作API是Puppeteer的核心模块之一,提供了与浏览器页面进行交互的完整能力。该API封装了浏览器自动化所需的各种操作,包括页面导航、内容查询、元素交互、JavaScript执行、截图和PDF生成等功能。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Page页面操作API是Puppeteer的核心模块之一,提供了与浏览器页面进行交互的完整能力。该API封装了浏览器自动化所需的各种操作,包括页面导航、内容查询、元素交互、JavaScript执行、截图和PDF生成等功能。
Page类继承自Puppeteer的EventEmitter类,会发出各种在PageEvent枚举中定义的事件。Puppeteer支持两种底层协议实现:Chrome DevTools Protocol (CDP) 和 WebDriver BiDi (BiDi),它们都实现了统一的Page抽象接口。
资料来源:packages/puppeteer-core/src/api/Page.ts:100
架构设计
实现层次结构
graph TD
A[Page 抽象基类] --> B[CDPPage CDP协议实现]
A --> C[BiDiPage BiDi协议实现]
D[Frame 抽象基类] --> E[CDPFrame]
D --> F[BiDiFrame]
G[EventEmitter] --> A
H[JSHandle] --> I[ElementHandle]核心组件关系
| 组件 | 类型 | 职责 |
|---|---|---|
| Page | 抽象类 | 定义页面操作的统一接口 |
| CDPPage | 实现类 | 通过CDP协议与Chrome通信 |
| BiDiPage | 实现类 | 通过BiDi协议与浏览器通信 |
| Frame | 抽象类 | 管理页面帧结构 |
| JSHandle | 抽象类 | JavaScript对象句柄 |
| ElementHandle | 抽象类 | DOM元素句柄 |
资料来源:packages/puppeteer-core/src/api/Page.ts:97-120
页面生命周期
页面状态管理
stateDiagram-v2
[*] --> 创建中: browser.newPage()
创建中 --> 已加载: 页面初始化完成
已加载 --> 导航中: goto() / setContent()
导航中 --> 已加载: 导航完成
已加载 --> 关闭中: close()
关闭中 --> [*]: 资源清理完成
已加载 --> 已加载: 页面刷新/前进后退内部状态变量
Page类维护以下内部状态:
_isDragging = false; // 拖拽状态
_timeoutSettings = new TimeoutSettings(); // 超时配置
_tabId = ''; // 浏览器标签页ID
#requestHandlers = WeakMap; // 请求处理器映射
#inflight$ = ReplaySubject; // 进行中的请求流
资料来源:packages/puppeteer-core/src/api/Page.ts:105-115
页面导航操作
goto - 页面跳转
导航到指定URL并等待页面加载完成。
await page.goto('https://developer.chrome.com/');
参数说明:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | string | 是 | 目标页面URL |
| options | NavigationOptions | 否 | 导航选项配置 |
导航选项:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| timeout | number | 30s | 导航超时时间(毫秒) |
| waitUntil | WaitUntilOptions | load | 等待条件 |
| referer | string | - | 引荐来源URL |
waitUntil 支持的值:
| 值 | 说明 |
|---|---|
load | 等待 load 事件触发 |
domcontentloaded | 等待 DOMContentLoaded 事件 |
networkidle0 | 等待无网络连接(500ms内) |
networkidle2 | 等待最多2个网络连接 |
setContent - 设置页面内容
直接设置页面的HTML内容。
await page.setContent('<html><body><h1>Hello</h1></body></html>');
reload - 刷新页面
await page.reload();
await page.reload({ timeout: 60000 });
goBack / goForward - 历史导航
await page.goBack(); // 返回上一页
await page.goForward(); // 前进到下一页
元素查询与选择器
选择器类型
Puppeteer支持多种选择器类型,可以满足不同的查询需求:
graph LR
A[选择器查询] --> B[CSS选择器]
A --> C[ARIA选择器]
A --> D[文本选择器]
A --> E[XPath选择器]
A --> F[Pierce选择器]选择器类型对照表
| 类型 | 语法 | 示例 |
|---|---|---|
| CSS | 标准CSS选择器 | page.$('div.container') |
| ARIA | ::-p-aria(...) | page.locator('::-p-aria(Search)') |
| 文本 | ::-p-text(...) | page.locator('::-p-text(Click me)') |
| XPath | ::-p-xpath(...) | page.locator('::-p-xpath(//button)') |
| Pierce | ::-p-shadow(...) | 穿透Shadow DOM查询 |
资料来源:packages/ng-schematics/README.md
查询方法
#### 单元素查询
// CSS选择器
const button = await page.$('button.submit');
// ARIA选择器
const searchInput = await page.$('::-p-aria(Search field)');
// 文本选择器
const heading = await page.locator('::-p-text(Welcome)');
#### 多元素查询
const inputs = await page.$$('input[type="text"]');
const items = await page.locator('li.item');
#### 高级查询
// 跨Shadow DOM查询
const shadowElement = await page.locator('::-p-shadow(div.inner)');
// 组合选择器
const complex = await page.locator('div.container >> text=Submit');
$$eval - 批量元素操作
在所有匹配元素上执行JavaScript函数:
const allInputValues = await page.$$eval('input', elements =>
elements.map(e => e.textContent)
);
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| selector | string | CSS或其他类型选择器 |
| pageFunction | Function | 在页面上下文执行的函数 |
| args | any[] | 额外参数 |
资料来源:packages/puppeteer-core/src/api/Page.ts:220-240
JavaScript执行与函数注入
evaluate - 页面内执行JavaScript
const title = await page.evaluate(() => document.title);
const result = await page.evaluate(async () => {
const response = await fetch('/api/data');
return await response.json();
});
exposeFunction - 注入全局函数
将Node.js函数暴露到页面window对象,页面JavaScript可以直接调用:
import crypto from 'crypto';
await page.exposeFunction('md5', text =>
crypto.createHash('md5').update(text).digest('hex')
);
await page.evaluate(async () => {
const hash = await window.md5('PUPPETEER');
console.log(`md5: ${hash}`);
});
使用场景:
| 场景 | 说明 |
|---|---|
| 文件读取 | 在页面中读取服务器文件系统 |
| 数据库访问 | 从页面查询数据库 |
| API调用 | 使用Node.js HTTP客户端 |
| 加密操作 | 复杂加密在Node端执行 |
特性:
- 通过
exposeFunction注入的函数在页面导航后仍然有效 - 如果注入的函数返回Promise,会自动await
- 支持
Function或{default: Function}类型
资料来源:packages/puppeteer-core/src/api/Page.ts:155-185
ExecutionContext - 执行上下文
CDP实现的执行上下文提供了更底层的控制:
sequenceDiagram
participant P as Puppeteer
participant EC as ExecutionContext
participant B as Browser
P->>EC: evaluate(pageFunction)
EC->>B: Runtime.evaluate
B-->>EC: result/exceptionDetails
EC-->>P: HandleFor<T> 或值页面截图
基本截图
await page.screenshot({ path: 'screenshot.png' });
截图选项
| 选项 | 类型 | 说明 | ||
|---|---|---|---|---|
| type | 'png' \ | 'jpeg' \ | 'webp' | 图片格式 |
| quality | number | 图片质量(0-100) | ||
| fullPage | boolean | 是否截取完整页面 | ||
| clip | Clip | 截图区域 | ||
| omitBackground | boolean | 隐藏默认背景 | ||
| encoding | 'binary' \ | 'base64' | 返回格式 |
完整页面截图
await page.screenshot({
path: 'fullpage.png',
fullPage: true
});
区域截图
await page.screenshot({
path: 'header.png',
clip: {
x: 0,
y: 0,
width: 800,
height: 100
}
});
Buffer返回
const buffer = await page.screenshot({
type: 'png',
encoding: 'binary'
});
资料来源:docs/guides/screenshots.md
PDF生成
基本PDF生成
await page.pdf({ path: 'page.pdf' });
PDF选项
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| printBackground | boolean | false | 打印背景色和图片 |
| landscape | boolean | false | 横向打印 |
| format | PaperFormat | 'Letter' | 纸张格式 |
| width | string | - | 自定义宽度 |
| height | string | - | 自定义高度 |
| margin | Margin | - | 页边距 |
| scale | number | 1 | 缩放比例 |
| displayHeaderFooter | boolean | false | 显示页眉页脚 |
| headerTemplate | string | - | 页眉HTML模板 |
| footerTemplate | string | - | 页脚HTML模板 |
常用纸张格式
| 格式 | 尺寸 |
|---|---|
| Letter | 8.5in x 11in |
| Legal | 8.5in x 14in |
| Tabloid | 11in x 17in |
| A4 | 210mm x 297mm |
| A3 | 297mm x 420mm |
| A5 | 148mm x 210mm |
自定义尺寸示例
await page.pdf({
path: 'custom.pdf',
width: '210mm',
height: '297mm',
printBackground: true,
margin: {
top: '20mm',
bottom: '20mm',
left: '20mm',
right: '20mm'
}
});
资料来源:docs/guides/pdf-generation.md
页面事件系统
事件类型
Page类继承自EventEmitter,支持以下核心事件:
graph LR
A[Page Events] --> B[导航事件]
A --> C[请求事件]
A --> D[响应事件]
A --> E[对话框事件]
A --> F[帧事件]
B --> B1[load]
B --> B2[domcontentloaded]
B --> B3[navigation]
C --> C1[request]
C --> C2[requestfailed]
C --> C3[requestfinished]
D --> D1[response]
E --> E1[dialog]
F --> F1[frameattached]
F --> F2[framedetached]
F --> F3[framenavigated]常用事件监听
// 页面加载完成
page.once('load', () => console.log('Page loaded!'));
// 监听所有请求
page.on('request', request => {
console.log('Request:', request.url());
});
// 监听响应
page.on('response', response => {
console.log('Response:', response.url(), response.status());
});
// 处理对话框
page.on('dialog', async dialog => {
console.log('Dialog:', dialog.message());
await dialog.accept();
});
// 订阅与取消订阅
const handler = request => console.log(request.url());
page.on('request', handler);
page.off('request', handler);
导航相关事件
| 事件 | 说明 | 回调参数 |
|---|---|---|
| load | 页面完全加载 | - |
| domcontentloaded | DOM解析完成 | - |
| navigation | 导航开始 | - |
| framenavigated | 帧导航完成 | Frame |
请求相关事件
| 事件 | 说明 | 回调参数 |
|---|---|---|
| request | 发起请求 | HTTPRequest |
| requestfailed | 请求失败 | HTTPRequest |
| requestfinished | 请求完成 | HTTPRequest |
| response | 收到响应 | HTTPResponse |
帧(Frame)处理
Frame类结构
Frame类提供了页面帧管理的能力,包括主框架和iframe。
graph TD
Page --> Frame
Frame --> IFrame1[iframe]
Frame --> IFrame2[iframe]
IFrame1 --> NestedFrame[嵌套帧]帧查询方法
// 获取主框架
const mainFrame = page.mainFrame();
// 获取所有框架
const frames = page.frames();
// 根据name属性查找iframe
const iframe = page.frame('my-iframe');
// 通过URL查找框架
const authFrame = page.frame({ url: /\/auth/ });
Frame中的操作
Frame类实现了与Page类似的API,可以在帧上下文中执行操作:
// 在特定帧中执行JavaScript
const result = await frame.evaluate(() => document.title);
// 在特定帧中查找元素
const button = await frame.$('button.submit');
// 等待帧加载
await frame.waitForSelector('.content-loaded');
Frame与Page的关系
// Frame的parentFrame
const parent = frame.parentFrame(); // 返回父帧或null
// 帧的name属性
console.log(frame.name()); // iframe的name属性值
// 帧的URL
console.log(frame.url()); // 帧的当前URL
资料来源:packages/puppeteer-core/src/api/Frame.ts
Viewport与设备模拟
setViewport - 设置视口
await page.setViewport({ width: 1080, height: 1024 });
设备模拟
Puppeteer内置了常用设备的配置:
import { KnownDevices } from 'puppeteer';
const iPhone = KnownDevices['iPhone 15 Pro'];
await page.emulate(iPhone);
自定义设备配置
await page.emulate({
name: 'Custom Device',
userAgent: 'Mozilla/5.0...',
viewport: {
width: 375,
height: 812,
deviceScaleFactor: 3,
isMobile: true,
hasTouch: true,
isLandscape: false
}
});
资料来源:packages/puppeteer-core/src/common/Device.ts
超时配置
TimeoutSettings
Puppeteer使用TimeoutSettings类统一管理各种超时配置。
常用超时配置
// 设置默认导航超时
page.setDefaultNavigationTimeout(60000);
// 设置默认操作超时
page.setDefaultTimeout(30000);
// 设置单次操作超时
await page.waitForSelector('.element', { timeout: 5000 });
超时选项说明
| 选项 | 默认值 | 说明 |
|---|---|---|
| navigationTimeout | 30000ms | 页面导航超时 |
| defaultTimeout | 30000ms | 默认操作超时 |
| waitForTimeout | 30000ms | 等待元素超时 |
CDP与BiDi实现差异
架构对比
| 特性 | CDPPage | BiDiPage |
|---|---|---|
| 底层协议 | Chrome DevTools Protocol | WebDriver BiDi |
| 浏览器支持 | Chrome/Edge | 所有主流浏览器 |
| 功能完整性 | 完整 | 部分特性 |
| 性能 | 较高 | 相对较低 |
| 调试能力 | 强 | 一般 |
实现文件
两种实现都遵循packages/puppeteer-core/src/api/Page.ts中定义的抽象接口,确保API行为的一致性。
最佳实践
页面操作流程
graph TD
A[启动浏览器] --> B[创建页面]
B --> C[设置Viewport]
C --> D[导航到URL]
D --> E{等待条件}
E -->|元素存在| F[执行操作]
E -->|等待超时| G[处理错误]
F --> H[截图/PDF]
H --> I[关闭页面]
G --> I错误处理
try {
await page.goto('https://example.com', {
timeout: 30000,
waitUntil: 'networkidle0'
});
} catch (error) {
if (error.message.includes('net::ERR_')) {
console.error('Network error occurred');
} else if (error.message.includes('timeout')) {
console.error('Navigation timeout');
}
}
资源清理
// 使用完记得关闭页面
const page = await browser.newPage();
try {
// 操作...
} finally {
await page.close();
}
// 等待特定元素时使用waitForSelector的cleanup
const handle = await page.waitForSelector('.modal', {
timeout: 5000
}).catch(() => null);
if (handle) {
// 使用handle
await handle.dispose();
}
性能优化建议
- 避免频繁截图 - 截图操作较耗时,按需使用
- 合理设置超时 - 过长超时会增加等待时间
- 使用waitForSelector - 比固定延迟更高效
- 批量操作 - 减少页面交互次数
- 复用Page实例 - 避免频繁创建销毁页面
相关链接
资料来源:[packages/puppeteer-core/src/api/Page.ts:100]()
元素定位器与操作
元素定位器与操作是 Puppeteer 自动化框架中用于在网页中查找和交互 DOM 元素的核心模块。该系统提供了多种定位策略,包括 CSS 选择器、ARIA 角色定位、文本匹配、XPath 表达式以及穿透 Shadow DOM 的选择器,同时支持通过定位器 API 实现稳定的元素等待和交互操作。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
元素定位器与操作是 Puppeteer 自动化框架中用于在网页中查找和交互 DOM 元素的核心模块。该系统提供了多种定位策略,包括 CSS 选择器、ARIA 角色定位、文本匹配、XPath 表达式以及穿透 Shadow DOM 的选择器,同时支持通过定位器 API 实现稳定的元素等待和交互操作。
定位器(Locator)是对传统 page.$() 和 page.$$() 查询方式的现代化封装,提供了更好的错误处理、自动重试机制以及流畅的 API 设计。元素句柄(ElementHandle)则代表了页面中 DOM 元素的引用,通过它可以执行点击、填充、拖拽等交互操作。
架构设计
核心组件关系
graph TD
A[Page] --> B[Locator API]
A --> C[ElementHandle API]
B --> D[Query Handler]
C --> D
D --> E[CSS Selector Handler]
D --> F[ARIA Selector Handler]
D --> G[Text Selector Handler]
D --> H[XPath Selector Handler]
D --> I[Pierce Selector Handler]
D --> J[Custom Query Handler]定位器与元素句柄的职责划分
| 组件 | 职责 | 特点 |
|---|---|---|
| Locator | 描述如何定位元素,提供延迟解析和自动等待 | 每次调用都会重新查询,支持重试 |
| ElementHandle | 持有元素引用,执行具体操作 | 可能因导航而失效,需要管理生命周期 |
| QueryHandler | 实现具体的查询逻辑 | 插件化设计,支持自定义扩展 |
资料来源:packages/puppeteer-core/src/api/locators/locators.ts:1-50
选择器类型详解
支持的选择器类型
Puppeteer 支持多种选择器语法,可通过前缀或组合方式使用:
| 选择器类型 | 前缀 | 示例 | 说明 |
|---|---|---|---|
| CSS 选择器 | 无 | div.container | 标准 CSS 选择器 |
| ARIA 角色 | ::-p-aria | ::-p-aria([name="搜索"]) | 通过无障碍属性定位 |
| 文本匹配 | ::-p-text | ::-p-text(提交) | 通过元素文本内容定位 |
| XPath | ::-p-xpath | ::-p-xpath(//button) | XPath 表达式 |
| 穿透选择器 | pierce/ | pierce/>>> button | 穿透 Shadow DOM 边界 |
资料来源:packages/puppeteer-core/src/common/CustomQueryHandler.ts:1-30
ARIA 选择器实现
ARIA 选择器通过无障碍 API 查询页面元素,其核心实现在 ARIAQuerySelector.ts 中:
export class ARIAQueryHandler {
async queryOne(
root: Node,
selector: string
): Promise<ElementHandle<Node> | null> {
// 使用 ARIA 属性查询 DOM
}
}
该处理器利用浏览器原生 ARIA 查询能力,支持通过角色、名称、状态等属性定位元素。
资料来源:packages/puppeteer-core/src/injected/ARIAQuerySelector.ts:1-80
穿透选择器实现
穿透选择器(Pierce Selector)能够跨越 Shadow DOM 边界进行查询:
export class PierceQueryHandler {
async queryOne(
root: Node,
selector: string
): Promise<ElementHandle<Node> | null> {
// 递归遍历 shadowRoot 查找匹配元素
}
}
该选择器通过递归遍历文档树和所有 Shadow DOM 来查找匹配的元素,适用于复杂的 Web 组件场景。
资料来源:packages/puppeteer-core/src/injected/PierceQuerySelector.ts:1-60
定位器 API
定位器工作流程
sequenceDiagram
participant User as 用户
participant Locator as Locator
participant QueryHandler as QueryHandler
participant Browser as 浏览器
User->>Locator: 创建定位器
Locator->>User: 返回 Locator 实例
User->>Locator: waitHandle()
Locator->>QueryHandler: 执行查询
QueryHandler->>Browser: DOM 查询
Browser-->>QueryHandler: 返回元素引用
QueryHandler-->>Locator: ElementHandle
Locator-->>User: Promise<Handle>主要定位器方法
| 方法 | 返回类型 | 说明 |
|---|---|---|
locator(selector) | Locator | 创建新的定位器 |
waitHandle() | Promise<Handle> | 等待并返回元素句柄 |
first() | Locator | 获取匹配的第一个元素定位器 |
nth(index) | Locator | 获取指定索引的定位器 |
filter(options) | Locator | 按条件过滤定位结果 |
map(fn) | ... | 映射操作 |
wait(options?) | Promise | 等待元素出现 |
资料来源:packages/puppeteer-core/src/api/locators/locators.ts:50-150
使用示例
// 使用 locator API 进行稳定操作
const button = page.locator('button[type="submit"]');
await button.wait();
await button.click();
// 使用 ARIA 选择器
const searchInput = page.locator('::-p-aria([name="搜索框"])');
// 使用文本选择器
const submitBtn = page.locator('::-p-text(提交)');
// 穿透 Shadow DOM
const nestedButton = page.locator('pierce/>>> my-component >>> button');
元素句柄操作
元素句柄生命周期
graph LR
A[创建 ElementHandle] --> B{页面导航}
B -->|发生| C[句柄失效]
B -->|未发生| D[可继续使用]
C --> E[需重新查询]
D --> F[执行操作]
F --> G[释放资源]ElementHandle 核心方法
| 方法 | 说明 | 返回值 |
|---|---|---|
click(options?) | 点击元素 | Promise<void> |
fill(value) | 填充输入框 | Promise<void> |
tap() | 触发触摸事件 | Promise<void> |
hover() | 鼠标悬停 | Promise<void> |
scrollIntoViewIfNeeded() | 滚动到可视区域 | Promise<void> |
drag(...targets) | 执行拖拽操作 | Promise<void> |
uploadFile(...filePaths) | 上传文件 | Promise<void> |
资料来源:packages/puppeteer-core/src/api/ElementHandle.ts:50-200
CDP 实现细节
CDP(Chrome DevTools Protocol)实现提供了高性能的元素交互能力:
class ElementHandleImpl extends CDPJSHandle implements ElementHandle<Node> {
#client: CdpCDPClient;
async click(options?: ClickOptions): Promise<void> {
const { x, y } = await this.clickablePoint();
this.#client.input.dispatchMouseEvent({
type: 'mousePressed',
button: 'left',
x, y
});
}
}
资料来源:packages/puppeteer-core/src/cdp/ElementHandle.ts:100-180
自定义查询处理器
注册自定义选择器
通过 CustomQueryHandler 可以扩展 Puppeteer 的查询能力:
import { register } from 'puppeteer';
register('jQuery', {
queryOne: (root: Node, selector: string) => {
// 实现 jQuery 选择逻辑
return root.querySelector(selector);
},
queryAll: (root: Node, selector: string) => {
return root.querySelectorAll(selector);
}
});
自定义处理器结构
| 属性 | 类型 | 说明 | |
|---|---|---|---|
queryOne | `(root: Node, selector: string) => ElementHandle \ | null` | 返回第一个匹配元素 |
queryAll | (root: Node, selector: string) => ElementHandle[] | 返回所有匹配元素 |
资料来源:packages/puppeteer-core/src/common/CustomQueryHandler.ts:30-80
等待与重试机制
定位器等待策略
graph TD
A[开始等待] --> B{超时?}
B -->|是| C[抛出 TimeoutError]
B -->|否| D{元素存在?}
D -->|否| E[重新查询]
E --> B
D -->|是| F{检查条件?}
F -->|否| G[等待后重新检查]
G --> B
F -->|是| H[返回元素句柄]等待选项
| 选项 | 类型 | 默认值 | 说明 | |||
|---|---|---|---|---|---|---|
timeout | number | 继承自 page | 等待超时时间(毫秒) | |||
state | 'attached' \ | 'detached' \ | 'visible' \ | 'hidden' | 'visible' | 元素状态条件 |
signal | AbortSignal | undefined | 中止信号 |
最佳实践
选择器性能优化
| 场景 | 推荐选择器 | 原因 |
|---|---|---|
| 唯一元素 | #id 或 data-testid | 最快,浏览器原生支持 |
| 语义化查询 | ::-p-aria | 可访问性好,不依赖样式 |
| 复杂层级 | pierce/ | 穿透 Shadow DOM |
| 避免 | :nth-of-type 深层嵌套 | 性能较差 |
稳定性建议
- 优先使用定位器 API:相比 ElementHandle,定位器提供自动重试和更好的错误信息
- 显式等待而非硬编码延迟:使用
wait()方法等待元素状态变化 - 使用语义化选择器:通过 ARIA 属性而非 CSS 类名定位元素
- 管理资源生命周期:使用
using声明自动释放 ElementHandle
// 推荐写法
await page.locator('button[type="submit"]').click();
// 避免硬编码延迟
// await new Promise(r => setTimeout(r, 2000));
相关文档
资料来源:[packages/puppeteer-core/src/api/locators/locators.ts:1-50](https://github.com/puppeteer/puppeteer/blob/main/packages/puppeteer-core/src/api/locators/locators.ts)
网络请求拦截与管理
Puppeteer 的网络请求拦截与管理功能允许开发者监控、修改、阻止或重定向网页发出的 HTTP 请求和响应。该功能是浏览器自动化测试和开发调试的核心能力之一,开发者可以借此实现广告屏蔽、请求日志记录、网络条件模拟、API 响应模拟等高级功能。
继续阅读本节完整说明和来源证据。
概述
Puppeteer 的网络请求拦截与管理功能允许开发者监控、修改、阻止或重定向网页发出的 HTTP 请求和响应。该功能是浏览器自动化测试和开发调试的核心能力之一,开发者可以借此实现广告屏蔽、请求日志记录、网络条件模拟、API 响应模拟等高级功能。
网络拦截机制基于事件驱动架构,通过 request、response、requestfailed、requestfinished 等事件向外暴露网络活动的完整生命周期。Puppeteer 支持两种协议实现:Chrome DevTools Protocol (CDP) 和 WebDriver BiDi,本质上都是通过底层协议拦截和处理网络请求。
资料来源:packages/puppeteer-core/src/api/Page.ts:setRequestInterception
资料来源:[packages/puppeteer-core/src/api/Page.ts:setRequestInterception](https://github.com/puppeteer/puppeteer/blob/main/packages/puppeteer-core/src/api/Page.ts)
浏览器上下文与扩展支持
Puppeteer 的浏览器上下文(Browser Context)与扩展支持功能为开发者提供了在同一浏览器实例中创建隔离环境的能力,并支持加载 Chrome 扩展程序。这些功能使得高级自动化场景(如多租户隔离、扩展辅助测试、隐私浏览模式等)成为可能。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Puppeteer 的浏览器上下文(Browser Context)与扩展支持功能为开发者提供了在同一浏览器实例中创建隔离环境的能力,并支持加载 Chrome 扩展程序。这些功能使得高级自动化场景(如多租户隔离、扩展辅助测试、隐私浏览模式等)成为可能。
核心概念
- 浏览器上下文(Browser Context):一个独立的浏览器会话环境,拥有独立的 Cookie 存储、缓存和本地存储。不同上下文之间的数据完全隔离。
- 扩展支持(Extension Support):Puppeteer 允许将未打包的扩展程序加载到浏览器实例中,以辅助自动化测试或实现自定义功能。
浏览器上下文架构
抽象层设计
Puppeteer 在 packages/puppeteer-core/src/api/ 目录下定义了 BrowserContext 的抽象接口。具体实现分别针对 CDP(Chrome DevTools Protocol)和 BiDi(WebDriver BiDi)协议提供了独立的实现类。
CDP 实现
在 CDP(Chrome DevTools Protocol)实现中,浏览器上下文通过创建独立的浏览器会话来实现隔离。CDP 协议原生支持上下文隔离,每个上下文拥有独立的 Target(目标),包括页面、服务工作者等。
BiDi 实现
在 BiDi(WebDriver BiDi)协议实现中,浏览器上下文作为独立的会话存在。BiDi 协议的上下文管理机制与 CDP 类似,但提供了标准化的跨浏览器支持。
扩展加载机制
启动配置
Puppeteer 通过 LaunchOptions 接口提供扩展支持配置。扩展可以在浏览器启动时加载:
interface LaunchOptions {
/**
* 如果为 true,则避免传递会阻止扩展启用的默认参数。
* 传递字符串数组将加载提供的路径作为未打包的扩展程序。
*/
enableExtensions?: boolean | string[];
}
资料来源:packages/puppeteer-core/src/node/LaunchOptions.ts:1-50
配置选项说明
| 参数 | 类型 | 默认值 | 说明 | |
|---|---|---|---|---|
enableExtensions | `boolean \ | string[]` | undefined | 启用扩展支持。布尔值启用所有默认扩展行为;字符串数组指定要加载的扩展路径 |
handleSIGINT | boolean | true | 在 Ctrl+C 时关闭浏览器进程 | |
handleSIGTERM | boolean | true | 在 SIGTERM 时关闭浏览器进程 | |
handleSIGHUP | boolean | true | 在 SIGHUP 时关闭浏览器进程 |
扩展上下文通信
exposeFunction 方法
exposeFunction 是 Page 类提供的核心方法,允许从浏览器页面调用 Node.js 环境中的函数。这对于扩展辅助测试和双向通信至关重要:
abstract exposeFunction(
name: string,
pptrFunction: Function | {default: Function},
): Promise<void>;
资料来源:packages/puppeteer-core/src/api/Page.ts:1-100
使用模式
#### 基本用法
import puppeteer from 'puppeteer';
import fs from 'node:fs';
const browser = await puppeteer.launch();
const page = await browser.newPage();
page.on('console', msg => console.log(msg.text()));
await page.exposeFunction('readfile', async filePath => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, text) => {
if (err) reject(err);
else resolve(text);
});
});
});
await page.evaluate(async () => {
const content = await window.readfile('/etc/hosts');
console.log(content);
});
await browser.close();
#### 与扩展配合使用
通过 exposeFunction,开发者可以创建桥接函数,使扩展程序能够与 Node.js 环境交互:
await page.exposeFunction('md5', async (myString: string) => {
const hash = await window.md5(myString);
console.log(`md5 of ${myString} is ${hash}`);
});
内部实现机制
在 CDP 实现中,exposeFunction 通过以下步骤工作:
- 在页面的执行上下文中注册一个全局函数
- 监听页面中对该函数的调用
- 将调用参数从浏览器环境传递到 Node.js 环境
- 执行提供的 Node.js 回调函数
- 将结果返回到浏览器环境
资料来源:packages/puppeteer-core/src/cdp/ExecutionContext.ts:1-80
evaluateOnNewDocument 功能
evaluateOnNewDocument 方法允许在每个新文档创建后、任何脚本运行前注入代码。这对于在页面加载前修改 JavaScript 环境非常有用:
abstract evaluateOnNewDocument<
Params extends unknown[],
Func extends (...args: Params) => unknown = (...args: Params) => unknown,
>(
pageFunction: Func | string,
...args: Params
): Promise<NewDocumentScriptEvaluation>;
应用场景
#### 覆盖 navigator.languages
// preload.js
Object.defineProperty(navigator, 'languages', {
get: function () {
return ['en-US', 'en', 'bn'];
},
});
// 在 Puppeteer 脚本中使用
const preloadFile = fs.readFileSync('./preload.js', 'utf8');
await page.evaluateOnNewDocument(preloadFile);
配置系统
全局配置接口
Puppeteer 提供了 Configuration 接口用于全局配置:
export interface Configuration {
defaultBrowser?: SupportedBrowser;
temporaryDirectory?: string;
skipDownload?: boolean;
logLevel?: 'silent' | 'error' | 'warn';
experiments?: ExperimentsConfiguration;
chrome?: ChromeSettings;
['chrome-headless-shell']?: ChromeHeadlessShellSettings;
firefox?: FirefoxSettings;
}
资料来源:packages/puppeteer-core/src/common/Configuration.ts:1-80
环境变量覆盖
| 环境变量 | 对应配置项 | 说明 |
|---|---|---|
PUPPETEER_TMP_DIR | temporaryDirectory | 临时文件目录 |
PUPPETEER_SKIP_DOWNLOAD | skipDownload | 跳过浏览器下载 |
PUPPETEER_LOG_LEVEL | logLevel | 日志级别 |
PUPPETEER_CHROME_SKIP_DOWNLOAD | chrome.skipDownload | 跳过 Chrome 下载 |
PUPPETEER_CHROME_DOWNLOAD_BASE_URL | chrome.downloadBaseUrl | Chrome 下载基础 URL |
调试支持
Puppeteer 提供了可配置的调试日志系统:
export const debug = (prefix: string): ((...args: unknown[]) => void) => {
if (isNode) {
return async (...logArgs: unknown[]) => {
if (captureLogs) {
capturedLogs.push(prefix + logArgs);
}
(await importDebug())(prefix)(logArgs);
};
}
// 浏览器环境实现...
};
资料来源:packages/puppeteer-core/src/common/Debug.ts:1-60
调试通道
| 通道前缀 | 说明 |
|---|---|
Page | 页面相关日志 |
BrowserContext | 浏览器上下文日志 |
Extension | 扩展相关日志 |
Target | 目标管理日志 |
使用方法
// 设置日志级别
window.__PUPPETEER_DEBUG='Page'; // 仅记录 Page 通道
window.__PUPPETEER_DEBUG='Page*'; // 记录所有 Page 开头的通道
window.__PUPPETEER_DEBUG='*'; // 记录所有通道
错误处理
执行上下文错误
Puppeteer 提供了专门的错误重写函数用于处理常见错误场景:
export function rewriteEvaluationError(error: unknown): never {
if (error instanceof Error) {
if (
error.message.includes('ExecutionContext was destroyed') ||
error.message.includes('Inspected target navigated or closed')
) {
throw new Error(
'Execution context was destroyed, most likely because of a navigation.',
);
}
}
throw error;
}
资料来源:packages/puppeteer-core/src/bidi/util.ts:1-80
导航超时处理
export function rewriteNavigationError(
message: string,
ms: number,
): (error: unknown) => never {
return error => {
if (error instanceof ProtocolError) {
error.message += ` at ${message}`;
} else if (error instanceof TimeoutError) {
error.message = `Navigation timeout of ${ms} ms exceeded`;
}
throw error;
};
}
完整使用示例
import puppeteer from 'puppeteer';
async function main() {
// 启用扩展支持
const browser = await puppeteer.launch({
enableExtensions: ['/path/to/unpacked/extension'],
handleSIGINT: true,
handleSIGTERM: true,
timeout: 30000,
});
// 创建隔离上下文
const context = browser.createBrowserContext();
const page = await context.newPage();
// 设置调试日志
page.on('console', msg => console.log('PAGE LOG:', msg.text()));
// 暴露 Node.js 函数到页面
await page.exposeFunction('getNodeVersion', () => process.version);
await page.exposeFunction('readConfig', async () => {
return {apiKey: 'xxx', endpoint: 'https://api.example.com'};
});
// 在文档创建前注入代码
await page.evaluateOnNewDocument(() => {
console.log('Document about to be created');
});
await page.goto('https://example.com');
await browser.close();
}
main().catch(console.error);
最佳实践
- 资源清理:使用完毕后调用
browser.close()或context.close()释放资源 - 超时配置:根据网络状况和目标网站性能合理设置超时时间
- 扩展路径:使用绝对路径确保扩展能够正确加载
- 错误处理:实现健壮的错误处理逻辑,特别是导航超时和执行上下文销毁场景
- 调试日志:在开发阶段启用调试日志便于排查问题
相关资源
资料来源:[packages/puppeteer-core/src/node/LaunchOptions.ts:1-50]()
覆盖率检测与调试功能
Puppeteer 提供了丰富的覆盖率检测与调试功能,使开发者能够在浏览器自动化过程中收集性能指标、追踪代码执行、分析控制台输出以及诊断运行时错误。这些功能对于优化网页性能、调试自动化脚本以及生成详细的测试报告至关重要。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Puppeteer 提供了丰富的覆盖率检测与调试功能,使开发者能够在浏览器自动化过程中收集性能指标、追踪代码执行、分析控制台输出以及诊断运行时错误。这些功能对于优化网页性能、调试自动化脚本以及生成详细的测试报告至关重要。
覆盖率检测功能主要通过 Chrome DevTools Protocol (CDP) 实现,支持 JavaScript 代码覆盖率统计、堆快照捕获以及性能指标采集。调试功能则涵盖控制台消息捕获、页面事件监听、调试日志输出以及详细的错误报告机制。
核心架构
模块关系
Puppeteer 的覆盖率检测与调试系统由多个核心模块组成,各模块协同工作以提供完整的诊断能力。
graph TD
A[Puppeteer 核心层] --> B[覆盖率模块]
A --> C[调试模块]
A --> D[追踪模块]
B --> E[CDP Coverage API]
C --> F[ConsoleMessage 处理]
C --> G[Errors 处理]
D --> H[CDP Tracing API]
E --> I[CoverageResult]
F --> J[控制台事件]
G --> K[错误类型定义]
H --> L[追踪数据]关键组件
| 组件名称 | 文件路径 | 职责说明 |
|---|---|---|
| Coverage | packages/puppeteer-core/src/cdp/Coverage.ts | 提供 JavaScript 和 CSS 覆盖率统计功能 |
| Tracing | packages/puppeteer-core/src/cdp/Tracing.ts | 管理性能追踪和事件流记录 |
| ConsoleMessage | packages/puppeteer-core/src/common/ConsoleMessage.ts | 处理和解析控制台消息 |
| Errors | packages/puppeteer-core/src/common/Errors.ts | 定义错误类型和错误处理机制 |
| Accessibility | packages/puppeteer-core/src/cdp/Accessibility.ts | 提供无障碍访问相关诊断 |
覆盖率检测功能
JavaScript 代码覆盖率
Puppeteer 支持获取页面的性能指标数据,这些数据包括文档数量、帧数、JavaScript 事件监听器数量、DOM 节点数量以及布局和样式重算的统计信息。
性能指标数据结构定义如下:
| 属性名 | 类型 | 说明 |
|---|---|---|
| Timestamp | number | 指标采样的时间戳(单调递增) |
| Documents | number | 页面中的文档数量 |
| Frames | number | 页面中的帧数量 |
| JSEventListeners | number | 页面中的 JavaScript 事件监听器数量 |
| Nodes | number | DOM 节点总数 |
| LayoutCount | number | 完整或部分页面布局的总次数 |
| RecalcStyleCount | number | 页面样式重算的总次数 |
| LayoutDuration | number | 所有页面布局的累计时长 |
| RecalcStyleDuration | number | 所有样式重算的累计时长 |
| ScriptDuration | number | JavaScript 执行的总时长 |
| TaskDuration | number | 浏览器执行的所有任务累计时长 |
| JSHeapUsedSize | number | 已使用的 JavaScript 堆大小 |
| JSHeapTotalSize | number | JavaScript 堆总大小 |
资料来源:packages/puppeteer-core/src/api/Page.ts:250-290
堆快照捕获
Puppeteer 提供了 captureHeapSnapshot() 方法用于捕获 JavaScript 堆的快照并写入文件。这对于内存泄漏排查和堆内存分析非常有价值。该方法为抽象方法,需要在具体的 Page 实现中由 CDP 或其他浏览器协议实现。
// 捕获堆快照的典型用法
const browser = await puppeteer.launch();
const page = await browser.newPage();
// 执行页面操作后捕获堆快照
await page.captureHeapSnapshot({ path: 'heap-snapshot.json' });
await browser.close();
CSS 覆盖率
通过 CDP 的 Coverage API,Puppeteer 能够追踪 CSS 规则的使用情况,帮助开发者识别页面中未使用的 CSS 样式。
调试功能
调试日志系统
Puppeteer 实现了灵活的调试日志系统,支持通过环境变量 window.__PUPPETEER_DEBUG 配置日志输出级别和通道。
// 输出所有调试日志
window.__PUPPETEER_DEBUG = '*';
// 输出特定通道的日志
window.__PUPPETEER_DEBUG = 'Page';
// 输出以指定前缀开头的所有通道
window.__PUPPETEER_DEBUG = 'Page*';
调试日志函数接受一个前缀参数,该前缀会被添加到每条日志消息的开头,便于区分不同模块的输出:
const log = debug('Page');
log('new page created');
// 输出: "Page: new page created"
资料来源:packages/puppeteer-core/src/common/Debug.ts:30-60
日志输出流程
graph LR
A[日志调用] --> B{运行环境检测}
B -->|Node.js| C[debug 模块]
B -->|浏览器| D[环境变量检查]
D --> E{匹配检查}
E -->|完全匹配| F[console.log 输出]
E -->|通配符匹配| F
E -->|不匹配| G[无输出]
C --> H[异步日志输出]控制台消息处理
ConsoleMessage 模块负责解析和传递来自页面的控制台消息。该模块支持多种消息类型,包括日志、警告、错误、信息和调试消息。
| 消息类型 | 说明 | 典型用途 |
|---|---|---|
| log | 日志消息 | 一般性信息输出 |
| warn | 警告消息 | 潜在问题的提示 |
| error | 错误消息 | 运行时错误的报告 |
| info | 信息消息 | 提示性信息 |
| debug | 调试消息 | 开发调试信息 |
监听控制台消息的标准模式:
const browser = await puppeteer.launch();
const page = await browser.newPage();
page.on('console', msg => {
console.log(`[${msg.type()}] ${msg.text()}`);
});
await page.goto('https://example.com');
await browser.close();
资料来源:packages/puppeteer-core/src/common/ConsoleMessage.ts
错误处理机制
Puppeteer 定义了完整的错误类型体系,确保各种运行时异常能够被正确识别和处理。
| 错误类型 | 错误码 | 说明 |
|---|---|---|
| UnsupportedOperationError | 错误码定义在 Errors.ts | 不支持的操作错误 |
| EvaluationError | 错误码定义在 Errors.ts | JavaScript 评估错误 |
| TimeoutError | 错误码定义在 Errors.ts | 操作超时错误 |
| ProtocolError | 错误码定义在 Errors.ts | CDP 协议通信错误 |
评估上下文中发生的异常会被捕获并转换为结构化的错误对象:
const {exceptionDetails, result: remoteObject} = await this.#client
.send('Runtime.evaluate', {
expression: expressionWithSourceUrl,
contextId,
returnByValue,
awaitPromise: true,
userGesture: true,
})
.catch(rewriteError);
if (exceptionDetails) {
throw createEvaluationError(exceptionDetails);
}
资料来源:packages/puppeteer-core/src/cdp/ExecutionContext.ts:40-70
性能追踪功能
Tracing 模块概述
Tracing 模块提供了强大的性能追踪能力,能够记录页面的各种事件流并生成详细的追踪报告。这对于分析页面加载性能、识别性能瓶颈以及生成 Chrome DevTools 兼容的追踪文件非常有用。
追踪数据流
graph TD
A[追踪开始] --> B[CDP Tracing.start]
B --> C[事件收集阶段]
C --> D[Page 事件]
C --> E[Network 事件]
C --> F[JavaScript 事件]
D --> G[缓冲区写入]
E --> G
F --> G
G --> H[CDP Tracing.end]
H --> I[追踪数据处理]
I --> J[结果输出]无障碍功能诊断
Accessibility 模块提供了页面无障碍访问相关的诊断能力,帮助开发者检查页面元素的可访问性属性。
ARIA 选择器支持
Puppeteer 支持通过 ARIA 选择器查询页面元素,这依赖于 Accessibility 组件提供的基础能力:
// 使用 ARIA 选择器定位元素
await page.locator('::-p-aria(Search)').fill('automate beyond recorder');
配置选项
覆盖率相关配置
| 配置项 | 类型 | 默认值 | 说明 | ||
|---|---|---|---|---|---|
| defaultBrowser | SupportedBrowser | 'chrome' | 默认浏览器类型 | ||
| temporaryDirectory | string | os.tmpdir() | 临时文件目录 | ||
| skipDownload | boolean | false | 是否跳过浏览器下载 | ||
| logLevel | 'silent' \ | 'error' \ | 'warn' | 'warn' | 日志级别 |
浏览器启动调试选项
| 选项名称 | 类型 | 说明 | |
|---|---|---|---|
| executablePath | string | 浏览器可执行文件路径 | |
| ignoreDefaultArgs | boolean \ | string[] | 是否忽略默认参数 |
| enableExtensions | boolean \ | string[] | 启用扩展支持 |
| handleSIGINT | boolean | 是否处理 Ctrl+C 信号 | |
| handleSIGTERM | boolean | 是否处理 SIGTERM 信号 | |
| handleSIGHUP | boolean | 是否处理 SIGHUP 信号 | |
| timeout | number | 浏览器启动超时时间(毫秒) |
资料来源:packages/puppeteer-core/src/node/LaunchOptions.ts:40-80
最佳实践
调试模式启用
在开发环境中启用完整调试日志:
PUPPETEER_DEBUG='*' node your-script.js
性能分析工作流
- 启动追踪:使用 Tracing API 开始记录性能数据
- 执行操作:在页面上执行待分析的操作
- 结束追踪:停止数据收集并获取结果
- 分析结果:使用 Chrome DevTools 或其他工具分析追踪数据
覆盖率采集建议
- 在关键测试场景中启用覆盖率统计
- 定期检查未使用的 CSS 和 JavaScript 代码
- 结合性能指标识别优化机会
相关资源
资料来源:[packages/puppeteer-core/src/api/Page.ts:250-290]()
失败模式与踩坑日记
保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
可能增加新用户试用和生产接入成本。
可能影响升级、迁移或版本选择。
可能增加新用户试用和生产接入成本。
可能影响授权、密钥配置或安全边界。
Pitfall Log / 踩坑日志
项目:puppeteer/puppeteer
摘要:发现 21 个潜在踩坑项,其中 4 个为 high/blocking;最高优先级:安装坑 - 来源证据:Chrome Canary/Firefox Nightly test results。
1. 安装坑 · 来源证据:Chrome Canary/Firefox Nightly test results
- 严重度:high
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:Chrome Canary/Firefox Nightly test results
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源问题仍为 open,Pack Agent 需要复核是否仍影响当前版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_1aabe120a9df47a2adbd293381b50a64 | https://github.com/puppeteer/puppeteer/issues/12379 | 来源类型 github_issue 暴露的待验证使用条件。
2. 安装坑 · 来源证据:Puppeteer v25
- 严重度:high
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:Puppeteer v25
- 对用户的影响:可能影响升级、迁移或版本选择。
- 建议检查:来源问题仍为 open,Pack Agent 需要复核是否仍影响当前版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_050f65ceff2a455da4a3538895a7538b | https://github.com/puppeteer/puppeteer/issues/14342 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
3. 安全/权限坑 · 来源证据:[Bug]: GHSA issued a false malicious package alert for puppeteer
- 严重度:high
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:[Bug]: GHSA issued a false malicious package alert for puppeteer
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源问题仍为 open,Pack Agent 需要复核是否仍影响当前版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_55588dfbd41442fdb8a2f4f1be57e4c9 | https://github.com/puppeteer/puppeteer/issues/14986 | 来源讨论提到 npm 相关条件,需在安装/试用前复核。
4. 安全/权限坑 · 来源证据:[Task]: Flaky `[fixtures.spec] Fixtures should dump browser process stderr`
- 严重度:high
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:[Task]: Flaky
[fixtures.spec] Fixtures should dump browser process stderr - 对用户的影响:可能影响授权、密钥配置或安全边界。
- 建议检查:来源问题仍为 open,Pack Agent 需要复核是否仍影响当前版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_9b1ef7c38ed14c41b3e4ce786adcdf26 | https://github.com/puppeteer/puppeteer/issues/14774 | 来源讨论提到 windows 相关条件,需在安装/试用前复核。
5. 安装坑 · 来源证据:[Bug]: @puppeteer/browsers silently corrupts Chrome cache on Node.js 26 (extract-zip 2.0.1)
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:[Bug]: @puppeteer/browsers silently corrupts Chrome cache on Node.js 26 (extract-zip 2.0.1)
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_5d1f448d8768460a806ab32e8d4f6997 | https://github.com/puppeteer/puppeteer/issues/14957 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
6. 安装坑 · 来源证据:[Bug]: `setViewport` crashes on Firefox if uncaught
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:[Bug]:
setViewportcrashes on Firefox if uncaught - 对用户的影响:可能阻塞安装或首次运行。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_75bddb8a74194cf7a8978853f19db23a | https://github.com/puppeteer/puppeteer/issues/14989 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
7. 安装坑 · 来源证据:[Bug]: chrome binary is not present when installing latest chrome
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:[Bug]: chrome binary is not present when installing latest chrome
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_1e85cdab2b684dda8e5c83f55b8ff7b6 | https://github.com/puppeteer/puppeteer/issues/14988 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
8. 安装坑 · 来源证据:[Feature]: Make proxy-agent dependency optional
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:[Feature]: Make proxy-agent dependency optional
- 对用户的影响:可能影响升级、迁移或版本选择。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_195c51e4a5e84edda14a2a79b456821c | https://github.com/puppeteer/puppeteer/issues/13775 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
9. 安装坑 · 来源证据:browsers: v3.0.0
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:browsers: v3.0.0
- 对用户的影响:可能影响升级、迁移或版本选择。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_bf2d83568c54447fbfd3047d24be0c48 | https://github.com/puppeteer/puppeteer/releases/tag/browsers-v3.0.0 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
10. 能力坑 · 来源证据:browsers: v3.0.2
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个能力理解相关的待验证问题:browsers: v3.0.2
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_c9f08632e7ee4e9485d27b864a21e462 | https://github.com/puppeteer/puppeteer/releases/tag/browsers-v3.0.2 | 来源类型 github_release 暴露的待验证使用条件。
11. 能力坑 · 来源证据:puppeteer-core: v25.0.2
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个能力理解相关的待验证问题:puppeteer-core: v25.0.2
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_3a8b10a5263e4d6488e16972c8249a38 | https://github.com/puppeteer/puppeteer/releases/tag/puppeteer-core-v25.0.2 | 来源类型 github_release 暴露的待验证使用条件。
12. 能力坑 · 能力判断依赖假设
- 严重度:medium
- 证据强度:source_linked
- 发现:README/documentation is current enough for a first validation pass.
- 对用户的影响:假设不成立时,用户拿不到承诺的能力。
- 建议检查:将假设转成下游验证清单。
- 防护动作:假设必须转成验证项;没有验证结果前不能写成事实。
- 证据:capability.assumptions | github_repo:90796663 | https://github.com/puppeteer/puppeteer | README/documentation is current enough for a first validation pass.
13. 维护坑 · 来源证据:ng-schematics: v0.8.0
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个维护/版本相关的待验证问题:ng-schematics: v0.8.0
- 对用户的影响:可能影响升级、迁移或版本选择。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_4e7ee6a70b1d4fb6879ab4670099d205 | https://github.com/puppeteer/puppeteer/releases/tag/ng-schematics-v0.8.0 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
14. 维护坑 · 来源证据:puppeteer-core: v25.0.0
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个维护/版本相关的待验证问题:puppeteer-core: v25.0.0
- 对用户的影响:可能影响升级、迁移或版本选择。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_3e6a5770b15146ddab5249f1aa687cae | https://github.com/puppeteer/puppeteer/releases/tag/puppeteer-core-v25.0.0 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
15. 维护坑 · 来源证据:puppeteer: v25.0.0
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个维护/版本相关的待验证问题:puppeteer: v25.0.0
- 对用户的影响:可能影响升级、迁移或版本选择。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_9294fdbab95d446887bdb54a11df66d2 | https://github.com/puppeteer/puppeteer/releases/tag/puppeteer-v25.0.0 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
16. 维护坑 · 维护活跃度未知
- 严重度:medium
- 证据强度:source_linked
- 发现:未记录 last_activity_observed。
- 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
- 建议检查:补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作:维护活跃度未知时,推荐强度不能标为高信任。
- 证据:evidence.maintainer_signals | github_repo:90796663 | https://github.com/puppeteer/puppeteer | last_activity_observed missing
17. 安全/权限坑 · 下游验证发现风险项
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:下游已经要求复核,不能在页面中弱化。
- 建议检查:进入安全/权限治理复核队列。
- 防护动作:下游风险存在时必须保持 review/recommendation 降级。
- 证据:downstream_validation.risk_items | github_repo:90796663 | https://github.com/puppeteer/puppeteer | no_demo; severity=medium
18. 安全/权限坑 · 存在评分风险
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:风险会影响是否适合普通用户安装。
- 建议检查:把风险写入边界卡,并确认是否需要人工复核。
- 防护动作:评分风险必须进入边界卡,不能只作为内部分数。
- 证据:risks.scoring_risks | github_repo:90796663 | https://github.com/puppeteer/puppeteer | no_demo; severity=medium
19. 安全/权限坑 · 来源证据:[Feature]: Reducing dependencies
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:[Feature]: Reducing dependencies
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_cb21a546ebb04ca39b334255b205c9da | https://github.com/puppeteer/puppeteer/issues/13552 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
20. 维护坑 · issue/PR 响应质量未知
- 严重度:low
- 证据强度:source_linked
- 发现:issue_or_pr_quality=unknown。
- 对用户的影响:用户无法判断遇到问题后是否有人维护。
- 建议检查:抽样最近 issue/PR,判断是否长期无人处理。
- 防护动作:issue/PR 响应未知时,必须提示维护风险。
- 证据:evidence.maintainer_signals | github_repo:90796663 | https://github.com/puppeteer/puppeteer | issue_or_pr_quality=unknown
21. 维护坑 · 发布节奏不明确
- 严重度:low
- 证据强度:source_linked
- 发现:release_recency=unknown。
- 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
- 建议检查:确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作:发布节奏未知或过期时,安装说明必须标注可能漂移。
- 证据:evidence.maintainer_signals | github_repo:90796663 | https://github.com/puppeteer/puppeteer | release_recency=unknown
来源:Doramagic 发现、验证与编译记录