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() # 关闭浏览器
这段代码做了几件事:
- 启动 Playwright
- 打开 Chromium 浏览器
- 新建一个页面
- 访问目标 URL
- 获取页面标题
- 关闭浏览器
四、浏览器和页面的基本操作
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_roleget_by_textget_by_test_id
3. 充分利用自动等待
但也不要迷信自动等待,复杂场景仍要明确等待条件。
4. 用 POM 管理页面
项目一旦大起来,页面对象模型依然很重要。
5. 配合 Pytest 和报告工具
例如:
- fixture 管理
browser、context、page - 失败自动截图
- 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。