2026年7月9日 周四晚上19:30,报名腾讯会议了解“如何构建自进化的动态知识库(Brain)”(限30人)
免费POC, 零成本试错
FDE知识库

FDE知识库

学习大模型的前沿技术与行业落地应用


收藏

Playwright 1.59 新特性:3 个 API 帮你告别 F12 手动找定位

发布日期:2026-05-22 12:13:32 浏览次数: 1752
作者:Playwright实战教程

微信搜一搜,关注“Playwright实战教程”

推荐语

Playwright 1.59 发布三大定位器新API,让你彻底告别F12手动查找的繁琐流程。

核心内容:
1. 三大新API(pickLocator、normalize、screencast)的实战应用
2. 批量清洗项目定位器的自动化工具
3. 结合AI自动生成Page Object骨架的Prompt模板

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家

 

Playwright 1.59 三个定位器新 API,把「F12 翻 DOM→手动改 selector」的工作流变成「指哪儿点哪儿→自动规范化→AI 生成 PO 骨架」。

学完你会获得:
① 三个 API(pickLocator / normalize / screencast)的完整代码示例,saucedemo 实战可跑
② 批量清洗现有项目定位器的工具脚本
③ 结合 AI 自动生成 Page Object 的 Prompt 模板

帮你少走弯路哦少踩坑。


环境配置:安装与升级(Playwright v1.59)

新用户(从零开始):

# 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 均支持


一、问题:1000+ 用例,定位器怎么写最快?

playwright 发布了最新的1.59版本,更新了不少内容,加强了AI Agent + 自动化测试。星主能不能介绍下具体的落地案例?

我现在还是F12一个一个的手动去写定位,有没有快速高效的案例,提升写用例的效率。现在已经维护了1000+的用例了。一个一个去找定位太慢了,虽然元素都加了testid了。
..生成整个 PO 模式的脚本,只需要人工调试修改定位表达式。想实现这种效果

「太慢了。能不能把页面地址丢给 AI,让它直接生成整个 PO 脚本?」

这个问题,Playwright 1.59 给了三个直接对口的答案。

但在讲 API 之前,先把定位策略优先级重申一遍——这是地基:

data-test > role > text > test_id > CSS > XPath
  1. 1. data-test:专门给测试预留,最稳
  2. 2. role:语义化定位,可访问性友好
  3. 3. text:文本定位,够直观
  4. 4. test_id:Playwright 内置测试属性
  5. 5. CSS:通用兜底
  6. 6. XPath:万不得已

下面三个 API,本质上是帮你在执行层更快地落地这套优先级框架。


二、3 个 API 更新

2.1 page.pickLocator() —— 指哪儿点哪儿

这是 1.59 对测试人员最友好的功能。

以前怎么找定位器?(以 saucedemo.com 登录页为例)

  1. 1. 打开 https://www.saucedemo.com
  2. 2. F12 → 审查元素
  3. 3. 在密密麻麻的 DOM 里找到用户名输入框
  4. 4. 看到一个 <input id="user-name" ...>
  5. 5. 写 #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())

运行这个脚本,你会在浏览器里点三个元素,终端立刻打印出三个已经规范化的定位器。

2.2 locator.normalize() —— 把烂定位器洗成最佳实践

上一个例子已经顺带演示了 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() 按优先级检查:

  1. 1. 有没有 data-test 属性?→ 有,直接用 getByTestId()
  2. 2. 有没有 role?→ 有,用 getByRole()
  3. 3. 有没有 aria-label / placeholder?→ 有,用对应方法
  4. 4. 以上都没有 → 保留原选择器但尝试简化

对于前面读者提到的那 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")

一键看清哪些定位器需要升级。

2.3 page.screencast —— 测试跑完自动生成带标注的视频

