Puppeteer 常见报错怎么解:浏览器、内存与配置对照处理
Puppeteer 是通过 DevTools Protocol 或 WebDriver BiDi 控制 Chrome、Firefox 的 JavaScript 库。当前官方安装说明特别提醒:现代包管理器默认阻止依赖安装脚本,可能导致浏览器没有下载;到 Puppeteer 16.0.0 起,官方还提供 Docker 镜像,容器排查路径也与早期版本不同。现在最值得先确认的,是报错究竟发生在安装、启动还是测试阶段。
先分清报错发生在哪一层
Puppeteer 的故障并不都表现为代码异常。依赖安装脚本被阻止时,安装过程仍可能显示成功,直到脚本运行时才找不到浏览器;Chrome 缺少系统共享库时,错误发生在 Docker 容器中;Jest 并行启动过多进程时,内存错误又来自测试运行器。
因此,先按现象定位,不要看到红色报错就同时修改启动参数。
| 现象 | 优先检查 | 对应处理 |
|---|---|---|
| 安装结束,但启动时找不到浏览器 | 浏览器是否实际下载 | 执行 npx puppeteer browsers install |
| 容器内 Chrome 无法启动 | Linux 共享库 | 对照官方 Docker 集成说明补依赖 |
Jest 报 spawn ENOMEM |
容器内存与 worker 数量 | 将 Jest worker 限制为 2 |
自定义浏览器命令报 method not found |
CDP 会话层级 | 改用浏览器级会话 |
| 浏览器能启动,但页面视口或地区配置不一致 | 启动选项是否覆盖配置 | 显式指定可执行文件和启动参数 |
这是按官方故障说明整理的排查顺序,不是把所有问题都归因于版本不兼容。
浏览器没下载:先补浏览器,再重跑脚本
官方仓库给出的两个安装方式有明确区别:
npm i puppeteer
这条命令会下载与当前 Puppeteer 兼容的 Chrome。若使用 puppeteer-core,库本身不包含浏览器,需要另行提供浏览器:
npm i puppeteer-core
现代 npm、pnpm、Yarn、Bun 和 Deno 默认阻止依赖安装脚本。脚本被阻止时,Puppeteer 不会在安装过程中下载浏览器,随后便出现运行期错误。直接执行下面的官方命令补齐浏览器:
npx puppeteer browsers install
不要先改 executablePath。如果浏览器尚未下载,先让 Puppeteer 按自身版本要求安装匹配项;executablePath 是连接已有浏览器,不是替代下载流程的通用开关。
也可以在 package.json 的 allowScripts 中加入 puppeteer,允许安装脚本执行。选择哪一种取决于项目是否允许依赖脚本:受控的 CI 环境可采用显式安装命令,隔离更严格的开发环境则配置包管理器白名单。
Docker 缺共享库:容器内启动失败这样查
Puppeteer 官方说明指出,Chrome for Testing 依赖一组 Linux 共享库。自 Puppeteer 16.0.0 起,官方通过 GitHub Container Registry 提供 Docker 镜像,早期版本使用的测试容器方案则已经停止作为当前发布路径。
遇到容器内启动失败时,进入官方 Troubleshooting 页面的 “Running Puppeteer in Docker” 部分,再沿页面中的 “Integrations > Docker” 入口查看镜像用法:
https://pptr.dev/troubleshooting
这里要区分两类问题:
- 使用官方镜像时,确认镜像里的浏览器版本与当前
puppeteer包匹配,不要只复制旧项目的 Dockerfile。 - 自建镜像时,按官方说明补齐 Chrome 所需的共享库;仅复制
puppeteer的安装命令并不能提供 Linux 系统库。
Docker 报出的共享库缺失信息通常位于最底层。先修复这些 cannot open shared object file 一类错误,再观察 Puppeteer 是否还能输出页面级异常。反过来调 JavaScript 超时或导航参数,只会掩盖容器根本没有启动浏览器的问题。
Jest 报 ENOMEM:限制 worker,而不是增加内存
如果错误输出包含下面这类内容,问题通常不是页面本身:
Error: spawn ENOMEM at ChildProcess.spawn (internal/child_process.js:394:11)
官方 Troubleshooting 给出的原因是 Jest 自动检测了整台机器的进程数,而容器实际只允许更少的进程;示例输出中的 --max-workers=36 就明显高于示例容器可承受的 2。
在测试命令中显式限制 worker:
jest --maxWorkers=2
这属于按官方示例执行的解法:若 CI 容器内存较小,2 是官方示例值,不应机械理解成所有机器的唯一设置;应根据容器可用内存调整,但必须显式设置,否则 Jest 仍可能按宿主机资源数启动进程。
判断是否解决,不要只看测试是否结束。还要确认容器没有继续出现 spawn ENOMEM,且多个浏览器用例能够并行完成。这里限制的是 Jest 创建的子进程数量,页面内部同时打开多少标签页仍由测试代码控制。
method not found:CDP 会话可能选错层级
BotBrowser 集成文档记录了一个不崩溃、却会直接失败的典型错误:调用扩展命令时出现 method not found。原因是 BotBrowser 命令属于浏览器级 CDP(Chrome DevTools Protocol,浏览器调试协议)能力,却被发给了页面级会话。
处理路径是:
- 用
puppeteer-core启动指定的 BotBrowser 可执行文件。 - 保留
defaultViewport: null,避免 Puppeteer 用默认视口覆盖浏览器配置。 - 创建会话时调用
browser.target().createCDPSession(),不要改用page.target().createCDPSession()。 - 把
--bot-profile、--proxy-server、--bot-timezone、--bot-locale和--bot-languages放进启动参数args。
其中第 3 步是最直接的修复点:命令不存在于当前会话时,先核对会话层级,而不是反复重装 Puppeteer。
这类错误还需要观察配置是否真正生效。新页面若仍报告 800×600,说明 Puppeteer 的默认视口覆盖仍在;若地区、时区或代理结果与配置不一致,则继续检查 args 中是否传入了对应启动参数。BotBrowser 是第三方浏览器,不能把它的命令直接套到普通 Chrome 或 Firefox 上。
用最小启动脚本确认问题已经消失
排查完安装、容器和测试配置后,用一个最小脚本验证 Puppeteer 自身能否启动浏览器:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://developer.chrome.com/');
await browser.close();
官方示例还提供了完整页面操作方式,包括设置视口、按键盘按键、用可访问性名称定位输入框,以及等待文本出现。故障排查阶段先保留最小动作,确认浏览器启动、页面创建、导航和关闭四个环节;不要一开始就把业务脚本中的几十个选择器、代理和重试逻辑全部带进来。
成功标志至少应包括:脚本没有浏览器下载或共享库错误,页面成功打开,并且 browser.close() 正常执行。如果最小脚本正常、原业务脚本失败,再把差异缩小到页面选择器、导航等待条件或浏览器启动参数。
官方入口与继续排查路径
Puppeteer 官方仓库是安装方式、浏览器下载命令和示例代码的一手来源:
https://github.com/puppeteer/puppeteer/tree/main#readme
故障排查页覆盖 Jest、Docker 和配置问题:
https://pptr.dev/troubleshooting
需要核对第三方浏览器的启动参数和 CDP 会话层级时,参考 BotBrowser 的集成说明:
https://botbrowser.io/zh/blog/getting-started-puppeteer/
排查时最有价值的顺序是:先看错误发生在安装、容器启动还是测试进程;再执行 Puppeteer 官方给出的对应命令;最后用最小启动脚本验收。这样能避免把浏览器缺文件、CDP 会话错误和 Jest 内存不足混成同一个“版本问题”。
参考来源
评论区
登录后可评论。