首页
/ Playwright Python 入门实战指南:Library 模式的安装、同步/异步 API、REPL 调试与 PyInstaller 打包

Playwright Python 入门实战指南:Library 模式的安装、同步/异步 API、REPL 调试与 PyInstaller 打包

2026-09-06 19:06:15作者:温艾琴Wonderful

Playwright 是一套用单一 API 驱动 Chromium、Firefox 与 WebKit 的 Web 自动化与端到端测试框架。本文基于开源仓库中的 Library 快速上手文档,聚焦"以 Python 库(Library)方式直接使用 Playwright"这一路径——即不依赖 pytest 插件、自行在 Python 脚本中启动浏览器并操控页面。读完本文,你将掌握 Python 端的完整安装流程(pip / Poetry / uv)、同步与异步双 API 的正确用法、REPL 下的交互式实验技巧、PyInstaller 单文件打包方案,以及 time.sleep、Windows 事件循环、多线程等典型坑位的规避方法。

说明:本文引用的文档位于本仓库 docs/src 目录,仓库版本为 1.64.0-next(见根目录 package.json)。仓库本身主要承载 Playwright 的核心实现(packages/playwright-corepackages/playwright)与多语言文档源,Python 客户端通过内置 driver 与这些核心服务通信,因此文中会交叉引用核心源码作为底层依据。

两种 Python 使用方式:Library 与 Pytest 插件