排查失败用例最痛苦的是什么?不知道脚本点了哪里。

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 视频文件。打开播放:

  • • 右上角实时显示每一步的操作名(fill、click、wait)
  • • 被点击的元素会高亮闪烁
  • • 每一段有章节标记
  • • 自定义浮层(「等待商品列表加载...」「购物车数量: 1」)清晰可见


    这个功能对于给 leader 演示或者排查 CI 上的偶发失败特别有用——不用再看截图猜谜了。


    三、AI 辅助生成 Page Object

    上面三步走完,你已经能做到:

    • • 定位器获取:pickLocator 指哪儿点哪儿
    • • 定位器优化:normalize 自动洗成最佳实践
    • • 调试回执:screencast 生成带标注的视频

    但前面读者的最终目标更远——整个 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 消耗。


    四、踩坑 / Tips

    说明
    解决
    pickLocator 必须 headless=False
    选取模式需要浏览器可交互,headless 下调用会报错
    本地调试用 headless=False,CI 里别用
    normalize 不改写文件
    它只返回新的定位器对象,不会帮你自动替换代码
    搭配扫描脚本做批量替换建议
    screencast 输出 .webm
    企业微信/钉钉不一定能直接播
    用 ffmpeg 转一下:ffmpeg -i input.webm output.mp4
    aria_snapshot 可能超时
    页面 DOM 特别大时,快照生成慢
    先 wait_for_load_state('domcontentloaded') 再取
    pickLocator 选错元素
    动态页面悬停时元素可能变
    选之前先 wait_for_load_state('networkidle')

    五、总结

    你的痛点
    1.59 解法
    一句话效果
    F12 手动找定位
    pickLocator()
    指哪儿点哪儿,不再翻 DOM
    脆弱的 CSS 选择器
    normalize()
    一键洗成 testid / role 最佳实践
    排查失败靠猜
    screencast
    带标注的操作回执视频
    手写 PO 类
    AI + ARIA 快照
    Prompt 模板直接生成,人工校对即可

    一句话记住:1.59 把定位器工作流从「手动 F12 → 复制 selector → 手动改 testid」变成了「指哪儿点哪儿 → 自动规范化 → AI 生成 PO 骨架」。
    省下的时间,够你多写 20 条用例。


    作业

    1. 1. 必做:用 pickLocator 重新选取 saucedemo 商品列表页的 6 个「ADD TO CART」按钮定位器,对比 F12 方式的耗时
    2. 2. 必做:跑一遍 normalize 扫描脚本,检查你现有项目的定位器有多少可以升级
    3. 3. 选做:用 screencast 录制一段完整的登录→加购→结账流程,发给同事,看看他们能不能只看视频就理解测试步骤

     


    53AI,企业落地大模型首选服务商

    产品:场景落地咨询+大模型应用平台+行业解决方案

    承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

    联系我们

    售前咨询
    186 6662 7370
    预约演示
    185 8882 0121

    微信扫码

    添加专属顾问

    回到顶部

    加载中...

    扫码咨询

    扫码登录
    登录即表示您同意《53AI网站服务协议》
    服务协议

    欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。

    在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。

    一、 定义

    本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。

    会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。

    知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。

    二、 账号注册与登录

    登录方式:本网站支持以下登录方式,您可根据实际情况选择:

    微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。

    手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。

    账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。

    实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。

    未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。

    三、 服务内容与规范

    知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。

    服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。

    禁止行为:您在使用服务时不得实施以下行为:

    利用技术手段批量爬取、下载、转存知识库内容;

    将知识库内容用于商业目的或未经授权地向第三方传播;

    干扰本网站正常运行或侵犯其他用户合法权益;

    发布违法违规信息或从事违反公序良俗的活动。

    四、 知识产权声明

    权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。

    有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。

    侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。

    五、 个人信息保护

    我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。

    您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。

    您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。

    六、 免责声明

    内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。

    不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。

    第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。

    七、 违约责任

    如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。

    如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。

    八、 法律适用与争议解决

    本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。

    因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。

    九、 其他

    本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。

    本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。

    我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。


    已查阅