Playwright:新一代跨浏览器自动化

Python 办公自动化专题 · 更现代、更快、更可靠的浏览器自动化方案

专题:Python 自动化办公系统学习

关键词:Python, 自动化办公, Playwright, Web自动化, 浏览器, 跨浏览器, Chromium, Python自动化

一、Playwright概述

1.1 诞生背景

Playwright 是由微软在2020年初推出的开源跨浏览器自动化框架,由原 Puppeteer 团队成员开发。它继承了 Puppeteer 的优秀设计理念,但更进一步实现了对 Chromium、Firefox 和 WebKit 三大浏览器引擎的统一支持。与 Selenium 等传统自动化框架不同,Playwright 在设计之初就瞄准了现代 Web 应用的特点——SPA 单页应用、AJAX 动态渲染、Shadow DOM 等,提供了更加原生和可靠的自动化能力。自发布以来,Playwright 迅速成为 Web 自动化领域的重要力量,被广泛应用于端到端测试、网页爬虫、数据采集、自动化运维等场景。

1.2 与 Selenium 核心对比

对比维度PlaywrightSelenium
浏览器支持Chromium + Firefox + WebKit(原生支持)Chrome/Firefox/Safari/Edge(需对应 Driver)
自动等待内置自动等待机制,无需显式等待需要显式/隐式等待,否则易报 NoSuchElement
API 风格异步优先(Async/Await),同步模式可选同步为主,异步需额外封装
网络拦截原生 route API,支持 mock 和修改需通过 DevTools Protocol 或代理
安装复杂度pip install 一键安装浏览器需额外下载对应版本 Driver
速度更快(浏览器上下文隔离,无 Driver 通信开销)相对较慢
执行环境Browser Context 隔离,轻量级每个实例相对重型

1.3 核心优势详解

自动等待(Auto-Waiting):Playwright 在执行操作前会自动等待元素可见、可用(如等待按钮可点击),开发者无需手动添加 time.sleep 或 WebDriverWait。这一机制大幅减少了一类常见的自动化脚本不稳定问题。

多浏览器统一 API:同一套 API 可以无缝运行在 Chromium、Firefox 和 WebKit 上,实现真正的跨浏览器兼容性测试。这对于需要确保 Web 应用在 Chrome、Edge、Safari 等不同浏览器中行为一致的场景尤为重要。

网络拦截与模拟:Playwright 提供了强大的网络控制能力,可以拦截、修改、模拟任意网络请求和响应,特别适合测试边界条件、模拟后端异常、在无后端情况下进行前端测试。

浏览器上下文:每个测试或任务可以在独立的浏览器上下文中运行,上下文之间完全隔离(缓存、Cookies、LocalStorage 互不干扰),无需启动多个浏览器实例。

1.4 安装

# 安装 Playwright 核心库 pip install playwright # 安装 Chromium、Firefox、WebKit 浏览器(首次运行) playwright install # 仅安装 Chromium(节省磁盘空间) playwright install chromium

安装完成后,可以使用以下代码验证版本并启动浏览器。

import playwright from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=False) page = browser.new_page() page.goto("https://www.baidu.com") print(page.title()) browser.close()

要点提示:Playwright 提供了 sync_api(同步)和 async_api(异步)两套 API。同步 API 适合快速上手和简单脚本;异步 API 适合高并发场景和与其他异步框架集成。建议初学者先掌握同步 API,再根据需求升级到异步版本。

二、环境与配置

2.1 浏览器安装与管理

Playwright 允许开发者按需安装特定浏览器,无须依赖系统已安装的浏览器版本。通过命令行工具可以精细控制安装内容。安装后的浏览器位于用户目录下的 playwright 文件夹中,与系统浏览器完全隔离,避免版本冲突。

# 查看已安装的浏览器 playwright install --list # 安装所有支持的浏览器(约 500MB-1GB) playwright install # 安装特定浏览器 playwright install firefox playwright install webkit # 安装带系统依赖(Linux 环境) playwright install-deps

