首页
/ Puppeteer 浏览器进程启动指南:@puppeteer/browsers launch() 函数全解

Puppeteer 浏览器进程启动指南:@puppeteer/browsers launch() 函数全解

2026-09-07 17:20:29作者:郁楠烈Hubert

本篇文章聚焦 Puppeteer 独立子包 @puppeteer/browsers 中的核心函数 launch()。该函数是 Puppeteer 生态中"程序化拉起 Chrome / Firefox 浏览器进程"的统一入口,也是 Puppeteer 主库在背后启动浏览器所使用的底层原语。读完本文,你将掌握 launch() 的签名、全部 LaunchOptions 参数含义与默认值、返回的 Process 对象生命周期管理方法,以及如何用日志/正则从浏览器输出中探测 CDP 与 WebDriver BiDi 的 WebSocket 端点,从而写出自己可控的浏览器进程启动器。

launch():把"启动浏览器"收敛为一个可编程 API

在 Puppeteer 项目中,launch() 位于独立发布、可供第三方复用的子包 @puppeteer/browsers(源码根目录见 packages/browsers/src/launch.ts)。它的作用一句话即可概括:根据 LaunchOptions 启动一个浏览器进程,并返回一个包装好的 Process 对象

它要解决的问题包括:用 child_process 拉起可执行文件、正确配置 stdio 流、捕获并缓存浏览器 stdout/stderr 输出、在 Node 进程收到信号时同步结束浏览器、以及在进程退出时执行清理钩子。下面先看官方 API 文档给出的签名。

函数签名与返回值

launch() 声明于 docs/browsers-api/browsers.launch.md,并同时从子包入口 packages/browsers/src/main.ts 对外导出:

export declare function launch(opts: LaunchOptions): Process;
参数 类型 说明
opts LaunchOptions 启动配置,见下文参数表

返回值类型为 Process。注意 LaunchOptions必选参数,其中最关键的是浏览器可执行文件的绝对路径 executablePath——launch() 本身不做"找浏览器"的工作,那是 computeExecutablePath() / computeSystemExecutablePath() 等函数的分工。

从源码看 launch() 的本质

从源码看,launch() 的实现极简——它只是 Process 类的构造工厂(见 packages/browsers/src/launch.ts#L216-L221):

export function launch(opts: LaunchOptions): Process {
  return new Process({
    ...opts,
    logger: opts.logger ?? debug,
  });
}

也就是说,真正的进程管理逻辑全部封装在 Process 类内部:构造时它会读取各项选项、配置 stdio、执行 childProcess.spawn,并注册 Node 进程级信号监听。理解 Process 的内部行为,就等于理解 launch() 的全部语义。

LaunchOptions 全参数速查与逐项解读

下表完整继承自 docs/browsers-api/browsers.launchoptions.md,同时补充默认值与源码实现细节:

属性 修饰符 类型 说明 默认值
executablePath (必填) string 浏览器可执行文件的绝对路径
args optional string[] 启动时附加传给可执行文件的命令行参数
detached optional boolean 是否以 detached 模式 spawn 子进程 Windows 外为 true
dumpio optional boolean true 时把浏览器 stdout/stderr 转发到 Node 进程的 stdout/stderr false
env optional Record<string, string | undefined> 为浏览器进程设置的环境变量
handleSIGHUP optional boolean Node 进程收到 SIGHUP 时尝试优雅关闭浏览器进程 true
handleSIGINT optional boolean Node 进程收到 SIGINT 时尝试杀掉浏览器进程 true
handleSIGTERM optional boolean Node 进程收到 SIGTERM 时尝试优雅关闭浏览器进程 true
logger optional Logger 用自定义 Logger 替换内部默认日志器
onExit optional () => Promise<void> 浏览器进程退出后、或被 Process.close() 关闭前执行的回调,仅执行一次
pipe optional boolean 额外打开两条流用于自动化(代替 WebSocket) false
signal optional AbortSignal 提供后,该信号被 abort 时会杀死进程

必填项 executablePath:绝对路径是硬约束

LaunchOptions 中唯一不带 optional 的属性。源码 packages/browsers/src/launch.ts#L146 注释明确要求它是"Absolute path to the browser's executable"。典型来源有二:

  • 调用 computeExecutablePath() 获取缓存目录内的浏览器路径(需要先 install());
  • 调用 computeSystemExecutablePath() 按发行渠道(如 Chrome Stable/Canary)探测系统级安装路径。

pipe:用管道流代替 WebSocket 做自动化

pipe 控制 stdio 的流数量(默认 false)。对应源码 #configureStdiopackages/browsers/src/launch.ts#L415-L421):

#configureStdio(opts: {pipe: boolean}): Array<'ignore' | 'pipe'> {
  if (opts.pipe) {
    return ['pipe', 'pipe', 'pipe', 'pipe', 'pipe'];
  } else {
    return ['pipe', 'pipe', 'pipe'];
  }
}
  • pipe: false:标准 3 条流(stdin/stdout/stderr);
  • pipe: true:额外多开 2 条流(共 5 条),供上层通过管道而非 WebSocket 驱动浏览器。Puppeteer 的 --pipe / pipe 模式即与此相关。

