Playwright 详细用法

5 阅读9分钟

Playwright 详细用法

如果说 Selenium 是很多人学习 UI 自动化的第一站,那么 Playwright 往往是很多团队在新项目里更愿意尝试的新选择。

它对现代前端支持更友好,自动等待能力更强,调试体验也更现代,所以这几年在测试开发和前端测试场景里非常受欢迎。

但很多同学虽然知道 Playwright“很好用”,真正上手时还是会遇到问题:

  • 怎么安装
  • 怎么打开浏览器
  • 怎么定位元素
  • 怎么做等待
  • 怎么处理 iframe、弹窗、多标签页
  • 怎么截图、录屏、看 trace

这篇文章就把 Playwright 最常用、也最实战的内容系统整理一遍。


一、Playwright 是什么

Playwright 是一个现代化的浏览器自动化工具,支持:

  • Chromium
  • Firefox
  • WebKit

它可以用来做:

  • UI 自动化测试
  • 端到端测试
  • 页面抓取
  • 自动化脚本操作

在测试开发场景中,Playwright 最常见的用途是做 Web UI 自动化测试。


二、安装和初始化

如果你使用 Python,可以先安装 Playwright:

pip install playwright

安装完成后,还需要安装浏览器驱动:

playwright install

如果你只想安装 Chromium,也可以:

playwright install chromium

三、最基础的脚本结构

Playwright Python 常见有两种写法:

  • 同步写法
  • 异步写法

初学时更常见的是同步写法。

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)   # 启动 Chromium 浏览器
    page = browser.new_page()                     # 新建页面标签
    page.goto("https://example.com")              # 打开目标页面
    print(page.title())                           # 打印页面标题
    browser.close()                               # 关闭浏览器

这段代码做了几件事:

  1. 启动 Playwright
  2. 打开 Chromium 浏览器
  3. 新建一个页面
  4. 访问目标 URL
  5. 获取页面标题
  6. 关闭浏览器

四、浏览器和页面的基本操作

1. 启动浏览器

browser = p.chromium.launch(headless=False)   # 有头模式启动浏览器

如果要无头运行:

browser = p.chromium.launch(headless=True)   # 无头模式启动浏览器

2. 创建页面

page = browser.new_page()   # 新建一个页面对象

3. 打开页面

page.goto("https://example.com")   # 打开目标页面

4. 获取页面信息

print(page.title())   # 页面标题
print(page.url)       # 当前 URL
print(page.content()) # 页面 HTML 内容

5. 刷新和导航

page.reload()
page.go_back()
page.go_forward()

6. 关闭页面和浏览器

page.close()
browser.close()

五、元素定位是 Playwright 的强项之一

相比很多传统自动化工具,Playwright 在元素定位体验上通常更现代。

1. 基础定位

page.locator("#username")                    # 通过 id 定位
page.locator(".login-btn")                  # 通过 class 定位
page.locator("input[name='password']")      # 通过属性定位
page.locator("//button[@type='submit']")    # 通过 XPath 定位

2. 推荐使用 locator

Playwright 中非常推荐使用 locator,而不是把元素一次性取出来后长期复用。

例如:

username = page.locator("#username")   # 获取用户名输入框 locator
username.fill("admin")                 # 输入用户名

这样做的好处是:

  • 可读性更好
  • 和等待机制结合更自然
  • 元素变化时更灵活

3. 按文本定位

page.get_by_text("登录")                 # 按文本内容定位
page.get_by_text("提交", exact=True)     # 精确匹配文本内容定位

4. 按角色定位

对于现代页面,Playwright 很推荐这种方式:

page.get_by_role("button", name="登录")     # 按角色定位登录按钮
page.get_by_role("textbox", name="用户名")   # 按角色定位用户名输入框

5. 按测试属性定位

如果前端提供了测试属性,会非常好用:

page.get_by_test_id("login-button")   # 按测试专用属性定位

这也是团队协作里非常推荐的一种方式。


六、元素常用操作

1. 输入内容

page.locator("#username").fill("admin")    # 输入用户名
page.locator("#password").fill("123456")   # 输入密码

2. 点击按钮

page.get_by_role("button", name="登录").click()   # 点击登录按钮

3. 获取文本