2.2 同步与异步 API 选择

Playwright 的同步 API 是最直观的入口,适合大多数脚本化场景。异步 API 则面向需要并发处理多个浏览器实例或与其他异步 I/O 操作配合的场景。二者的核心概念(Browser、Context、Page)完全一致,仅在调用风格上有所不同。

# 同步 API(推荐初学者使用) from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch() page = browser.new_page() page.goto("https://example.com") content = page.content() browser.close()
# 异步 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://example.com") content = await page.content() await browser.close() asyncio.run(main())

2.3 Browser、Context 与 Page 模型

Playwright 采用三层架构:Browser(浏览器实例)→ BrowserContext(浏览器上下文)→ Page(页面标签页)。每个 Browser 可以创建多个独立的 Context,Context 之间完全隔离(Cookies、缓存、LocalStorage 互不影响),每个 Context 下又可以管理多个 Page。这一设计使得多用户、多会话场景的模拟变得异常简单。

# 浏览器上下文隔离示例 from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch() # 上下文 A(模拟用户 A) context_a = browser.new_context() page_a = context_a.new_page() page_a.goto("https://example.com") page_a.evaluate("localStorage.setItem('user', 'A')") # 上下文 B(模拟用户 B,完全隔离) context_b = browser.new_context() page_b = context_b.new_page() page_b.goto("https://example.com") print(page_b.evaluate("localStorage.getItem('user')")) # 输出 None browser.close()

2.4 浏览器启动选项

Playwright 提供了丰富的启动参数,可以控制浏览器的头模式、窗口大小、代理、调试端口等。这些选项在开发和调试过程中非常有用。

# 常用浏览器启动选项 browser = p.chromium.launch( headless=False, # 有头模式(调试时可见) slow_mo=500, # 操作间延迟 500ms(便于观察) args=['--start-maximized'], # 启动参数 proxy={"server": "http://127.0.0.1:8080"}, # 代理设置 downloads_path="./downloads" # 下载目录 )

三、页面导航操作

3.1 基本页面导航

Playwright 的页面导航以 goto 方法为核心,支持完整的页面加载生命周期控制。开发者可以指定等待策略(DOMContentLoaded、Load、NetworkIdle),以适应不同场景。与 Selenium 不同,Playwright 的 goto 方法默认会等待页面加载完成再返回,避免了后续操作因页面未加载完全而失败。

# 基本导航与等待策略 page.goto("https://example.com") page.goto("https://example.com", wait_until="domcontentloaded") # DOM 就绪即返回 page.goto("https://example.com", wait_until="networkidle") # 网络空闲后返回

3.2 前进后退与刷新

浏览器自动化中,模拟用户的前进、后退、刷新操作是最基础的能力。Playwright 将这些操作抽象为 page 的方法,调用方式直观且稳定。

# 导航历史操作 page.goto("https://example.com/page1") page.goto("https://example.com/page2") page.go_back() # 后退到 page1 page.go_forward() # 前进到 page2 page.reload() # 刷新当前页面 # 获取当前页面信息 print(page.url) # 当前页面 URL print(page.title()) # 当前页面标题

3.3 等待页面加载

页面加载状态的管理是自动化稳定性的关键。Playwright 提供了 wait_for_load_state 方法来精确控制页面加载阶段,同时支持自定义超时时间,确保脚本在慢速网络环境下也能稳定运行。

# 等待页面加载状态 page.goto("https://example.com") # 等待特定加载状态 page.wait_for_load_state("networkidle") # 等待网络空闲 page.wait_for_load_state("domcontentloaded") # 等待 DOM 就绪 # 等待导航完成(点击链接后等待新页面加载) with page.expect_navigation(): page.click("a.next-page") # 等待新标签页打开 with page.expect_popup() as popup_info: page.click("a[target='_blank']") new_page = popup_info.value new_page.wait_for_load_state()

3.4 多标签页管理

Playwright 通过 Context 下的多个 Page 对象管理多标签页。每个 Page 代表一个标签页,可以通过 pages 属性获取所有已打开的标签页,并通过 context 创建新的标签页。