无论哪种情况,浏览器子进程的 stdout、stderr 都会被逐行记录(见下文"端点探测"一节)。

env、detached 与日志脱敏

env 会整体传给 child_process.spawnpackages/browsers/src/launch.ts#L337)。值得注意的是,内部日志只打印键名以 puppeteer_ 开头的环境变量,避免把敏感 env 全量刷入日志(launch.ts#L343-L353)。

detached 的语义来自 Node 的 child_process 选项:置为 true 时,子进程会成为新进程组的组长,从而可以把整棵进程树隔离起来,防止控制台信号直接传播到浏览器。源码以 opts.detached ??= true 兜底默认值(launch.ts#L332),文档标注的默认值是"除 Windows 外均为 true"。

信号处理三兄弟与 onExit 钩子

三个布尔开关控制 Node 进程收到信号时的联动行为(源码 launch.ts#L435-L445):

信号 处理动作(默认开启)
SIGINT(如 Ctrl+C) kill() 浏览器进程后 process.exit(130)
SIGTERM / SIGHUP 调用 close() 优雅关闭浏览器进程

内部通过 subscribeToProcessEvent / unsubscribeFromProcessEvent 维护一组进程级监听器(launch.ts#L260-L286),多个 Process 实例共享同一底层监听并各自派发。浏览器退出或 close() 触发时,onExit 钩子只运行一次(由 #hooksRan 标记保证,见 launch.ts#L403-L409)。

signal:以 AbortSignal 形式取消启动

signal 接受一个 AbortSignal。源码在构造期就检查信号是否已 abort,若是则直接抛出 signal.reason || 'Launch aborted'launch.ts#L317-L321);否则注册一次性 abort 监听,触发即执行 kill()。这让 launch() 可以自然地融入 AbortController 超时/取消流程。

返回值 Process:如何管理浏览器子进程

launch() 返回的 Process 类同样定义在 packages/browsers/src/launch.ts#L291,并在 docs/browsers-api/browsers.process.md 有完整文档。它向调用方暴露以下能力:

成员 类型/签名 作用
nodeProcess readonly childProcess.ChildProcess 底层 Node 子进程对象(可直接拿到 pid 等)
close() () => Promise<void> 先运行 onExit 钩子,再杀掉仍未退出的进程,等待其退出
kill() () => void 强杀浏览器进程(含进程组/子进程树)
hasClosed() () => Promise<void> 返回一个在进程退出后 resolve 的 Promise
getRecentLogs() () => string[] 获取浏览器近期的 stderr + stdout 输出
waitForLineOutput(regex, timeout?) (regex, timeout = 0) => Promise<string> 等待 stdout/stderr 中出现匹配正则的行,返回第一个捕获组

跨平台 kill 策略

Process.kill() 内部按平台区分处理(launch.ts#L459-L513):

  • Windows:优先 taskkill /pid <pid> /T /F,递归结束整棵子进程树;失败则退回 childProcess.kill()
  • Linux / macOS:以 -pid 作为进程组 id 调用 process.kill(..., 'SIGKILL') 杀进程组;失败则退回 childProcess.kill('SIGKILL')

同时它会先通过 pidExistsprocess.kill(pid, 0))确认进程仍存在,避免因可执行文件路径非法、子进程根本没拿到 pid 而抛错。若最终仍无法杀掉,会抛出包含 Puppeteer was unable to kill the process... 说明文字的异常,提示清理遗留浏览器进程。

日志缓冲与端点探测:waitForLineOutput

Process 构造后会用 readline 按行读取浏览器 stdout 与 stderr,写入最多保留 1000 行的环形日志缓冲(#maxLogLinesSize = 1000,见 launch.ts#L515-L540),每来一行都会触发内部 line 事件。

waitForLineOutput(regex, timeout = 0)launch.ts#L551-L610)正是建立在这套逐行监听之上:它会先扫描已缓存行、再实时匹配新行,命中后 resolve 第一个捕获组;若浏览器提前退出/报错,则拒绝并把近期日志拼进错误信息;timeout > 0 时超时会抛出 TimeoutError

与之配套,包内还导出两个端点匹配正则(launch.ts#L226-L233):

export const CDP_WEBSOCKET_ENDPOINT_REGEX = /^DevTools listening on (ws:\/\/.*)$/;
export const WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX = /^WebDriver BiDi listening on (ws:\/\/.*)$/;

典型用法:以 --remote-debugging-port=0 或 WebDriver BiDi 模式启动浏览器,然后等待"DevTools listening on ws://..."或"WebDriver BiDi listening on ws://..."这行输出,从而拿到浏览器自报的端口与端点地址。

一个最小可运行示例

下面是一个完整的最小脚本:先用 computeExecutablePath 算出缓存内已安装 Chrome 的路径,再调用 launch() 启动,并通过正则探测端点:

import {
  Browser,
  BrowserPlatform,
  CDP_WEBSOCKET_ENDPOINT_REGEX,
  computeExecutablePath,
  detectBrowserPlatform,
  install,
  launch,
} from '@puppeteer/browsers';

const cacheDir = '/tmp/my-cache';
const browser = Browser.CHROME;
const buildId = '120.0.6099.109';

// 1. 确保浏览器已下载到本地缓存
await install({browser, buildId, cacheDir, platform: detectBrowserPlatform()!});

// 2. 依据缓存元数据解析出可执行文件绝对路径
const executablePath = computeExecutablePath({
  browser,
  buildId,
  cacheDir,
  platform: detectBrowserPlatform(),
});

// 3. 启动浏览器进程
const proc = launch({
  executablePath,
  args: ['--no-sandbox', '--disable-setuid-sandbox'],
  env: {PUPPETEER_CACHE_DIR: cacheDir},
  dumpio: false,
  handleSIGINT: true,
});

// 4. 等待 CDP WebSocket 端点出现在 stdout 上
const wsEndpoint = await proc.waitForLineOutput(
  CDP_WEBSOCKET_ENDPOINT_REGEX,
  30_000, // 30s 超时
);
console.log('Endpoint:', wsEndpoint);

// 5. 业务结束后优雅关闭;进程崩溃时可拿最近日志排查
await proc.close();
console.log('Recent logs:', proc.getRecentLogs());

需要说明:平台一般无需手传,BrowserPlatform 会自动探测;但显式传入 detectBrowserPlatform() 的返回值会让代码在 CI 等异构环境中更可预期。若使用 WebDriver BiDi 协议,请把匹配正则换成 WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEXwaitForLineOutput 在浏览器进程提前退出时会把 stderr/近期日志一并拼入错误并建议查阅官方 Troubleshooting 页,方便快速定位启动失败原因。

上游调用:Puppeteer 主库如何消费 launch()

@puppeteer/browsers 提供的这套启动原语,正是 Puppeteer 主库(puppeteer-core)的底层依赖。在 packages/puppeteer-core/src/node/BrowserLauncher.ts#L10-L17 可以看到它直接导入:

import {
  Browser as InstalledBrowser,
  CDP_WEBSOCKET_ENDPOINT_REGEX,
  launch,
  TimeoutError as BrowsersTimeoutError,
  WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX,
  computeExecutablePath,
} from '@puppeteer/browsers';

这意味着 Puppeteer 的 puppeteer.launch() 本质上就是在 executablePath 解析、用户参数整理之外,委托这里的 launch() 去 spawn 进程,再配合上述两个端点正则与 waitForLineOutput 拿到调试/自动化端点。若想深入了解进程级启动与协议级连接之间的衔接,可继续阅读 BrowserLauncher.ts 以及 Chrome/Firefox 两个具体启动器 ChromeLauncher.tsFirefoxLauncher.ts

CLI 侧的 launch:命令行的同一套逻辑

除了程序化 API,@puppeteer/browsers 的 CLI 也提供 launch 子命令,它最终复用同一个 launch() 函数(见 packages/browsers/src/CLI.ts#L363-L445):

# 启动缓存中指定版本的 Chrome
npx @puppeteer/browsers launch chrome@115.0.5790.170

# 启动后把浏览器 stdout/stderr 转发到当前终端
npx @puppeteer/browsers launch chrome@115.0.5790.170 --dumpio

# 以 detached 方式启动(进程脱离终端)
npx @puppeteer/browsers launch chrome@115.0.5790.170 --detached

# 尝试定位并启动系统安装的 Chrome Canary
npx @puppeteer/browsers launch chrome@canary --system

# 启动并把自定义参数传给浏览器二进制(-- 之后的部分)
npx @puppeteer/browsers launch chrome@115.0.5790.170 -- --version

命令内部先用 computeExecutablePath(缓存模式)或 computeSystemExecutablePath--system 模式)解析路径,再调用 launch() 传入 extraArgsdumpiodetached。CLI 的 launch 默认 detached: false,与 API 的默认值不同,便于终端场景下把浏览器输出留在前台。

调试技巧与适用边界

  • 查看启动日志launch() 内部通过 debug 模块输出,调试前缀为 puppeteer:browsers:launcher(见 packages/browsers/src/debug.ts)。可用 Node 内置能力开启:

    env NODE_DEBUG="puppeteer:browsers:launcher" node your-script.mjs
    

    日志会打印待执行的可执行文件与参数、spawn 时的 detached/stdio 配置、pid、进程是否存在等关键状态。

  • logger 字段LaunchOptions.logger 可传入自定义 Logger(类型 (prefix: string) => LoggerFunction | undefined)替换默认实现,方便接入自己的日志体系。

  • 已知限制:本包 API 文档明确说明,"启动系统已安装浏览器(system browsers)仅对 Chrome/Chromium 可用"(见 docs/browsers-api/index.md);Firefox 需走缓存内已安装的构建产物。

  • 进程清理:若应用异常退出后残留浏览器进程,请优先确保代码路径调用 close()/kill();一旦进程组无法被杀,后续再次启动浏览器可能失败。

综合来看,launch() 把"起进程、管输出、收信号、清进程树"这些繁琐且易错的工作封装成 10 个参数 + 1 个返回值即可驾驭的简洁 API,是 Puppeteer 生态里任何需要"自己拉起一个浏览器进程"场景的可靠地基。想要继续探究它的上下游,可顺次阅读本仓库中的 launch 源码LaunchOptions 文档Process 文档,以及引用它的 BrowserLauncher.ts

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388