text = page.locator(".error-msg").text_content()   # 获取错误提示文本
print(text)                                        # 打印文本

4. 获取属性

value = page.locator("#username").get_attribute("value")   # 获取输入框 value 属性
print(value)                                               # 打印属性值

5. 复选框和单选框

page.locator("#remember").check()     # 勾选复选框
page.locator("#remember").uncheck()   # 取消勾选复选框

6. 下拉框

page.locator("#city").select_option("shanghai")   # 按 value 选择下拉项
page.locator("#city").select_option(label="北京") # 按显示文本选择下拉项

7. 悬停

page.locator("#menu").hover()   # 鼠标悬停到菜单上

8. 双击和右键

page.locator("#item").dblclick()              # 双击元素
page.locator("#item").click(button="right")   # 右键点击元素

七、Playwright 的等待机制为什么更友好

很多同学喜欢 Playwright,一个非常重要的原因就是它的自动等待能力。

1. 为什么说它“更省心”

在 Selenium 里,你经常要自己显式处理:

  • 元素是否出现
  • 元素是否可点击
  • 页面是否加载完

而 Playwright 在很多操作中会自动等待元素达到可交互状态。

例如:

page.get_by_role("button", name="登录").click()

它在很多情况下会自动等待按钮可点击,而不是立即报错。

2. 显式等待依然有价值

虽然 Playwright 自动等待很强,但并不是说你永远不用等待。

常见显式等待方式:

page.wait_for_url("**/dashboard")
page.wait_for_load_state("networkidle")
page.locator(".success-msg").wait_for()

3. 不建议滥用固定等待

page.wait_for_timeout(3000)

这个方法不是不能用,但更适合临时调试,不适合作为长期方案。

长期更推荐等待“条件成立”。


八、断言怎么写

Playwright 的断言通常和 expect 配合使用。

from playwright.sync_api import expect

expect(page).to_have_title("首页")
expect(page.locator(".success-msg")).to_have_text("登录成功")
expect(page).to_have_url("https://example.com/dashboard")

常见断言包括:

  • 页面标题
  • 页面 URL
  • 元素文本
  • 元素可见
  • 元素数量

例如:

expect(page.locator("#submit")).to_be_visible()
expect(page.locator(".row")).to_have_count(5)

九、iframe 处理

如果页面元素在 iframe 里,需要使用 frame 相关 API。

1. 通过 frame_locator

frame = page.frame_locator("#login-frame")
frame.locator("#username").fill("admin")

这是 Playwright 中比较推荐的写法。

2. 通过 frame 名称或 URL 获取

for frame in page.frames:
    print(frame.url)

如果你要做更复杂的 frame 排查,也可以遍历页面里的所有 frame。


十、多标签页和新窗口处理

很多业务场景会点击后打开新页面。

Playwright 里通常这样处理:

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())

如果是浏览器上下文里的多个页面:

context = browser.new_context()
page = context.new_page()

context 是 Playwright 中非常重要的概念,它可以理解成一个独立的浏览器会话环境。


十一、弹窗处理

1. 浏览器原生弹窗

例如 alert、confirm、prompt。

page.on("dialog", lambda dialog: dialog.accept())

如果需要读取文本:

def handle_dialog(dialog):
    print(dialog.message)
    dialog.accept()

page.on("dialog", handle_dialog)

2. 页面自定义弹窗

如果是页面自己实现的弹层,它本质上还是页面元素,直接正常定位和点击即可。


十二、文件上传和下载

1. 文件上传

page.set_input_files("input[type='file']", "demo.txt")

可以上传单文件,也可以上传多个文件。

2. 文件下载

with page.expect_download() as download_info:
    page.get_by_text("下载").click()

download = download_info.value
download.save_as("result.xlsx")

这也是 Playwright 比较方便的一点,下载处理体验通常更自然。


十三、截图、录屏和 trace

Playwright 在调试和失败排查方面非常强。

1. 截图

page.screenshot(path="page.png")

只截某个元素:

page.locator("#login-form").screenshot(path="form.png")

2. 视频录制

创建 context 时可以配置视频输出目录。

3. trace 追踪

trace 是 Playwright 很强大的调试能力之一。

运行失败后,你可以查看:

  • 点击了什么
  • 页面怎么变化
  • 每一步执行了什么