# 多标签页管理 context = browser.new_context() page1 = context.new_page() page1.goto("https://example.com") page2 = context.new_page() page2.goto("https://python.org") # 切换标签页 page1.bring_to_front() print(page1.title()) # 列出所有标签页 for p in context.pages: print(p.url, p.title())

四、元素定位

4.1 Locator API 核心概念

Playwright 引入了全新的 Locator(定位器)概念,与传统的 find_element 方式不同,Locator 是一种"惰性"定位策略——它不会在创建时立即查找元素,而是在执行操作时才会真正定位并交互。这种设计使得定位器可以在页面变化后仍然有效,同时内置了自动等待机制,大幅提升了脚本的健壮性。

4.2 CSS 选择器与 XPath

Playwright 完整支持 CSS 选择器和 XPath 定位方式,语法与 Selenium 中的用法一致,迁移成本极低。

# CSS 选择器定位 page.locator("button.submit").click() page.locator("#username").fill("admin") page.locator("div.content > p:first-child").text_content() # XPath 定位 page.locator("xpath=//div[@class='header']//a").click() page.locator("xpath=//input[@type='submit']").click() # 复合条件定位 page.locator("input:has-text('搜索')").click() page.locator("button:visible").first().click()

4.3 文本选择器

文本选择器是 Playwright 的特色功能,允许通过可见文本内容直接定位元素,特别适合没有稳定 CSS class 的国际化应用或内容密集型的页面。

# 文本选择器 page.get_by_text("登录").click() # 精确匹配可见文本 page.get_by_text("提交订单", exact=True).click() # 精确匹配(无子字符串) page.locator("text=立即购买").click() # 标签 + 文本组合 page.locator("button:has-text('确认')").click() page.locator("div:has-text('温馨提示')").text_content() # 包含特定文本的元素(用于等待) page.get_by_text("操作成功").wait_for()

4.4 角色选择器(ARIA)

Playwright 支持通过 ARIA 角色和标签进行定位,更接近用户与页面的交互方式。这种定位方式对无障碍友好型应用尤为有效,也是 Playwright 推荐的定位方式之一。

# 角色选择器 page.get_by_role("button", name="提交").click() page.get_by_role("link", name="更多").click() page.get_by_role("heading", name="产品介绍").text_content() page.get_by_role("textbox", name="用户名").fill("admin") page.get_by_role("checkbox", name="同意协议").check()

4.5 层级定位与过滤

在实际页面中,元素往往嵌套在复杂的 DOM 结构中。Playwright 提供了链式调用和过滤机制,可以精确地在层级结构中定位目标元素。

# 层级链式定位 parent = page.locator(".product-list") child = parent.locator(".product-item") link = child.locator("a.view-detail") # 过滤定位器 rows = page.locator("table tr") rows.filter(has_text="待处理").locator(".action-btn").click() # 获取多个匹配元素 items = page.locator(".list-item").all() for item in items: print(item.text_content()) # 按索引定位 page.locator(".item").first.click() page.locator(".item").nth(2).click() page.locator(".item").last.click()

五、交互操作

5.1 基本交互:点击、输入、选择

Playwright 提供了丰富且稳定的交互方法,所有交互操作都内置了自动等待机制。点击操作前会自动等待元素可见和可用,输入操作会自动清空原有内容并触发 input 事件,选择操作会自动等待选项加载完成。

# 点击操作 page.click("button#submit") # 普通点击 page.dblclick(".item") # 双击 page.click("button", button="right") # 右键 page.click(".target", click_count=3) # 三击 # 输入操作 page.fill("#username", "admin") # 清空后输入 page.type("#search", "Playwright", delay=100) # 模拟真实输入延迟 page.locator("#email").press_sequentially("test@example.com", delay=50)

5.2 下拉选择与复选框

