ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Playwright 国内手动安装 Chromium 指南:镜像源加速与依赖排查

Playwright 国内手动安装 Chromium 指南:镜像源加速与依赖排查 1. Playwright 的浏览器管理机制以及它为什么让国内用户抓狂1.1 浏览器下载并非下载一个 exe那么简单用 Playwright 做自动化测试的人大概率都遇到过这个场景pip install playwright或者npm install playwright/test很快就装完了然后跑playwright install chromium的时候进度条像蜗牛一样最后直接给你报一个 timeout。更气人的是官方网站默认你置身于海外网络环境从来没有考虑过国内开发者怎么把这个 150MB 左右的 Chromium 包顺利拉下来。很多人把playwright install chromium理解成下载一个浏览器安装包然后像装软件一样装进系统。其实 Playwright 的做法完全不同。它不需要你系统里装过 Chromium而是下载一个定制构建版的 Chromium解压到用户缓存目录里然后由 Playwright 内部直接调用这个可执行文件。这个目录在 Linux/macOS 下默认是~/.cache/ms-playwrightWindows 下是%USERPROFILE%\AppData\Local\ms-playwright。真正让手动安装这件事变得复杂的是版本匹配机制。Playwright 每一个版本都绑定一组固定的浏览器构建号build id。比如你在缓存目录里看到的chromium-1140这个1140就是 Chromium 构建号。它和 Chromium 的正式版本号比如 120.x不是一回事是 Playwright 自己维护的编号。你升级 Playwright 之后它需要找的构建号也变了目录名也随之改变旧的目录并不会被复用。这个机制决定了手动安装不能随便装个系统 Chromium 就完事。你必须有和当前 Playwright 版本严格对应的那个构建包否则launch()时它会按固定路径去找.../chromium-1140/chrome-linux/chrome找不到就报Executable doesnt exist。这是很多新手栽跟头的地方——以为系统装了 Chrome 就能跑 Playwright结果照样报错。1.2 国内网络环境下自动安装的真实失败原因自动安装流程看起来很简单下载 zip - 解压 - 写标记文件。但这个 zip 包从哪里来Playwright 官方默认从境外的 CDN 下载国内直连通常会有两个问题。一是网络绕路导致速度极慢。大文件传输在跨区域链路下经常被限制到几十 KB/s一个 Chromium 包几十到一百多 MB按这个速度要等半个小时甚至更久。二是连接不稳定下载到一半断了客户端不会智能续传直接失败重来。于是你看到的现象就是npx playwright install chromium跑了好几分钟进度条几乎不动然后报Connection lost或者直接超时。更恶心的是失败后它不会清理已下载的临时文件下次再跑又从零开始甚至因为残留文件导致校验不过陷入死循环。对国内开发者来说与其跟这个自动流程较劲不如手动干预控制下载源、控制下载方式、控制存放位置。我要先说一句结论手动安装并不等于自己从零编译 Chromium而是把下载环节从 Playwright 的默认流程里拆出来换成你能掌控的方式。理解这一点后面所有步骤就顺理成章了。2. 手动安装的前置准备先看清 Playwright 要什么版本2.1 通过 dry-run 拿到浏览器构建号动手之前你首先得知道当前项目里的 Playwright 到底需要哪个构建号的 Chromium。最简单的方式是看错误信息里的路径提示但最可靠的方式是主动查询。在 Node 项目里运行npx playwright install --dry-run chromium这个命令不会真正下载任何东西而是把当前装好的 Playwright 对应的 Chromium 版本、下载地址、缓存目录路径等信息打印出来。输出里通常能看到类似chromium-1140这样的关键字这就是构建号。如果你用的是 Python 版 Playwright对应的命令是python -m playwright install --dry-run chromium另外一个很实用的路子是直接查看playwright-core里的browsers.json文件。比如在 Node 环境里node -e const b require(playwright-core/browsers.json); console.log(b.browsers.find(x x.name chromium));里面会有revision字段那个数字就是构建号。很多网上教程直接告诉你下载 chromium-1140但你的 Playwright 版本可能不是 1.4x 系列构建号自然不同。以 dry-run 输出为准不要在版本号上想当然。2.2 三条手动安装路径的取舍拿到构建号之后你面前有三条路方案原理适用场景难度A换国内镜像源跑 install环境变量指向镜像站下载交给 Playwright 完成能联网只想加速低B手动下载 zip 解压到缓存自己用下载工具拉包解压到指定目录离线内网、需要断点续传、完全可控中C复用系统 Chrome/Chromium不走 Playwright 内置浏览器直接调系统浏览器快速验证、磁盘紧张低这里给出决策逻辑你的网络能通但慢选 A完全没外网选 B不想下载或者公司强制用系统浏览器选 C。如果一开始没头绪我建议无脑从 A 开始它最省事也最容易验证。B 和 C 作为备选方案后面我会把细节全部展开。3. 国内加速手动装 Chromium 的完整实操3.1 方案 A换镜像源后重新跑 install所谓国内加速最优雅的做法不是自己手动下载而是让 Playwright 从国内镜像下载。社区里最常用的镜像就是 npmmirror原淘宝 npm提供的 Playwright 浏览器镜像路径规则和官方 CDN 保持一致你只需要把环境变量指过去。先删掉之前可能残留的失败目录避免校验干扰# Linux / macOS rm -rf ~/.cache/ms-playwright/ # Windows PowerShell Remove-Item -Recurse -Force $env:USERPROFILE\AppData\Local\ms-playwright然后设置环境变量# Linux / macOS临时生效 export PLAYWRIGHT_DOWNLOAD_HOSThttps://npmmirror.com/mirrors/playwright # Windows PowerShell $env:PLAYWRIGHT_DOWNLOAD_HOSThttps://npmmirror.com/mirrors/playwright接着安装 Chromium# Node 项目 npx playwright install chromium # Python 项目 python -m playwright install chromium这样 Playwright 会向https://npmmirror.com/mirrors/playwright/builds/chromium/{构建号}/chromium-linux.zip请求文件。镜像服务器在国内速度通常能跑到几 MB/s体感和直连相比完全是两回事。我实测在同一台机器上原本十几分钟都下不完的包换源后几分钟内搞定。如果你希望永久生效把PLAYWRIGHT_DOWNLOAD_HOST写进 shell 配置文件.bashrc/.zshrc或 Windows 环境变量里。CI 上则可以直接写在流水线的环境变量配置中。有个细节值得专门说npm 包本身也可以用国内镜像装。npm config set registry https://registry.npmmirror.com解决的是playwright这个 npm 包跟浏览器二进制下载是两回事。很多人在 npm 上配了镜像结果发现还是卡在浏览器下载就是因为没设置PLAYWRIGHT_DOWNLOAD_HOST。这两个镜像各自解决各自的问题不要混淆。3.2 方案 B完全手动下载 zip 并解压到缓存目录如果你的机器连镜像站也访问不了或者你需要在内网离线环境里部署那就只能走全手动路线。这个过程分四步找到 URL、下载、解压、放对目录。先确定下载 URL 结构它基本是固定的https://npmmirror.com/mirrors/playwright/builds/chromium/{构建号}/chromium-linux.zip如果构建号是 1140那就是https://npmmirror.com/mirrors/playwright/builds/chromium/1140/chromium-linux.zipLinux 平台对应chromium-linux.zipWindows 对应chromium-win.zipmacOS 对应chromium-mac.zip。跨平台不能混用不要图省事在 Linux 机器上解压 Windows 的包目录结构和可执行文件都不对跑到一半必然出错。下载时我建议用支持断点续传的工具比如wget -c https://npmmirror.com/mirrors/playwright/builds/chromium/1140/chromium-linux.zip # 或者用 aria2 多线程加速 aria2c -x 8 https://npmmirror.com/mirrors/playwright/builds/chromium/1140/chromium-linux.zip大文件下载过程中断掉是常态wget -c能续传aria2 还能多线程分块下载速度比单线程好很多。下载完成后把 zip 解压到 Playwright 的缓存目录里目录名必须严格是chromium-{构建号}mkdir -p ~/.cache/ms-playwright/chromium-1140 unzip chromium-linux.zip -d ~/.cache/ms-playwright/chromium-1140/此时目录结构应该是~/.cache/ms-playwright/chromium-1140/chrome-linux/chrome不要去掉中间那层chrome-linux。Playwright 查找可执行文件时按固定相对路径去找你把它展平反而找不到。这个细节我特意强调因为很多人解压后习惯把内层文件直接挪到外层结果launch()就一直报Executable doesnt exist。解压完成后建议手动创建一个安装完成标记文件。Playwright 在装完浏览器后会在目录里写一个INSTALLATION_COMPLETE之类的标记用于判断这个目录是否有效。手动解压时你绕过了官方安装流程这个标记没被创建有时 Playwright 会认为浏览器没装好于是又触发重新下载。可以这样补一个touch ~/.cache/ms-playwright/chromium-1140/INSTALLATION_COMPLETEWindows 下则是New-Item -ItemType File -Path $env:LOCALAPPDATA\ms-playwright\chromium-1140\INSTALLATION_COMPLETE如果你所在的环境不创建这个标记也能跑那就算了。但既然已经手动管理了多这一个空文件不亏能避免很多奇怪的问题。使用 Python 的读者需要注意Python Playwright 也遵循同样的ms-playwright缓存目录和标记文件规则所以上面这套手动解压步骤在 Python 项目里同样适用。如果你要把这套浏览器环境搬到离线机器上直接把整个ms-playwright目录打包带走tar czf playwright-browsers.tar.gz -C ~/.cache ms-playwright在目标机器上解压回原路径或者用PLAYWRIGHT_BROWSERS_PATH环境变量指向你解压后的目录export PLAYWRIGHT_BROWSERS_PATH/opt/ms-playwright这个变量在后续多项目共享和 CI 加速里也会反复用到建议记下来。3.3 方案 C复用系统 Chrome/Chromium绕开下载还有一条几乎零成本的路径如果你的机器上本来就有 Chrome 或 Chromium可以直接让 Playwright 使用系统浏览器连缓存目录都不需要。这也是热词里centos 7 环境的 chromium 浏览器安装最常见的替代思路——与其折腾 Playwright 专用包不如直接用系统里现成的。Node 项目里这样写const { chromium } require(playwright); (async () { const browser await chromium.launch({ channel: chrome, // 用系统 Chrome // 或者指定可执行文件绝对路径 executablePath: /usr/bin/google-chrome }); // ... })();Python 项目里这样写from playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch( channelchrome )这个方案的好处是省下载、省磁盘但它有前提你必须接受系统浏览器的版本不受你控制和 Playwright 测试预期不一定是严格匹配的那一版。日常写脚本验证功能完全够用但如果你在 CI 里要求版本锁定或者要用 Playwright 提供的协议级新特性还是建议走前两种方案。我自己只在本地快速调试脚本时用这个正式测试环境一律用 Playwright 自带的构建包。4. 装完 Chromium 之后系统依赖与 headless 启动检查4.1 install-deps 到底帮你装了什么很多人好不容易把 Chromium 下载解压好一跑launch()又报错。这次问题不在下载环节而在系统依赖库。Chromium 是一个完整的图形浏览器不是精简的 WebView。它运行时需要一堆动态库NSS、NSPr、ATK、CUPS、libdrm、libxkbcommon 等等。即使你用的是 headless 模式部分库依然必不可少因为 Headless Chromium 并不是完全不加载图形栈它还会用到部分图形相关的底层库。在联网机器上直接用官方命令装依赖最省心npx playwright install-deps chromium # 或者 python -m playwright install-deps chromium它会根据你的发行版自动调用apt或者yum安装全部依赖。注意这一步和下载浏览器是分开的。你换源解决了下载问题依赖库还是要单独装。很多人以为playwright install chromium就万事大吉结果 launch 时报missing dependencies其实就是漏了这一步。4.2 CentOS 7 环境下的依赖与启动验证在 CentOS 7 上部署时可能会遇到install-deps并不完全可靠的情况——CentOS 7 的软件源相对陈旧某些较新版本 Chromium 依赖的库版本不够。这时候就得手动装。常见缺失库和对应包名如下缺失的动态库对应的包libnss3.sonsslibnspr4.sonsprlibatk-1.0.so.0atklibatk-bridge-2.0.so.0at-spi2-atklibcups.so.2cups-libslibdrm.so.2libdrmlibXcomposite.so.1libXcompositelibXdamage.so.1libXdamagelibXfixes.so.3libXfixeslibXrandr.so.2libXrandrlibgbm.so.1mesa-libgbmlibasound.so.2alsa-liblibxkbcommon.so.0libxkbcommonCentOS 7 下可以先批量装一轮yum install -y nss nspr atk at-spi2-atk cups-libs libdrm \ libXcomposite libXdamage libXfixes libXrandr \ mesa-libgbm alsa-lib pango cairo libxkbcommon如果某个包在默认源里找不到libxkbcommon经常需要 EPEL可以用yum provides反查yum provides */libxkbcommon.so.0这比盲目查教程靠谱得多——系统缺哪个.so你就查哪个.so属于哪个包装上就是。有的包虽然在列表里但版本太老可能还需要更新或安装兼容层这种情况就按报错提示逐个解决。装完依赖后写一个最小的验证脚本确认整条链路没问题。Node 版const { chromium } require(playwright); (async () { const browser await chromium.launch({ headless: true }); const page await browser.newPage(); await page.goto(https://example.com); console.log(await page.title()); await browser.close(); })();Python 版from playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch(headlessTrue) page browser.new_page() page.goto(https://example.com) print(page.title()) browser.close()如果这一步能正常打印出页面标题说明浏览器安装、依赖、路径全部正确后面写用例就只是代码层面的事了。4.3 高频启动报错的排查链路我把自己实际遇到过的、以及在群里被问得最多的启动报错整理成一张表方便你对照快速定位报错关键字真实原因处理方式Executable doesnt exist at ...缓存目录里没有对应构建号的浏览器或者路径层级不对检查~/.cache/ms-playwright/chromium-{构建号}/chrome-linux/chrome是否存在不存在就走方案 A 或 B 重新安装Host system is missing dependencies ...系统缺少 Chromium 运行库跑install-deps或按 4.2 节手动装error while loading shared libraries: libnss3.so某个具体库缺失或版本太老用yum provides/apt-file search找到包名装上browserType.launch: Timeout启动超时常见于容器或配置太低的机器也可能是沙箱权限问题尝试chromium.launch({ args: [--no-sandbox] })同时确认/dev/shm是否过小关于沙箱权限这里多说一句。在 Docker 容器或没有 root 权限的环境里Chromium 经常因为无法创建 sandbox 而启动失败。如果只是本地自测可以加--no-sandbox参数绕开但正式 CI 环境建议在容器配置里处理好权限而不是长期关闭沙箱否则安全性是打折扣的。还有一种比较隐蔽的情况你更新了 Playwright但没重新安装浏览器。此时launch()会去找新构建号的目录而你的缓存里只有旧构建号于是照样报Executable doesnt exist。这种错误其实不是没装而是版本不匹配。下面专门说这个。5. 版本配套、缓存迁移与日常维护5.1 浏览器与 Playwright 版本的对应关系Playwright 的版本和 Chromium 的构建号是一一对应的。比如某个 1.4x 版本对应chromium-1140某个更新版本对应更高的编号具体可以在browsers.json里查到。升级 Playwright 之后旧的构建包不会被自动删除新的构建包也不会自动下载。也就是说升级后要重新跑一次安装命令否则测试会莫名其妙的失败。这里有个实际教训我有一次升级了playwright/test到新版本没有重新安装浏览器结果跑了半天全部用例都报Executable doesnt exist。查了半天发现是构建号从旧编号变成了更高的编号旧目录还在但 Playwright 已经不去找它了。不要试图把旧目录改名成新构建号Chromium 构建之间可能有二进制格式差异硬改名大概率还是跑不起来。正确的做法是升级之后顺手执行npx playwright install chromium配合镜像源这个操作的成本几乎可以忽略。所以我建议项目里的 package.json 或者 CI 脚本里显式固定 Playwright 版本同时把浏览器安装步骤做成每次部署的必经环节避免版本漂移。5.2 多项目公共缓存与 CI 加速当你手上有多个 Playwright 项目或者团队里有多个成员一起开发时浏览器重复下载是巨大的浪费。建议用一个共享目录统一管理export PLAYWRIGHT_BROWSERS_PATH/opt/ms-playwright然后所有项目、所有成员的playwright install和运行时launch()都会读写这个目录。第一次有人装好后面的人直接跳过下载环节。在 CI 里这个思路更实用。你可以提前把浏览器打进基础镜像或者在流水线上把ms-playwright目录设为缓存路径每次跑测试就能省掉几分钟下载时间。我第一次在 CI 里这样做之后整个 Job 的耗时从 8 分钟降到 3 分钟省出来的时间都用在真正的测试执行上。需要提醒的是共享目录的权限要注意。如果多人都会执行 install建议用专门的账号或者保证目录可写否则有人装不上又开始走老路反复下载这就违背了共享的初衷。清理旧版本也是一件值得做的事。构建号数字大的新目录会不断产生旧目录可能占用几个 GB 磁盘。定期看一下~/.cache/ms-playwright或自定义的共享目录确认项目不再使用某个构建号后把对应目录删掉即可。判断依据很简单目录名上的数字就是构建号和当前browsers.json对不上、项目里也不再引用的就可以清理了。5.3 关于装完浏览器不等于测试稳了的一点体会最后说点安装之外的事情。很多人以为浏览器装好Playwright 就能畅通无阻了。实际跑起来还是会遇到各种和安装无关、但同样让新手劝退的问题页面里嵌入了复杂的数据校验、滑块验证、登录态验证甚至更变态的运行时环境检测。这里我不展开讲某个具体的技术对抗手段因为那个话题单独写一篇都不够。我只想说你看到的那些Playwright 过滑块Playwright 处理动态 iframe之类的经验分享前提都是浏览器能正常启动。安装问题和页面问题是两座山先把第一座翻过去才有资格去研究第二座。我现在的做法是把所有 Playwright 项目的浏览器安装收口到一个脚本里。脚本内部设置好PLAYWRIGHT_DOWNLOAD_HOST、PLAYWRIGHT_BROWSERS_PATH再执行 install。新同事入职、CI 重建镜像、换一台服务器都只需要跑同一个脚本再也不用解释第二遍为什么你下载了 20 分钟最后还失败了。这个习惯也是我推荐给你的——手动安装 Chromium 这件事值得一次性做对、做成脚本然后彻底忘掉它。之后的每一次调试、每一个用例报错都发生在干净的浏览器环境里你才有精力去处理真正有价值的问题。最后分享一个我自己一直在用的小技巧如果你不放心手动解压的目录是否完整可以在解压完成后直接执行一次目录内浏览器的版本探测~/.cache/ms-playwright/chromium-1140/chrome-linux/chrome --version只要它能输出 Chromium 的版本号就说明可执行文件这个层面已经没问题了。剩下的依赖问题再用launch()脚本去验证。这个两步验证法能让你在排查问题时少走不少弯路。
返回列表