Playwright Python:现代浏览器自动化
Playwright Python:现代浏览器自动化入门与实战
为什么选择 Playwright?
Playwright 是由微软开发的开源自动化测试框架,能够以单一 API 驱动 Chromium、Firefox 和 WebKit 浏览器。与 Selenium 相比,Playwright 原生支持自动等待(Auto-waiting)、强大的选择器引擎和现代 Web 特性(如 Shadow DOM、Service Workers),无需额外工具即可处理单页应用和复杂交互。它在执行速度、稳定性和跨浏览器一致性方面表现卓越,是当今自动化测试和网页抓取的首选方案。
环境准备与安装
系统要求
- Python 3.8 或更高版本
- 操作系统:Windows、macOS、Linux(包括 ARM 架构的树莓派)
安装 Playwright 库
pip install playwright
安装浏览器引擎
Playwright 需要下载浏览器二进制文件(Chromium、Firefox、WebKit),执行如下命令:
playwright install
此操作会将浏览器安装到 Playwright 的缓存目录,如果希望系统识别已安装的 Chrome/Edge 等,可参考后续配置。
第一个自动化脚本
创建 test.py 文件,编写以下代码:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False) # 设置为 False 可看到浏览器界面
page = browser.new_page()
page.goto('https://playwright.dev/')
print(page.title())
browser.close()
使用 python test.py 运行,你会看到浏览器打开并输出页面标题。
同步与异步模式
Playwright 提供了同步(sync_api)和异步(async_api)两套 API。同步模式代码简洁,适合脚本编写;异步模式适合集成到异步 Web 框架中,能发挥更高的并发性能。异步示例:
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())
Playwright 核心概念与代码片段
浏览器、上下文与页面
- Browser:浏览器实例,可通过
p.chromium.launch()创建。 - BrowserContext:隔离的浏览器会话,类似隐身窗口。不同上下文之间不共享 Cookie、localStorage。使用
browser.new_context()创建。 - Page:单个标签页或窗口,所有交互都基于 Page 对象。
上下文的使用可以模拟多登录状态,同时运行多个独立测试。
context = browser.new_context(locale='zh-CN') # 设置语言
page = context.new_page()
选择器与定位元素
Playwright 提供了多种内置定位方式,推荐使用 page.locator() 和 page.get_by_*() 方法,它们内置自动等待并支持链式操作。
基础定位方法
# 通过文本内容
page.get_by_text("提交")
# 通过角色(无障碍属性)
page.get_by_role("button", name="登录")
# 通过标签和属性
page.get_by_label("用户名")
page.get_by_placeholder("请输入密码")
# 通过测试 ID
page.get_by_test_id("submit-btn")
# CSS 与 XPath 仍可使用,但推荐上述语义化方法
page.locator("css=button.primary")
page.locator("xpath=//button[@type='submit']")
链式与过滤
row = page.get_by_role("listitem").filter(has_text="Playwright")
row.locator(".delete-btn").click()
交互操作:点击、输入与键盘
所有交互都会自动等待元素可操作(可见、启用、无动画遮挡)。
# 导航
page.goto("https://example.com")
# 点击
page.get_by_text("开始使用").click()
# 输入文本(默认先清空并键入)
page.get_by_placeholder("邮箱").fill("user@example.com")
# 逐字输入(模拟真实打字)
page.get_by_placeholder("邮箱").type("user@example.com", delay=100)
# 键盘操作
page.keyboard.press("Enter")
page.keyboard.press("Control+A")
# 复选与单选框
page.get_by_label("我同意").check()
page.get_by_role("radio", name="个人用户").click()
提取数据与断言
直接从 Page 或 Locator 提取文本、属性以及 HTML。
# 提取单个文本
heading = page.get_by_role("heading").text_content()
# 提取属性
link = page.get_by_role("link").get_attribute("href")
# 提取多个元素
texts = page.locator(".item").all_text_contents()
# 使用断言(需安装 pytest 并配合 Playwright 断言)
from playwright.sync_api import expect
expect(page.get_by_text("操作成功")).to_be_visible()
expect(page).to_have_title("预期标题")
自动化等待机制
Playwright 的自动等待体现在:
- 操作前自动等待:点击、输入等动作会等待元素出现并达到可操作状态。
- 断言自动重试:
expect()会持续检查直到条件满足或超时。 - 显式等待:需要等待特定状态时使用
wait_for系列方法。
# 等待网络安静(无请求持续500ms以上)
page.wait_for_load_state("networkidle")
# 等待特定元素可见
page.locator(".result").wait_for()
# 等待下载事件
with page.expect_download() as download_info:
page.get_by_text("下载报告").click()
download = download_info.value
download.save_as("report.pdf")
处理弹窗、对话框与多页面
对话框
自动取消或确认 JavaScript 对话框:
page.on("dialog", lambda dialog: dialog.accept())
page.get_by_text("删除").click()
新标签页
with page.expect_popup() as popup_info:
page.get_by_text("打开新窗口").click()
new_page = popup_info.value
new_page.wait_for_load_state()
print(new_page.title())
截图、录像与追踪
调试复杂场景时,Playwright 的可视化诊断功能非常强大。
# 截图
page.screenshot(path="screenshot.png", full_page=True)
# 录像(上下文级别)
context = browser.new_context(record_video_dir="videos/")
page = context.new_page()
# ... 执行操作 ...
context.close() # 视频自动保存
# 追踪(Trace Viewer)
browser = p.chromium.launch()
context = browser.new_context()
context.tracing.start(screenshots=True, snapshots=True)
page = context.new_page()
# ... 执行操作 ...
context.tracing.stop(path="trace.zip")
使用 playwright show-trace trace.zip 命令打开图形化界面,回放每一步截图、DOM 快照和日志。
高级配置与技巧
绕过反自动化检测
许多网站会检测自动化工具,Playwright 通过修改启动参数和上下文设置降低检测风险。
browser = p.chromium.launch(
headless=False,
args=["--disable-blink-features=AutomationControlled"]
)
context = browser.new_context(
viewport={"width": 1920, "height": 1080},
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ..."
)
page.add_init_script("""
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
""")
使用已安装的浏览器
如果你希望复用系统装的 Chrome 或 Edge,可以使用 channel 参数:
browser = p.chromium.launch(channel="chrome") # 或 "msedge"
注意需要先通过 playwright install chrome 或 playwright install msedge 安装 Playwright 的驱动适配。
并行与性能
异步 API 配合 asyncio.gather 可以同时运行多个浏览器实例,大幅提升抓取或测试效率。对于大量页面,可使用 context.new_page() 而非创建多个上下文,以减少内存开销。
完整示例:表单提交与结果验证
以下示范一个典型的搜索提交并检查返回结果的流程:
from playwright.sync_api import sync_playwright
from playwright.sync_api import expect
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context(locale="zh-CN")
page = context.new_page()
page.goto("https://www.google.com")
# 处理 Cookies 同意弹窗
try:
page.get_by_text("接受全部").click(timeout=3000)
except:
pass
# 执行搜索
page.get_by_label("搜索", exact=True).fill("Playwright Python")
page.keyboard.press("Enter")
# 等待结果加载
first_result = page.locator("h3").first
expect(first_result).to_be_visible()
print(first_result.text_content())
# 验证标题包含搜索词
expect(page).to_have_title("Playwright Python - Google 搜索")
browser.close()
测试集成与 CI 建议
- Playwright 与
pytest深度集成,通过pytest-playwright插件可提供page,browser等夹具。 - 在 Docker 中运行:
docker run -it mcr.microsoft.com/playwright/python:v1.XX-jammy - 无头模式下推荐使用
--headless=new参数,避免云环境图形依赖问题。
常见问题排查
- 元素找不到:使用
page.pause()进入交互调试模式,或开启PWDEBUG=1环境变量。 - 网络超时:通过
page.set_default_timeout(60000)调整,或对特定操作设置 timeout 参数。 - 浏览器未自动下载:手动执行
python -m playwright install chromium。
Playwright Python 凭借简洁的 API、卓越的可靠性和丰富的调试工具,极大降低了浏览器自动化的门槛。掌握本文基础后,推荐阅读官方文档了解网络拦截、模拟移动设备、身份验证等高级主题,在真实项目中实践。