# 下拉选择框 page.select_option("select#city", "shanghai") # 按 value 选择 page.select_option("select#city", label="上海") # 按标签选择 page.select_option("select#tags", index=2) # 按索引选择 page.select_option("select#tags", ["tag1", "tag3"]) # 多选 # 复选框和单选框 page.check("input#agree") # 勾选 page.uncheck("input#agree") # 取消勾选 page.set_checked("input#switch", True) # 强制设定状态

5.3 拖拽与文件上传

# 拖拽操作 source = page.locator("#drag-source") target = page.locator("#drop-target") source.drag_to(target) # 拖拽到目标 # 文件上传 page.set_input_files("input[type='file']", "photo.jpg") # 上传单个文件 page.set_input_files("input[type='file']", ["a.pdf", "b.pdf"]) # 上传多个文件 # 移除已选择的文件 page.set_input_files("input[type='file']", [])

5.4 键盘与焦点操作

# 键盘操作 page.keyboard.press("Enter") # 按回车键 page.keyboard.press("Control+A") # 全选 page.keyboard.press("Control+C") # 复制 page.keyboard.type("Hello World") # 逐字输入 page.keyboard.down("Shift") # 按住 Shift page.keyboard.up("Shift") # 释放 Shift # 焦点管理 page.focus("#search-input") # 设置焦点 page.locator("#search-input").focus() page.locator("#search-input").blur() # 移除焦点

六、自动等待

6.1 自动等待机制原理

Playwright 的自动等待是它最显著的优势之一。当执行 click、fill 等操作时,Playwright 会自动检查一系列元素状态:元素是否附加到 DOM、是否可见、是否稳定(未持续变化)、是否没有被遮挡、是否启用。每种操作都对应一组等待条件,开发者无需手动调用等待方法,框架会自动轮询直到条件满足或超时。这一机制是 Playwright 脚本比 Selenium 脚本更加稳定的核心原因。

6.2 显式等待

尽管自动等待覆盖了大多数场景,但在某些复杂情况下(如等待特定文本出现、等待请求完成),仍需要显式等待方法。Playwright 提供了 wait_for 系列方法以应对这些场景。

# 显式等待元素 page.locator(".loading-finished").wait_for() # 等待元素出现在 DOM 中 page.locator(".result").wait_for(state="visible") # 等待元素可见 page.locator(".old-content").wait_for(state="hidden") # 等待元素隐藏 page.locator(".target").wait_for(state="attached") # 等待元素附加到 DOM # 等待特定文本内容 page.get_by_text("加载完毕").wait_for() page.locator(".status").wait_for(timeout=10000) # 自定义超时(毫秒)

6.3 状态检查方法

Playwright 提供了一系列断言检查方法,用于验证元素的当前状态。这些方法配合自动等待使用,可以在条件不满足时自动重试直到超时。

# 元素状态检查 locator = page.locator("#submit-btn") locator.wait_for() # 等待元素就绪 locator.is_visible() # 检查是否可见 locator.is_enabled() # 检查是否启用 locator.is_checked() # 检查是否勾选 locator.is_editable() # 检查是否可编辑 # 状态断言(自动重试直到条件满足或超时) from playwright.sync_api import expect expect(locator).to_be_visible() # 断言元素可见 expect(locator).to_be_enabled() # 断言元素可用 expect(locator).to_have_text("提交成功") # 断言文本内容 expect(page).to_have_title("首页") # 断言页面标题 expect(page.locator("table tr")).to_have_count(5) # 断言元素数量

6.4 超时控制

# 超时控制 # 全局超时设置(影响所有操作) browser = p.chromium.launch() context = browser.new_context() page = context.new_page() page.set_default_timeout(15000) # 15秒超时 # 单次操作超时 page.click(".slow-element", timeout=30000) # 30秒超时 # 导航超时 page.goto("https://example.com", timeout=60000) # 60秒导航超时

要点提示:Playwright 的默认超时时间为 30 秒。如果脚本在不稳定的网络环境下运行,建议增加全局超时时间。同时,避免滥用显式等待——优先依赖自动等待机制,只在特殊场景下使用 wait_for 和 expect。

