微信扫码
添加专属顾问
我要投稿
Playwright 1.59 发布三大定位器新API,让你彻底告别F12手动查找的繁琐流程。核心内容:1. 三大新API(pickLocator、normalize、screencast)的实战应用2. 批量清洗项目定位器的自动化工具3. 结合AI自动生成Page Object骨架的Prompt模板
大家好,我是欢乐马。
学完本篇,你将掌握 Playwright 1.59 三个定位器新 API,把「F12 翻 DOM→手动改 selector」的工作流变成「指哪儿点哪儿→自动规范化→AI 生成 PO 骨架」。
学完你会获得:
① 三个 API(pickLocator / normalize / screencast)的完整代码示例,saucedemo 实战可跑
② 批量清洗现有项目定位器的工具脚本
③ 结合 AI 自动生成 Page Object 的 Prompt 模板
帮你少走弯路哦少踩坑。
新用户(从零开始):
# Python 版
pip install playwright
playwright install
# Node.js 版
npm init playwright@latest
老用户升级:
# Python 版
pip install --upgrade playwright
playwright install
# Node.js 版
npm install @playwright/test@latest
npx playwright install
Python 和 Node.js 都支持吗?
✅ pickLocator() — Python + Node.js 均支持
✅ locator.normalize() — Python + Node.js 均支持
✅ page.screencast — Python + Node.js 均支持
playwright 发布了最新的1.59版本,更新了不少内容,加强了AI Agent + 自动化测试。星主能不能介绍下具体的落地案例?
我现在还是F12一个一个的手动去写定位,有没有快速高效的案例,提升写用例的效率。现在已经维护了1000+的用例了。一个一个去找定位太慢了,虽然元素都加了testid了。
..生成整个 PO 模式的脚本,只需要人工调试修改定位表达式。想实现这种效果
「太慢了。能不能把页面地址丢给 AI,让它直接生成整个 PO 脚本?」
这个问题,Playwright 1.59 给了三个直接对口的答案。
但在讲 API 之前,先把定位策略优先级重申一遍——这是地基:
data-test > role > text > test_id > CSS > XPath
下面三个 API,本质上是帮你在执行层更快地落地这套优先级框架。
这是 1.59 对测试人员最友好的功能。
以前怎么找定位器?(以 saucedemo.com 登录页为例)
<input id="user-name" ...>#user-name,心里默念「这 id 应该不会变吧...」现在呢?一行代码:
locator = await page.pick_locator()
运行后浏览器进入选取模式——鼠标悬停到哪个元素,哪个高亮,旁边实时显示定位器表达式。点一下就选中,locator 对象直接返回。
实战:pickLocator 选取 saucedemo 登录页元素
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto('https://www.saucedemo.com/', wait_until='networkidle')
print('\n>>> 请在浏览器中点击「用户名输入框」')
username_loc = await page.pick_locator()
username_loc = await username_loc.normalize()
print(f'✅ 用户名输入框 → {username_loc}')
print('\n>>> 请点击「密码输入框」')
password_loc = await page.pick_locator()
password_loc = await password_loc.normalize()
print(f'✅ 密码输入框 → {password_loc}')
print('\n>>> 请点击「登录按钮」')
login_btn = await page.pick_locator()
login_btn = await login_btn.normalize()
print(f'✅ 登录按钮 → {login_btn}')
await browser.close()
asyncio.run(main())
运行这个脚本,你会在浏览器里点三个元素,终端立刻打印出三个已经规范化的定位器。
上一个例子已经顺带演示了 normalize。这里单独展开讲讲它到底做了什么。
saucedemo 举例:商品页的按钮
saucedemo 的商品列表页,每个商品都有「ADD TO CART」按钮,HTML 长这样:
<button class="btn btn_primary btn_small btn_inventory"
data-test="add-to-cart-sauce-labs-backpack">
Add to cart
</button>
如果你手头有一段历史代码,用 CSS class 定位了这个按钮:
add_to_cart_btn = page.locator('.btn_inventory')
问题在于 .btn_inventory 这个 class 在页面里有 6 个(6 个商品各一个),会匹配到第一个,不稳定。
用 normalize 一键升级:
raw = page.locator('.btn_inventory')
best = await raw.normalize()
print(best) # getByTestId('add-to-cart-sauce-labs-backpack')
normalize() 按优先级检查:
data-test 属性?→ 有,直接用 getByTestId()role?→ 有,用 getByRole()aria-label / placeholder?→ 有,用对应方法对于前面读者提到的那 1000+ 条用例,可以写个脚本全量扫描一遍 PO 类文件,找出所有可以用 normalize 升级的定位器,批量建议替换。
批量扫描脚本(核心逻辑):
import re
from pathlib import Path
NORMALIZE_RULES = [
(r'\[data-test\s*=\s*["\']([^"\']+)["\']\]', r'getByTestId("\1")'),
(r'\[placeholder\s*=\s*["\']([^"\']+)["\']\]', r'getByPlaceholder("\1")'),
]
def scan_po_files(pages_dir='pages'):
for py_file in Path(pages_dir).glob('*.py'):
if py_file.name.startswith('__'):
continue
with open(py_file) as f:
lines = f.readlines()
for i, line in enumerate(lines, 1):
m = re.match(r'^\s*(\w+)\s*=\s*["\']([^"\']+)["\']', line)
if not m:
continue
var_name, locator = m.group(1), m.group(2)
if locator.startswith('getBy'):
continue
for pattern, repl in NORMALIZE_RULES:
if re.search(pattern, locator):
print(f'{py_file}:{i} | {var_name} = "{locator}"')
print(f' → 建议改为: {re.sub(pattern, repl, locator)}')
break
输出类似:
pages/inventory_page.py:18 | ADD_TO_CART_BUTTON = ".btn_inventory"
→ 建议改为: getByTestId("add-to-cart-sauce-labs-backpack")
pages/inventory_page.py:20 | CART_LINK = ".shopping_cart_link"
→ 建议改为: getByTestId("shopping-cart-link")
一键看清哪些定位器需要升级。
排查失败用例最痛苦的是什么?不知道脚本点了哪里。
screencast 是 1.59 新增的录屏 API,比 recordVideo 更灵活,而且能在视频里标注每一步操作。
实战:录制 saucedemo 登录 + 加购完整流程
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
# ===== 开始录屏 + 操作标注 =====
await page.screencast.start(path='saucedemo_login.webm')
await page.screencast.show_actions(position='top-right')
# 步骤 1:打开登录页
await page.screencast.show_chapter('打开登录页')
await page.goto('https://www.saucedemo.com/', wait_until='networkidle')
# 步骤 2:输入用户名和密码
await page.screencast.show_chapter('输入用户名')
await page.fill('#user-name', 'standard_user')
await page.fill('#password', 'secret_sauce')
# 步骤 3:点击登录
await page.screencast.show_chapter('点击登录')
await page.click('#login-button')
# 步骤 4:验证商品列表
await page.screencast.show_chapter('验证登录成功')
await page.screencast.show_overlay('等待商品列表加载...')
await page.wait_for_selector('.inventory_list', timeout=5000)
# 步骤 5:添加商品到购物车
await page.screencast.show_chapter('添加第一个商品')
await page.click('.btn_inventory')
cart_badge = page.locator('.shopping_cart_badge')
if await cart_badge.is_visible():
count = await cart_badge.inner_text()
await page.screencast.show_overlay(f'购物车数量: {count}')
# ===== 停止录屏 =====
await page.screencast.stop()
print('✅ 视频已保存')
await browser.close()
asyncio.run(main())
跑完这段脚本,你会得到一个 .webm 视频文件。打开播放:
这个功能对于给 leader 演示或者排查 CI 上的偶发失败特别有用——不用再看截图猜谜了。
上面三步走完,你已经能做到:
但前面读者的最终目标更远——整个 PO 类的代码都由 AI 生成,人工只校对定位器和业务逻辑。
Step 1:用 Playwright 打开目标页面,抓取 DOM 结构快照
body = page.locator('body')
snapshot = await body.aria_snapshot()
print(snapshot)
Step 2:把「页面 URL + ARIA 快照 + 已知定位器」组成 Prompt,发给 LLM
你是一个 Playwright 自动化测试专家。
## 页面信息
- URL: https://www.saucedemo.com/inventory.html
- 类名: InventoryPage
## 已知定位器
- ADD_TO_CART_BUTTON: getByTestId("add-to-cart-sauce-labs-backpack")
- CART_BADGE: getByTestId("shopping-cart-badge")
- CART_LINK: getByTestId("shopping-cart-link")
## 页面 ARIA 结构
[ariaSnapshot 输出...]
## 要求
生成完整的 InventoryPage 类,继承 BasePage,包含:
- load() 方法加载页面
- 根据页面元素推断可用的业务方法
- 定位器使用已知定位器
Step 3:LLM 输出完整 PO 类,人工校对定位器 → 保存到项目 → 跑测试验证 → 通过后不再重复生成。
关键心法:AI 的正确用法不是让它每次跑测试时实时决策(那是 MCP 的坑),而是让它帮你生成一次固定的 PO 代码。代码一旦固化并通过测试,后续全是直接执行,没有幻觉,没有 token 消耗。
ffmpeg -i input.webm output.mp4 |
||
wait_for_load_state('domcontentloaded') 再取 |
||
wait_for_load_state('networkidle') |
pickLocator() |
||
normalize() |
||
screencast |
||
一句话记住:1.59 把定位器工作流从「手动 F12 → 复制 selector → 手动改 testid」变成了「指哪儿点哪儿 → 自动规范化 → AI 生成 PO 骨架」。
省下的时间,够你多写 20 条用例。
以上全套(可运行源码、Prompt 模板、扫描脚本)均已上传知识星球,大家可自取。
免费学,付费练,一文一码,就找欢乐马。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2026-05-22
AI Coding 时代:程序员的生存与进化指南
2026-05-20
Prompt 缓存,一次讲明白
2026-05-20
【干货】从Prompt、Context到Harness,工程的三次进化与终局之战原创
2026-05-20
2026 年真正好用的 30 个提示词技巧
2026-05-20
Google design.md 实战:让 AI 帮你做出 99.99% 的人做不出的设计
2026-05-20
从Prompt、Context到Harness,工程的三次进化与终局之战
2026-05-19
用好AI,从换用语音输入法开始
2026-05-17
2026年开发者现在就该用上的12个Claude Skills
2026-02-26
2026-02-24
2026-03-07
2026-03-13
2026-03-18
2026-02-24
2026-04-21
2026-02-28
2026-04-07
2026-03-05
2026-05-16
2026-04-14
2026-02-28
2026-02-12
2026-02-12
2026-02-08
2026-02-05
2026-02-05