Python 开发者使用 Playwright 通常有两条路线,官方在 Python 入门文档 中做了区分:

  • Library(库模式):直接 import playwright,在自己的 Python 脚本中显式管理浏览器、上下文与页面的创建和销毁。本文 关联文档 即以此为讲解对象,适合写脚本、做爬虫/采集、开发内部自动化工具,或希望完全掌控自动化流程的场景。
  • Pytest 插件(pytest-playwright:官方推荐的端到端测试写法,为测试用例内置隔离的 page/context fixture、多浏览器配置与 Web-First 断言,需额外 pip install pytest-playwright(见 Python 入门文档的安装章节)。

两种方式共享同一套底层驱动与浏览器二进制,playwright install 安装的浏览器可被两者复用。本文只讨论 Library 模式,若你面向正式的端到端测试工程,建议另行阅读 运行测试文档Pytest 集成文档

安装 Playwright 与浏览器

用你喜欢的包管理器安装 Python 包

原文档针对 pip、Poetry、uv 三种主流工具分别给出了安装序列,本质都是三件事:升级包管理器自身、安装 playwright 包、执行 playwright install 下载浏览器。

pip(最常用)

pip install --upgrade pip
pip install playwright
playwright install

Poetry

poetry self update
poetry add playwright
playwright install

uv

uv self update
uv add playwright
playwright install

第三步 playwright install 会默认下载 Chromium、Firefox 与 WebKit 三个内核的浏览器二进制(同时包含 ffmpeg 等附随组件)。本仓库 packages/playwright-core/browsers.json 中记录了默认安装清单:chromiumchromium-headless-shellfirefoxwebkitffmpeginstallByDefault 均为 true,可由此核实"默认安装哪些浏览器"这一行为;需要定制时参考官方 浏览器安装参数文档

浏览器二进制下载的进阶控制

playwright install 支持更细粒度的参数与若干环境变量,常见实用场景如下(完整列表见 浏览器管理文档):

  • 只安装特定内核:playwright install chromium / playwright install webkit / playwright install firefox
  • 安装系统级依赖(适合 CI/纯净 Linux 环境):playwright install-deps,可与浏览器安装合并为 playwright install --with-deps chromium
  • 通过 HTTPS_PROXY 走代理下载:HTTPS_PROXY=https://192.0.2.1 playwright install
  • 通过 PLAYWRIGHT_DOWNLOAD_HOST 从内网制品仓库下载,也支持按浏览器单独指定(PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST 等)并优先于全局变量;
  • 指定浏览器存放位置:PLAYWRIGHT_BROWSERS_PATH=$HOME/pw-browsers playwright install(安装与运行脚本时需使用同一变量值)。不设置时,Linux/macOS/Windows 下浏览器默认分别放入 ~/.cache/ms-playwright~/Library/Caches/ms-playwright%USERPROFILE%\AppData\Local\ms-playwright
  • 跳过浏览器下载(由外部统一管理二进制):PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
  • 卸载本安装的浏览器:playwright uninstall,跨安装全部清理加 --all

值得说明的是,浏览器管理文档 还指出:Playwright 在"浏览器安装与脚本执行"等环节依赖其捆绑的 Node.js 运行时,如需改用系统预装的 Node.js,可设置 PLAYWRIGHT_NODEJS_PATH 指向具体 node 可执行文件。这条规则同样适用于 Python 端运行 playwright install 的场景。

第一个 Python 脚本:同步 API 起步

安装完成后,在 Python 脚本中 import playwright 并启动三种浏览器中的任意一种(chromiumfirefoxwebkit)即可工作。同步 API 的最小示例:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://playwright.dev")
    print(page.title())
    browser.close()

这段代码的语义结构值得拆解:

  • with sync_playwright() as psync_playwright() 是全局入口,with 语句负责启动与收尾 Playwright driver 进程;
  • p.chromium.launch():显式启动一个浏览器实例;
  • browser.new_page():创建页面(建议正式的自动化任务改用 browser.new_context() 建立隔离的 BrowserContext,再 new_page,参见 BrowserContext 文档);
  • page.goto(...)page.title():导航并读取页面标题;
  • browser.close():结束后显式关闭浏览器。

为什么同步 API 也"看起来像异步":driver 子进程机制

Python 同步 API 并非单纯把异步方法包一层,而是基于"Playwright 把 driver 放在子进程中运行"这一架构。从已知问题一节(下文详述)可知:Python 端通过子进程与 driver 通信,driver 内部再与浏览器内核对接。这也解释了为什么在 Windows 上 asyncio 必须使用支持异步子进程的 ProactorEventLoop。仓库侧对应的服务端实现位于 packages/playwright-core/src/server,例如浏览器类型的启动入口 browserType.ts(含 headless 默认值为 true 的解析逻辑),Python/Node 各语言客户端都通过 dispatcher 层与其通信。

同步与异步双 API:asyncio 项目用 async_api

Playwright Python 同时提供同步与异步两套几乎一一对应的 API。若项目基于 asyncio(现代异步 Python 的主流选择),官方建议使用异步 API:

import asyncio
from playwright.async_api import async_playwright

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()
        await page.goto("https://playwright.dev")
        print(await page.title())
        await browser.close()

asyncio.run(main())

两套 API 的核心差异总结:

对比项 sync_api async_api
导入方式 from playwright.sync_api import sync_playwright from playwright.async_api import async_playwright
使用上下文 with sync_playwright() as p: async with async_playwright() as p:
方法调用 直接调用,如 page.goto(url) 全部需要 await,如 await page.goto(url)
适用场景 普通脚本、REPL、单元式快捷实验 基于 asyncio 的现代项目、与异步生态混用

第一个实战脚本:用 WebKit 截图

继续原文档的经典演练——用 WebKit 访问 https://playwright.dev/ 并保存页面截图:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.webkit.launch()
    page = browser.new_page()
    page.goto("https://playwright.dev/")
    page.screenshot(path="example.png")
    browser.close()

运行后将得到当前目录下的 example.pngpage.screenshot(path=...) 是调试与文档化最常用的能力之一,截图时 Playwright 会自动等待页面加载、执行必要的布局,更多截图细节(整页截图 full_page、区域截图、元素截图等)见 截图指南

headless 与 slow_mo:让浏览器"看得见、走得慢"

默认情况下 Playwright 以无头(headless)模式运行浏览器,方便 CI。若需要观察浏览器 UI(例如排查布局或验证交互效果),在 launch() 时显式关闭 headless,并用 slow_mo 放慢每一步操作的执行速度:

firefox.launch(headless=False, slow_mo=50)

参数含义与取值:

  • headless=False:以有头模式启动,弹出真实浏览器窗口;不传时默认 True。服务端解析可印证默认值逻辑见 browserType.ts
  • slow_mo=50:每次操作间隔 50 毫秒(示例值,可按需调整),便于肉眼跟踪脚本执行的每个动作;该参数对所有支持的操作生效,是演示与排错利器。

更深度的调试工具(Playwright Inspector、PWDEBUG、Trace Viewer 等)属于独立专题,详见 调试指南——文档中给出 Python 端通过 PWDEBUG=1 pytest -s 进入调试模式的用法。

交互式实验:同步 REPL 与 asyncio REPL

不想写完整脚本时,可以直接在 Python REPL 中启动 Playwright 做快速验证。

普通 REPL(同步 API):直接运行 python,然后逐步执行:

from playwright.sync_api import sync_playwright
playwright = sync_playwright().start()
# Use playwright.chromium, playwright.firefox or playwright.webkit
# Pass headless=False to launch() to see the browser UI
browser = playwright.chromium.launch()
page = browser.new_page()
page.goto("https://playwright.dev/")
page.screenshot(path="example.png")
browser.close()
playwright.stop()

注意这里不再使用 with,而是显式调用 .start().stop() 管理 Playwright 的生命周期。

asyncio REPL(异步 API):运行 python -m asyncio 进入支持顶层 await 的交互环境:

from playwright.async_api import async_playwright
playwright = await async_playwright().start()
browser = await playwright.chromium.launch()
page = await browser.new_page()
await page.goto("https://playwright.dev/")
await page.screenshot(path="example.png")
await browser.close()
await playwright.stop()

python -m asyncio 模式省去了每次手写 asyncio.run(main()) 的样板代码,在临时探索选择器、验证定位策略时非常高效。

用 PyInstaller 打成独立可执行文件

Playwright 可以与 PyInstaller 配合,把脚本打包成不带 Python 环境也能运行的独立可执行程序。原文档给出的打包入口脚本如下:

# main.py
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://playwright.dev/")
    page.screenshot(path="example.png")
    browser.close()

不捆绑浏览器的普通打包

若目标机器已单独安装过 Playwright 浏览器(或能从共享路径读取,见上文 PLAYWRIGHT_BROWSERS_PATH),只需打包应用本身:

pyinstaller -F main.py

-F 表示生成单一可执行文件。

把浏览器一起打进可执行文件

如果要让产物"开箱即用"、不依赖目标机器上的任何 Playwright 浏览器,可以在打包前用 PLAYWRIGHT_BROWSERS_PATH=0 让浏览器二进制以密闭(hermetic)方式落入本地位置,再执行打包。官方文档给出的三个平台写法:

bash

PLAYWRIGHT_BROWSERS_PATH=0 playwright install chromium
pyinstaller -F main.py

Windows 命令提示符(batch)

set PLAYWRIGHT_BROWSERS_PATH=0
playwright install chromium
pyinstaller -F main.py

PowerShell

$env:PLAYWRIGHT_BROWSERS_PATH="0"
playwright install chromium
pyinstaller -F main.py

:::note 官方提示 把浏览器一起捆绑进可执行文件会让产物体积显著变大,因此建议只捆绑你实际用到的浏览器(如示例中只装了 chromium),而非全部三种内核。 :::

已知问题与规避方案

原文档以"已知问题"为标题罗列了四类高频坑,理解它们背后的机制比死记规则更重要。

time.sleep() 会导致状态陈旧:改用 page.wait_for_timeout()

不要手动 sleep——Playwright 在每次动作前都内置了可自动等待的 actionability 检查(见 自动等待文档:元素需可见、稳定、能接收事件、可用等)。如果确实需要等待,使用 page.wait_for_timeout(5000) 而非 time.sleep(5)

page.wait_for_timeout(5000)   # 推荐:经 Playwright 内部通道调度
# time.sleep(5)               # 不推荐

原因在于 Playwright 内部依赖异步操作完成页面通信与协议消息处理;time.sleep 会阻塞当前线程的事件处理,使这些内部异步任务无法被正确消化,导致读取到陈旧状态。仓库侧的参考实现可见 frameDispatcher.tsframes.tswaitForTimeout 通道:它以 Promise + 定时器在服务端等待,同时保持对页面关闭/Frame 分离等状态的响应,这正是与进程级 time.sleep 的本质区别。

即便要用等待,也应优先依赖自动等待或显式的条件等待(如 page.wait_for_selectorexpect 轮询断言),把固定超时等待仅作为调试手段。

Windows 上与 asyncio 的 SelectorEventLoop 不兼容

Playwright 将 driver 作为子进程运行,因此要求 asyncio 使用支持异步子进程的 ProactorEventLoop,而 Windows 默认的 SelectorEventLoop 不支持异步子进程。

  • 在 Windows Python 3.8+ 上,ProactorEventLoop 本就是默认事件循环,通常无需处理;
  • 在 Windows Python 3.7 上,Playwright 会主动把默认事件循环设置为 ProactorEventLoop(即把 3.8+ 的默认行为向前兼容到 3.7)。

若自定义了事件循环策略并遇到子进程相关错误,请检查是否将事件循环策略改成了 Selector 系。

线程安全:API 不是线程安全的

Playwright 的 API 不保证线程安全。多线程环境中,正确保用姿势是每个线程创建独立的 playwright 实例,避免共享浏览器/页面对象跨线程访问(更详细的讨论可参见官方 issue playwright-python #623)。这与 BrowserContext 的隔离设计(每个上下文对应独立的浏览器状态)一脉相承——隔离不是可选项,而是多线程并发的硬性要求。

取消 asyncio 任务会产生未定义行为

取消正在执行 Playwright 调用的 task 不被支持,会引发未定义行为。如果一个操作需要比它的调用者活得更久,应当:

  1. 把它放进一个独立的 task 中运行;
  2. asyncio.shield() 保护它,避免外层取消波及。

从 Library 继续深入:下一步阅读地图

library-python.md 为起点,可将能力半径逐步扩大到以下主题:

  • 浏览器管理进阶:按内核安装/卸载、系统依赖、代理下载、浏览器缓存目录与 GC 清理,见 browsers.md
  • 定位器与动作:从"能跑通脚本"迈向"写出稳定可靠的自动化逻辑",优先阅读 定位器指南自动等待机制
  • 上下文与隔离:理解 new_context()、多页面管理及 storage state,见 BrowserContext 文档浏览器上下文概念
  • 调试:Inspector、PWDEBUG、Trace Viewer、慢动作演示,见 debug.md
  • 走向正式测试工程:Library 适合脚本化自动化;若你的目标是从零搭建可维护的端到端测试套件,则应切换为 pytest 插件路线,从 Python 入门文档测试运行文档 开始。
登录后查看全文
热门项目推荐
相关项目推荐