七、网络拦截

7.1 Route 拦截与修改请求

Playwright 的 route API 提供了完整的网络请求生命周期控制能力。通过拦截请求,开发者可以修改请求头、请求体、URL 参数,甚至可以完全阻止某些请求(如广告、统计脚本)。与 Selenium 的方案相比,Playwright 的网络拦截更加原生和高效,无需配置代理服务器。

# 拦截并修改请求 page.route("**/api/**", lambda route: route.continue_(headers={ "Authorization": "Bearer fake-token" }) ) # 拦截并中止特定请求 page.route("**/*.png", lambda route: route.abort()) page.route("**/analytics.js", lambda route: route.abort()) # 完整请求检查 def handle_request(route): request = route.request print(f"请求: {request.method} {request.url}") print(f"请求头: {request.headers}") route.continue_() page.route("**", handle_request)

7.2 Mock API 响应

在前端开发与测试中,往往需要在不依赖真实后端的情况下模拟 API 响应。Playwright 可以拦截请求并直接返回自定义的 Mock 数据,极大提升了测试效率。

# Mock API 响应 page.route("**/api/users", lambda route: route.fulfill( status=200, content_type="application/json", body='{"users": [{"id": 1, "name": "张三"}]}' ) ) # 模拟网络错误 page.route("**/api/checkout", lambda route: route.fulfill(status=500, body='{"error": "服务器繁忙"}') ) # 模拟延迟响应 import time page.route("**/api/payments", lambda route: (time.sleep(5), route.continue_())[1] )

7.3 请求抓取与分析

Playwright 可以捕获页面发出的所有网络请求及其响应,这对于调试、性能分析和数据采集非常有价值。

# 请求捕获 requests = [] def on_request(request): requests.append({ "url": request.url, "method": request.method, "headers": request.headers, "resource_type": request.resource_type }) page.on("request", on_request) page.goto("https://example.com") print(f"共捕获 {len(requests)} 个请求") # 响应捕获 page.on("response", lambda response: print(f"响应: {response.status} {response.url}") )

7.4 模拟网络条件

在真实场景中,用户可能处于各种不同网络条件下。Playwright 允许模拟离线模式、慢速网络等场景,帮助开发者验证应用在弱网环境下的表现。

# 模拟网络条件 context = browser.new_context() # 离线模式 context.set_offline(True) # 模拟慢速网络(3G 条件) context = browser.new_context( extra_http_headers={ "Accept-Encoding": "gzip" } ) context.route("**", lambda route: (time.sleep(1), route.continue_())[1] ) # 模拟不同带宽(限制下载/上传速度,需配合代理使用) # Playwright 本身不直接限制带宽,但可以通过全局延迟模拟 browser = p.chromium.launch(slow_mo=200) # 200ms 操作延迟

八、多浏览器与移动端

8.1 三大浏览器引擎

Playwright 最强大的特性之一是对 Chromium、Firefox 和 WebKit 三大浏览器引擎的统一支持。这意味着开发者可以使用同一套 API 在 Chrome、Edge、Safari 和 Firefox 上运行自动化脚本,特别适合跨浏览器兼容性测试场景。每个浏览器引擎的启动方式完全一致,只需修改 browser_type 名称即可切换。

# Chromium(Chrome、Edge 等) browser = p.chromium.launch() page = browser.new_page() page.goto("https://example.com") # Firefox browser = p.firefox.launch() page = browser.new_page() page.goto("https://example.com") # WebKit(Safari) browser = p.webkit.launch() page = browser.new_page() page.goto("https://example.com")

8.2 移动设备模拟

Playwright 内置了丰富的移动设备描述符,可以精确模拟 iPhone、iPad、Android 等设备的浏览器行为。模拟内容包括视口大小、设备像素比、用户代理字符串、触控事件等,使开发者无需真实设备即可进行移动端测试。

