playwright install 下载浏览器失败:Playwright 在离线与代理环境怎么装

2026-08-18
站内工具 AI 编程工具报错分诊器 → 把报错原文贴进去,先分清是网络、额度、配置还是上游故障,再决定往哪个方向查。

装 Playwright 这件事分两步:装包,和装浏览器。前一步走 npm / pip / maven,公司里通常早就配好了私服;后一步是 Playwright 自己发起的一次 HTTP 下载,走的不是包管理器那条路。所以经常出现的局面是——依赖装得好好的,playwright install 一执行就卡死在进度条上,或者直接抛一串证书错误。

仓库 docs/src/browsers.md 的开头就写明了这个前提:每个版本的 Playwright 需要特定版本的浏览器二进制,必须用 Playwright CLI 去装;每次升级 Playwright,可能都得重新跑一次 install。下面这些排查动作与处置手段,全部来自这个文件以及 packages/playwright-core/src/ 下对应的实现代码。

一、先分清是哪一类失败

docs/src/browsers.md 里点名的失败形态有两类。

一类是代理拦截并换了自签名证书,文档写明的报错原文是 Error: self signed certificate in certificate chain。另一类是网络连到浏览器归档慢,文档给出的对策是调大超时。

还有一类文档没有直接命名,但源码里有确切的报错串:packages/utils/network.ts 里请求超时时抛的是 Request to ${params.url} timed out after ${params.socketTimeout}mspackages/playwright-core/src/server/registry/index.ts 里下载最终失败时包一层 Failed to download ${title}, caused by。看到这两句,说明失败发生在下载阶段,而不是包安装或运行阶段。

二、判定动作:先让它把要做的事打印出来

不要靠猜代理有没有生效。install 命令带一个 --dry-runpackages/playwright-core/src/cli/program.ts 里对它的描述是”不执行安装,只打印信息”。

npx playwright install --dry-run

它打印什么,在 packages/playwright-core/src/cli/installActions.ts 里写得很清楚:对每一个待装的可执行体,先打印下载标题,然后依次是 Install location:Download url:,以及若干行 Download fallback N:

这三行正好对应了排查这件事的三个未知数:装到哪个目录、主下载地址是什么、还有几个备用地址。你设的环境变量到底吃进去没有,看这一屏就知道了,不用真的等下载。

两个限制要记住:--dry-run--list 不能同时给,源码里直接抛 Only one of --dry-run and --list can be specified--no-shell--only-shell 也互斥,报错是 Only one of --no-shell and --only-shell can be specified

想看更细的过程,下载相关的日志在源码里是通过 debugLogger.log('install', ...) 打出来的,而 packages/utils/debugLogger.tsdebug(\pw:${name}`)这行说明这个通道对应的名字是pw:install。需要说明的是,仓库文档里被正式写进去的调试通道我们只找到 pw:apidocs/src/debug.md)和 pw:browserdocs/src/ci.mddocs/src/selenium-grid.md`)这两个。

另外,如果你在没装项目依赖的情况下直接 npx playwright install,源码里会先打一段 WARNING 框,提示你先 npm install 再跑 install。这段警告和网络无关,别被它带偏。

三、处置一:把下载来源换掉

Playwright 默认从微软的 CDN 下浏览器,这是 docs/src/browsers.md 明写的。改来源有两个方向。

走代理。 文档给的变量是 HTTPS_PROXY,并且按平台分了三种写法。Linux/macOS:

HTTPS_PROXY=https://192.0.2.1 npx playwright install

Windows 命令提示符与 PowerShell 分别是:

set HTTPS_PROXY=https://192.0.2.1
npx playwright install
$Env:HTTPS_PROXY="https://192.0.2.1"
npx playwright install

其中的 192.0.2.1 是仓库文档里用的示例地址,换成你自己的代理。Python 绑定对应的是 playwright install,Java 是 mvn exec:java 那一长串,C# 是 pwsh bin/Debug/netX/playwright.ps1 install,四种写法在 docs/src/browsers.md 里都各自列了一份,别把 JS 那行套到别的绑定上。

代理这层在代码里的落点是 packages/utils/network.ts:它用 proxy-from-envgetProxyForUrl(params.url) 按目标 URL 解析代理,https: 的请求走 HttpsProxyAgent。文档里点名的变量只有 HTTPS_PROXY 一个,别的变量名仓库文档里没有写,不要凭印象设。

如果代理换了自签名 CA,文档要求在装浏览器之前NODE_EXTRA_CA_CERTS

set NODE_EXTRA_CA_CERTS="C:\certs\root.crt"
export NODE_EXTRA_CA_CERTS="/path/to/cert.pem"