在项目里,trace 对排查偶发失败非常有帮助。


十四、Mock 和网络拦截

Playwright 不只是能做页面自动化,它还非常适合做前端联调和接口 Mock。

1. 拦截请求

page.route("**/api/login", lambda route: route.fulfill(
    status=200,
    body='{"code":0,"msg":"success"}'
))

2. 放行请求

page.route("**/*", lambda route: route.continue_())

3. 获取响应

response = page.wait_for_response("**/api/login")
print(response.status)

这类能力在前端测试、联调测试和异常场景模拟时很有价值。


十五、浏览器上下文是 Playwright 的一个重要概念

很多人第一次接触 Playwright 时,对 browser context 这个概念不太熟。

你可以把它理解成:

一个隔离的浏览器会话环境

不同 context 之间通常可以做到:

  • Cookie 隔离
  • LocalStorage 隔离
  • Session 隔离

所以它非常适合做:

  • 多账号测试
  • 独立会话测试
  • 更干净的测试隔离

示例:

context1 = browser.new_context()
context2 = browser.new_context()

page1 = context1.new_page()
page2 = context2.new_page()

这样两个页面通常可以模拟两个独立用户。


十六、Playwright 在项目里的推荐实践

1. 优先使用 locator

不要到处混用旧式 API,尽量统一风格。

2. 优先使用语义化定位

比如:

  • get_by_role
  • get_by_text
  • get_by_test_id

3. 充分利用自动等待

但也不要迷信自动等待,复杂场景仍要明确等待条件。

4. 用 POM 管理页面

项目一旦大起来,页面对象模型依然很重要。

5. 配合 Pytest 和报告工具

例如:

  • fixture 管理 browsercontextpage
  • 失败自动截图
  • trace 保留
  • 生成测试报告

十七、Playwright 常见问题

1. 为什么元素明明在页面上,却操作失败

可能原因:

  • 元素被遮挡
  • 元素还没真正进入可交互状态
  • 页面局部刷新导致时机问题

2. 为什么自动等待了还是会失败

因为自动等待主要解决通用交互条件,但复杂业务条件仍然需要你自己明确表达。

比如:

  • 等待接口返回完成
  • 等待业务提示出现
  • 等待页面跳转完成

3. 为什么 Playwright 适合现代前端

因为它在定位、等待、调试、网络拦截、多浏览器支持这些方面,对现代页面交互支持更自然。


十八、写在最后

Playwright 最值得掌握的,不只是语法本身,而是它背后的使用思路:

  • 用更稳定的定位方式
  • 充分利用自动等待
  • 用 context 做隔离
  • 用 trace 和截图做排查
  • 用框架化方式做长期维护

如果用一句话总结 Playwright 的学习重点,我会这样说:

Playwright 的优势不只是“能自动化”,而是“让现代 UI 自动化更自然、更稳定、更容易排查”。

如果你愿意,下一篇还可以继续展开:

  • Playwright + Pytest 自动化框架实战
  • Playwright 常见面试题
  • Playwright 和 Selenium 的代码对照版教程

十九、Playwright 面试高频问答

1. Playwright 为什么很多团队觉得更好用

参考答法:

因为 Playwright 对现代前端支持更友好,自动等待能力更强,定位方式更现代,调试、截图、录屏和 trace 能力也更完善。

2. locator 为什么推荐优先使用

参考答法:

因为 locator 和等待机制结合更自然,写法更统一,也更适合项目里长期维护。

3. Playwright 的自动等待是不是就不需要显式等待了

参考答法:

不是。自动等待可以解决很多通用交互问题,但复杂业务场景里仍然需要显式等待 URL、接口响应、业务提示等条件。

4. Playwright 的 context 有什么作用

参考答法:

context 可以理解成一个独立的浏览器会话环境,适合做 Cookie 隔离、Session 隔离和多账号测试。

5. Playwright 适合哪些场景

参考答法:

比较适合新项目、现代前端页面、多浏览器测试,以及需要更强调试和追踪能力的团队。

6. Playwright 和 Selenium 怎么选

参考答法:

老项目如果已经有成熟 Selenium 体系,可以优先延续;新项目从零开始,通常更推荐 Playwright。