# 移动设备模拟 from playwright.sync_api import sync_playwright with sync_playwright() as p: # iPhone 13 模拟 iphone_13 = p.devices["iPhone 13"] context = browser.new_context( **iphone_13, locale="zh-CN" ) page = context.new_page() page.goto("https://example.com") page.screenshot(path="iphone13.png", full_page=True) # 查看所有可用设备 print(list(p.devices.keys())[:10])

8.3 地理定位、时区与语言设置

Playwright 支持精细化配置浏览器上下文的地理位置、时区、语言偏好等参数,这在测试国际化应用和地理位置相关功能时非常有用。

# 地理位置模拟 context = browser.new_context( geolocation={"latitude": 31.2304, "longitude": 121.4737}, # 上海 permissions=["geolocation"], locale="zh-CN", timezone_id="Asia/Shanghai" ) page = context.new_page() page.goto("https://maps.example.com") # 多语言测试 en_context = browser.new_context(locale="en-US") jp_context = browser.new_context(locale="ja-JP") de_context = browser.new_context(locale="de-DE")

8.4 浏览器持久化与认证

# 保存登录状态 context = browser.new_context() page = context.new_page() page.goto("https://example.com/login") page.fill("#username", "admin") page.fill("#password", "123456") page.click("button[type='submit']") context.storage_state(path="login-state.json") # 保存 Cookies 和存储 # 复用登录状态 context = browser.new_context(storage_state="login-state.json") page = context.new_page() page.goto("https://example.com/dashboard") # 已登录状态

九、截图与录制

9.1 截图功能

Playwright 提供了强大的截图能力,支持对整个页面、特定元素进行截图,也可以生成全页截图(包含滚动内容)。截图输出为 PNG 格式,可以嵌入测试报告或作为调试证据使用。

# 全页截图 page.screenshot(path="fullpage.png", full_page=True) # 元素截图 page.locator(".highlight-box").screenshot(path="element.png") # 视口截图 page.screenshot(path="viewport.png") # 仅当前可见区域 # 截图质量控制 page.screenshot( path="highres.png", full_page=True, scale="css", # 使用 CSS 像素 quality=90 # JPEG 质量(仅 JPEG 格式) )

9.2 视频录制

Playwright 支持在浏览器上下文中录制视频,完整记录测试执行过程。这对于失败测试的复盘和非技术人员的沟通非常有用。视频录制需要安装 FFmpeg 支持。

# 录制测试视频 context = browser.new_context( record_video_dir="videos/", # 视频输出目录 record_video_size={"width": 1280, "height": 720} # 视频尺寸 ) page = context.new_page() page.goto("https://example.com") page.click("button") context.close() # 关闭上下文时停止录制 # 获取视频文件路径 video_path = page.video.path() print(f"视频保存至: {video_path}")

9.3 PDF 生成

Playwright 可以将页面内容生成为 PDF 文件,这在生成报告、发票、存档等办公自动化场景中非常实用。PDF 生成功能目前仅在 Chromium(无头模式)下可用。

# PDF 生成 page.goto("https://example.com/report") page.pdf( path="report.pdf", format="A4", # 纸张大小(A4/Letter 等) margin={ "top": "20mm", "bottom": "20mm", "left": "15mm", "right": "15mm" }, print_background=True, # 打印背景颜色和图片 scale=0.9 # 缩放比例 )

9.4 追踪记录与交互录制

# 启用追踪记录(调试利器) context = browser.new_context() context.tracing.start( screenshots=True, snapshots=True, sources=True ) page.goto("https://example.com") page.click("button") context.tracing.stop(path="trace.zip") # 可在 Playwright Trace Viewer 中查看 # 使用代码生成器(命令行交互) # playwright codegen https://example.com # 以上命令会打开浏览器录制窗口,操作将自动生成 Python 代码

十、实战案例

10.1 案例一:电商价格监控

本案例演示如何使用 Playwright 定时抓取电商商品页面的价格信息,并在价格低于阈值时发送通知。该场景充分展示了 Playwright 在页面解析、数据提取和定时任务方面的综合能力。