走内网镜像。 公司自建二进制仓库的场景,文档给的是 PLAYWRIGHT_DOWNLOAD_HOST;还可以按浏览器分别指定 PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOSTPLAYWRIGHT_FIREFOX_DOWNLOAD_HOSTPLAYWRIGHT_WEBKIT_DOWNLOAD_HOST,文档写明这三个的优先级高于 PLAYWRIGHT_DOWNLOAD_HOST。这一点在 registry/index.ts_downloadURLs 里能对上:它先按浏览器名挑出对应的那个变量,取不到再回落到通用变量。

这里有一处值得放在一起看的细节。browserFetcher.ts 的下载循环会在多次尝试之间轮换地址(downloadURLs[(attempt - 1) % downloadURLs.length]),当前代码里的重试次数常量是 5——这是仓库当前代码里的值,随版本可能变动。而 _downloadURLs 里一旦读到自定义 host,就执行 mirrors = [customHostOverride],候选地址被收敛成一条。也就是说,配了内网镜像之后,那几次重试全都打在同一个地址上,官方的备用镜像不再参与。--dry-run 输出里 Download fallback 那几行会不会消失,正好是这件事的直接验证点。

只是慢,不是不通。 文档提供了 PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT,单位毫秒。源码里对它有一句作者自述的注释(registry/index.ts):这个名字起得不准,它实际控制的是 socket 的最大空闲超时,但改名会破坏已有用户的工作流,所以没改。没设这个变量时用的是 packages/utils/network.ts 里的 NET_DEFAULT_TIMEOUT,当前代码里是 30_000 毫秒——同样是仓库当前代码里的默认值,随版本可能变动。

四、处置二:--with-deps 到底做了什么

--with-deps 常被当成”装得更全”的万能开关,但它在两个平台上做的事差得很远。

docs/src/browsers.md 的定位是:系统依赖可以自动安装,这对 CI 有用;install-deps 可以单独跑,也可以合进 install:

npx playwright install --with-deps chromium

看实现 packages/playwright-core/src/server/registry/dependencies.ts:Linux 分支 installDependenciesLinux 会汇总一份库列表,然后跑 apt-get updateapt-get install;Windows 分支 installDependenciesWindows 只在目标包含 chromium 时,用 powershell.exe -ExecutionPolicy Bypass -File 执行仓库自带的 install_media_pack.ps1,其它情况什么都不做。

所以在 Windows 上,--with-deps 覆盖的面比 Linux 小得多,指望它解决网络或路径问题是找错了对象。反过来在 Linux 上,文档专门提醒:要在代理后面装依赖,得用 root 跑,否则 Playwright 自己提权时不会把 HTTPS_PROXY 这类变量传给包管理器:

sudo HTTPS_PROXY=https://192.0.2.1 npx playwright install-deps

install-deps 自己也有 --dry-runprogram.ts 里对它的说明是:不修改系统,Linux 上用 apt-get 模拟一遍、缺包就以非零码退出,Windows 上则把要执行的安装命令打印出来。做非交互式校验时这个比直接装有用。

体积上还有两个开关:只跑 headless 时可以 --only-shell 跳过完整 Chromium 的下载;用新版 headless(chromium channel)时可以 --no-shell 跳过 headless shell。两者互斥,前面说过。

五、处置三:不下载,直接指向已有的浏览器

彻底离线的机器上,最省事的做法是别让它下载。

共享目录:PLAYWRIGHT_BROWSERS_PATH 文档把它分成了两组命令:安装时用它决定装到哪儿,运行脚本时同样要设它,Playwright 才会去那个共享位置找浏览器。这两处必须一致,只在安装时设、跑测试时忘了设,是很常见的一个坑。Windows 上文档给的示例是:

set PLAYWRIGHT_BROWSERS_PATH=%USERPROFILE%\pw-browsers
npx playwright install

registry/index.tsregistryDirectory 的解析逻辑值得一读:值为字符串 '0' 时落到包目录下的 .local-browsers(也就是文档里 JS 专属的 hermetic install 那一节);给了其它值就直接当目录用;相对路径会用 INIT_CWD 或当前工作目录解析成绝对路径,代码注释自述的理由是安装期与执行期必须指向同一个目录。

不设这个变量时,默认缓存目录文档写得很明确:Windows 是 %USERPROFILE%\AppData\Local\ms-playwright,macOS 是 ~/Library/Caches/ms-playwright,Linux 是 ~/.cache/ms-playwright。离线机器上把这个目录整份拷过去,是很多团队的实际做法——但这属于通用运维手段,不是仓库文档写明的官方流程。

