Python Playwright 脚本打包为独立 Windows EXE 含浏览器内核
如何将 Python Playwright 脚本连同 Chromium 浏览器内核打包成独立的 Windows EXE 文件。通过修改代码动态定位浏览器路径,并使用 PyInstaller 配合 PowerShell 脚本进行构建,解决了浏览器二进制文件依赖问题,实现了零依赖分发。

如何将 Python Playwright 脚本连同 Chromium 浏览器内核打包成独立的 Windows EXE 文件。通过修改代码动态定位浏览器路径,并使用 PyInstaller 配合 PowerShell 脚本进行构建,解决了浏览器二进制文件依赖问题,实现了零依赖分发。

在开发自动化工具或定制化浏览器时,我们经常使用 Python 的 Playwright 库。但如果要将工具分发给非技术用户,要求对方安装 Python 环境、下载对应版本的浏览器内核是非常痛苦的。
本文介绍一种方案:将 Python 代码、Playwright 依赖库以及 Chromium 浏览器内核全部打包进一个独立的 .exe 文件中,实现真正的'零依赖'运行。
Playwright 默认将浏览器二进制文件下载到用户目录(如 %AppData%)。在打包时,我们需要解决两个核心问题:
test-01.py)我们需要在代码中动态检测当前是否在 PyInstaller 的打包环境中运行。如果是,则将环境变量 PLAYWRIGHT_BROWSERS_PATH 指向解压后的临时目录(sys._MEIPASS)。
此外,为了更好的用户体验,我们增加了错误捕获:如果程序崩溃(特别是在无控制台模式下),会弹出 Windows 错误对话框,而不是直接静默退出。
import argparse
import os
from pathlib import Path
import sys
import time
import traceback
from playwright.sync_api import sync_playwright
SUPPORTED_DEFAULT_DEVICE = "Pixel 5"
def resolve_browser_root() -> Path | None:
"""
核心逻辑:定位浏览器路径
1. 如果是打包环境,资源位于 sys._MEIPASS 下的 ms-playwright 目录
2. 如果是开发环境,可能在环境变量指定位置、当前目录或系统默认目录
"""
candidates = []
# PyInstaller 解压临时目录
if hasattr(sys, "_MEIPASS"):
candidates.append(Path(sys._MEIPASS) / "ms-playwright")
# 手动环境变量
if os.environ.get("PLAYWRIGHT_BROWSERS_PATH"):
candidates.append(Path(os.environ["PLAYWRIGHT_BROWSERS_PATH"]))
# 当前目录或默认目录
candidates.append(Path.cwd() / "ms-playwright")
candidates.append(Path.home() / "AppData" / "Local" / "ms-playwright")
for c in candidates:
if c.exists():
return c
return None
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Launch Chromium in mobile emulation mode.")
parser.add_argument("--url", default="https://doris.apache.org", help="Page to open.")
parser.add_argument("--device", default=SUPPORTED_DEFAULT_DEVICE, help="Device profile name.")
parser.add_argument("--headless", action="store_true", help="Run in headless mode.")
parser.add_argument("--timeout", type=int, default=0, help="Auto-close timeout.")
return parser.parse_args()
def launch_mobile(url: str, device_name: str, headless: bool, timeout: int) -> None:
# 动态设置浏览器路径
browser_root = resolve_browser_root()
if browser_root:
os.environ["PLAYWRIGHT_BROWSERS_PATH"] = str(browser_root)
with sync_playwright() as p:
devices = p.devices
if device_name not in devices:
print(f"Unknown device: {device_name}")
sys.exit(1)
browser = p.chromium.launch(headless=headless)
# 忽略 HTTPS 证书错误,确保内网或测试环境可用
context = browser.new_context(ignore_https_errors=True, **devices[device_name])
page = context.new_page()
page.goto(url)
print(f"Opened {url} in mobile mode: {device_name}")
if browser_root:
print(f"Using bundled browsers at: {browser_root}")
# 保持运行
try:
if timeout > 0:
time.sleep(timeout)
else:
while True:
time.sleep(1)
except KeyboardInterrupt:
pass
finally:
browser.close()
def main():
try:
args = parse_args()
launch_mobile(args.url, args.device, args.headless, args.timeout)
except Exception:
# 错误处理:如果是打包环境(无控制台),弹窗提示错误
if getattr(sys, 'frozen', False):
import ctypes
ctypes.windll.user32.MessageBoxW(0, f"Error: {traceback.format_exc()}", "Application Error", 0x10)
else:
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()
build_exe.ps1)为了简化构建流程,我们编写一个 PowerShell 脚本。它的作用是:
ms-playwright-local,防止污染全局环境。--add-data 参数,将下载好的 ms-playwright-local 映射打包到 EXE 内部的 ms-playwright 路径。# build_exe.ps1
# 1. 确保安装依赖
Write-Host "Installing Python dependencies..."
pip install playwright pyinstaller
# 2. 设置本地下载路径,避免影响系统全局配置
$localBrowserPath = Join-Path (Get-Location) "ms-playwright-local"
$env:PLAYWRIGHT_BROWSERS_PATH = $localBrowserPath
# 3. 下载 Chromium 到本地文件夹
Write-Host "Downloading Chromium to $localBrowserPath..."
if (Test-Path $localBrowserPath) {
Remove-Item -Recurse -Force $localBrowserPath
}
# 这里会自动下载 Chromium
python -m playwright install chromium
# 4. 执行 PyInstaller 打包
Write-Host "Building EXE..."
# 关键参数解释:
# --windowed: 隐藏控制台窗口(适合 GUI 程序)
# --collect-all playwright: 自动收集 Playwright 的库文件
# --add-data "源路径;目标路径": 将浏览器文件夹打入包内
pyinstaller --noconfirm --onefile --windowed --name mobile_chromium `
--collect-all playwright `
--add-data "$localBrowserPath;ms-playwright" `
src02/test-01.py
Write-Host "Build complete! Output: dist/mobile_chromium.exe"
在项目根目录下,打开 PowerShell 运行:
.uild_exe.ps1
构建完成后,dist 文件夹下的 mobile_chromium.exe 就是我们需要的文件。你可以将其拷贝到任何 Windows 电脑上运行。
基本用法: 直接双击运行。
高级用法(命令行):
# 指定打开百度,模拟 iPhone 13
./mobile_chromium.exe --url https://www.baidu.com --device "iPhone 13"
最终效果:

exe 文件大小:

通过这种方式,我们成功将一个复杂的浏览器自动化环境(Python + Playwright + Chromium Binary)压缩成了一个数百 MB 的单文件 EXE,极大地降低了工具的分发和部署成本。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online