# 电商价格监控 from playwright.sync_api import sync_playwright import smtplib from email.message import EmailMessage def check_price(url, threshold): with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() page.goto(url, timeout=30000) # 提取商品名称和价格 name = page.locator(".product-title").text_content() price_text = page.locator(".price-current").text_content() # "¥299.00" -> 299.00 price = float(price_text.replace("¥", "").strip()) print(f"商品: {name}, 当前价格: {price}") if price <= threshold: send_alert(name, price, threshold) browser.close() def send_alert(name, price, threshold): msg = EmailMessage() msg.set_content(f"商品 [{name}] 已降至 ¥{price},低于阈值 ¥{threshold}") msg["Subject"] = "价格监控提醒" msg["To"] = "user@example.com" # 使用 SMTP 发送邮件(需配置) # with smtplib.SMTP("smtp.example.com") as server: # server.send_message(msg) # 监控多个商品 products = [ ("https://shop.example.com/product/001", 200), ("https://shop.example.com/product/002", 350), ] for url, threshold in products: check_price(url, threshold)

10.2 案例二:自动化 UI 回归测试

在前端项目迭代中,UI 回归测试是确保功能正常的重要手段。Playwright 提供了完整的测试框架集成,支持浏览器矩阵测试、截图对比和并行执行。

# UI 回归测试脚本 from playwright.sync_api import sync_playwright import os def test_login_flow(browser_type="chromium"): with sync_playwright() as p: browser = getattr(p, browser_type).launch() context = browser.new_context( viewport={"width": 1920, "height": 1080} ) page = context.new_page() # 测试步骤 1:访问登录页 page.goto("https://example.com/login") assert page.title() == "登录" # 测试步骤 2:错误密码提示 page.fill("#username", "admin") page.fill("#password", "wrong") page.click("button[type='submit']") expect(page.get_by_text("密码错误")).to_be_visible() # 测试步骤 3:成功登录 page.fill("#password", "correct123") page.click("button[type='submit']") expect(page).to_have_url("https://example.com/dashboard") # 截图对比基准 page.screenshot(path=f"screenshots/{browser_type}_dashboard.png") browser.close() # 跨浏览器执行 for browser_type in ["chromium", "firefox", "webkit"]: test_login_flow(browser_type) print(f"{browser_type} 测试通过")

10.3 案例三:跨浏览器兼容性测试

Web 应用需要在不同浏览器上保持一致的表现。Playwright 的矩阵测试能力使得跨浏览器兼容性验证变得简单高效。

# 跨浏览器兼容性测试矩阵 from playwright.sync_api import sync_playwright import json def run_compatibility_check(url, test_cases): results = {} with sync_playwright() as p: browsers = { "Chrome": p.chromium.launch(), "Firefox": p.firefox.launch(), "Safari": p.webkit.launch(), } for name, browser in browsers.items(): print(f"正在测试: {name}") page = browser.new_page() page.goto(url) results[name] = {} for case_name, selector in test_cases.items(): try: element = page.locator(selector) results[name][case_name] = { "exists": element.is_visible(), "text": element.text_content()[:50] if element.is_visible() else None, } except Exception as e: results[name][case_name] = {"error": str(e)} browser.close() with open("compatibility_report.json", "w", encoding="utf-8") as f: json.dump(results, f, ensure_ascii=False, indent=2) return results # 执行测试 url = "https://example.com/product" cases = { "页面标题": "h1", "购买按钮": "button.buy-now", "商品列表": ".product-grid", "搜索框": "input#search", } report = run_compatibility_check(url, cases) print(json.dumps(report, ensure_ascii=False, indent=2))

知识回顾:Playwright 作为新一代跨浏览器自动化工具,其核心优势在于:自动等待机制大幅提升脚本稳定性;统一 API 支持 Chromium/Firefox/WebKit 三大引擎;Context 上下文隔离设计简洁高效;网络拦截 route API 强大灵活。建议在实际项目中逐步从 Selenium 迁移到 Playwright,以享受更流畅的开发体验和更高的运行效率。