一个边界:文档单独用 note 标出,PLAYWRIGHT_BROWSERS_PATH 不改变 Google Chrome 与 Microsoft Edge 的安装路径。

完全跳过下载。 docs/src/browsers.md 里有 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD,注意这一节标的是 * langs: java,适用场景是二进制由外部单独管理。JS 侧的说明写在 docs/src/library-js.md:同样是二进制由外部单独管理时,在装包之前设这个变量,从而跳过 npm install 阶段的浏览器下载(那一节前面刚讲过 @playwright/browser-chromium 这类辅助包会在包安装时自动下载浏览器)。两处语境不同,别混着抄。

指定可执行文件本身。 启动参数 executablePathdocs/src/api/params.md 的定义是:运行指定的浏览器可执行文件而不是自带的那份,相对路径按当前工作目录解析。同一份文档紧跟着写明”Playwright 只与自带的 Chromium、Firefox 或 WebKit 配合工作,风险自负”;docs/src/api/class-browsertype.mdBrowserType.launch 下的提醒更重:Playwright 与自带的那个 Chromium 版本配合最好,不保证能配合其它版本,使用 executablePath 要极其谨慎。这条路能走通,但它是官方明确标了风险的口子,不是推荐做法。想知道 Playwright 期望的路径是什么,class-browsertype.md 里还有一个 BrowserType.executablePath 方法,返回它预期找到自带浏览器可执行文件的路径。

用机器上已有的 Chrome / Edge。 这条走的是 channel,文档列出的可用取值是 chromemsedgechrome-betamsedge-betachrome-devmsedge-devchrome-canarymsedge-canary。文档同时挂了一条 warning:某些企业浏览器策略会影响 Playwright 启动和控制 Chrome 与 Edge 的能力,在有浏览器策略的环境下运行不在 Playwright 项目的范围内。企业内网恰恰是这类策略最密集的地方,选这条路之前先掂量一下。

以上命令为按仓库文档中的参数语义组合的示例,未经实测,以仓库最新内容与 --help 的实际输出为准。

六、处置完怎么验证

第一步还是 --dry-runDownload url 那行应该已经换成你的镜像地址,Install location 应该指向你设的目录。这一步不产生任何下载,可以反复跑。

第二步跑 npx playwright install --listinstallActions.ts 里这个分支调的是 listInstalledBrowsers(),并按 Playwright 版本分组打印机器上所有 Playwright 安装的浏览器。

第三步是安装完成之后:browserFetcher.ts 在成功路径末尾会打印 ${title} downloaded to ${browserDirectory},这行里的目录应当与前面 --dry-run 报的安装位置一致。另外,判断”已经装过”靠的是浏览器目录里的一个标记文件(browserDirectoryToMarkerFilePath),已经存在就直接跳过;怀疑上一次是残包,用 --force 强制重装。

七、什么情况说明不是下载这一环的问题

三种信号可以把你从这条排查线上拉走。

报的是 Executable doesn't exist at ... 这句来自 registry/index.ts,后面通常跟一段框起来的提示:“Looks like Playwright was just installed or updated. Please run the following command to download new browsers”。这是运行期按预期路径找不到可执行文件,典型成因是升级了 Playwright 却没重装浏览器,或者安装期设了 PLAYWRIGHT_BROWSERS_PATH 而运行期没设。网络这时候是通的,改代理没有任何用。

下载完成、启动却失败。 install 之后代码还会调 validateHostRequirementsForExecutablesIfNeeded,失败时以 Playwright Host validation warning 的形式打出来。这属于系统依赖缺失,方向是 install-deps(Linux 上先用 --dry-run 看缺哪些包),不是下载来源。

Chrome / Edge 启动被拦。 前面那条企业策略的 warning 归这一类,文档已经说明它在项目范围之外;此时切回自带的 Chromium 通常比继续调网络参数更快。

最后提醒一句:这几个环境变量与 CLI 选项的名字、默认值都写在持续演进的代码里,本文只是把当前仓库里的语义翻给你看,具体以仓库最新内容为准。


本文依据 github.com/microsoft/playwright 仓库于 2026-08-18 的公开内容整理, 事实来自仓库内的文档与源码。我们没有对文中涉及的功能做过实测, 因此不涉及运行速度、稳定性与实际表现的任何描述。 该项目迭代频繁,文中涉及的 API 签名、配置项与默认值随版本变动,请以仓库最新内容为准。 本文不涉及浏览器版本矩阵与版本清单,相关信息请以官方发布说明为准。

安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。