Python Playwright进阶教程:元素定位详解(二)

目录

常见的元素定位

5、通过替代文本定位

5.1 验证图片加载状态

5.2 操作带替代文本的图标/按钮

5.3 动态 alt 属性匹配

6、按标题定位

7、按测试 ID 查找

7.1 示例

7.2 对比其他定位方式‌

8、设置自定义测试 ID 属性

8.1 方法作用

9、通过 CSS 或 XPath 定位

10、XPath选择器

10.1 XPath 定位语法规则

1 基础定位

2 ‌动态路径匹配

3 显式声明 XPath 前缀

4 隐式省略前缀

10.2 XPath 表达式规范

a. 路径表达式要求

b. 动态属性与文本匹配

c. 优先使用相对路径

d. 避免过度复杂表达式

10.3 高级场景与优化

10.4 与其他定位器对比

10.5 适用场景

11、CSS选择器 (locator(selector))

基础用法-基础选择器

11.1 元素选择器

11.2 类与 ID 选择器

11.3 属性选择器

11.4 层级关系定位

11.5 直接子代选择器(>分隔)

高级用法与优化

11.6 属性操作符

1‌1.7 组合选择器‌

11.8 伪类与状态匹配‌

11.9 动态内容处理‌

11.10 列表项定位优化‌

与 XPath 的对比

12、Frame 内定位 (frame_locator())

13、链式选择器

14、过滤定位器


常见的元素定位

5、通过替代文本定位

通过其文本替代来定位元素(通常是图像),所有图片都应具有描述图像的 alt 属性。可以使用page.get_by_alt_text() 根据替代文本查找图片。

根据图片或媒体元素的 alt 属性定位元素,适用于图像或媒体内容。

基础语法:page.get_by_alt_text(alt_text, exact=False)

  • alt_text‌:必填参数,指定元素的 alt 属性文本(支持字符串或正则表达式)‌。
  • exact‌:默认为 False,控制是否精确匹配文本(True 为完全匹配,False 为模糊匹配
  •  示例1:

    示例代码:

    page.get_by_alt_text("playwright logo").click()
    
    # 说明:当元素支持替代文本(如 img 和 area 元素)时,建议使用此定位器
    

    示例2:

    <img alt="playwright logo" src="/img/playwright-logo.svg" width="100" />
    

    代码示例:

    # 定位alt属性为“logo”的图片
    page.get_by_alt_text("playwright logo")
    
    5.1 验证图片加载状态

    适用场景:验证图片是否正确加载或显示‌

    # 断言页面中存在 alt 属性为“公司 Logo”的图片  
    expect(page.get_by_alt_text("公司 Logo")).to_be_visible()  
    
    5.2 操作带替代文本的图标/按钮

    适用场景:图标按钮或可交互图片的点击操作‌

    # 点击 alt 文本为“搜索图标”的图片按钮  
    page.get_by_alt_text("搜索图标").click()  
    
    5.3 动态 alt 属性匹配

    适用场景:动态生成的图片或带参数的替代文本‌

    # 使用正则表达式匹配动态生成的 alt 文本(如“用户头像_张三”)  
    page.get_by_alt_text(re.compile(r"用户头像_\w+")).hover()  
    

    注意:

    1.alt 属性唯一性‌:确保目标 alt 文本在当前页面唯一,避免匹配多个元素导致操作异常‌。

    2.非图片元素兼容性‌:仅适用于支持 alt 属性的元素(如 <img><area>),其他元素需结合 get_by_role() 或 CSS 选择器‌

    3.优先使用正则表达式或模糊匹配

    6、按标题定位

    可以通过元素的 title 属性来定位元素。适用于有 title 提示的元素

    语法:page.get_by_title()

    说明:当元素具有 title 属性时,建议使用此定位器

    示例1:

    代码示例:

    expect(page.get_by_title("Issues count")).to_have_text("25 issues")
    
    <span title='用户设置'>用户设置</span>
    ```(
    ```python
    # 定位标题为“用户设置”的按钮
    page.get_by_title("用户设置")
    

    示例2:

    <title>百度一下,你就知道</title>

    示例代码:

    page.get_by_title("百度一下,你就知道").click()

    7、按测试 ID 查找

    根据元素data-testid 属性来定位元素(可以配置其他属性)

    如果 HTML 元素中有 data-testid 属性,可以使用 get_by_test_id() 方法通过此属性进行定位。这种方式特别适合在前端开发中为测试提供稳定的定位

    语法:page.get_by_test_id("test_id_value")

    7.1 示例

    代码示例:

    page.get_by_test_id("directions").click()
    
    # 定位data-testid属性为“submit-button”的按钮
    page.get_by_test_id("submit-button")
    
    # 定位并操作带有 data-testid="BookList-container" 的元素
    page.get_by_test_id("BookList-container").click()
    # 模糊匹配‌:支持正则表达式匹配部分 data-testid 值
    page.get_by_test_id(re.compile(r"user-\d+")).hover()

    注意:

  • 属性唯一性‌:确保 data-testid 值在页面中唯一,避免匹配到多个元素‌
  • 跨环境一致性‌:开发与生产环境需同步维护 data-testid,防止测试中断‌
  • 避免滥用‌:仅对关键交互元素添加 data-testid,避免过度标记导致维护成本增加‌
  • 7.2 对比其他定位方式

    方法 特点 适用场景
    get_by_test_id() 依赖专用测试属性,稳定性高 测试代码、动态内容
    get_by_role() 基于 ARIA 角色,强调可访问性 表单、按钮等标准组件
    get_by_text() 依赖文本内容,易受多语言影响 静态文本元素

    8、设置自定义测试 ID 属性

    默认情况下,page.get_by_test_id() 将根据 data-testid 属性查找元素,但您可以在测试配置中或通过调用 selectors.set_test_id_attribute() 来配置它。将测试 ID 设置为对测试使用自定义数据属性

    8.1 方法作用

  • 自定义属性名‌:将默认的 data-testid 替换为其他 HTML 属性(如 data-qadata-test-id 等)‌。
  • 全局生效‌:设置后所有 get_by_test_id() 定位操作均使用新属性名,无需逐条修改定位器‌。
  • from playwright.sync_api import sync_playwright
    
    with sync_playwright() as p:
        # 设置自定义测试 ID 属性为 "data-qa"
        p.selectors.set_test_id_attribute("data-qa")
        
        browser = p.chromium.launch()
        page = browser.new_page()
        page.goto("https://example.com")
        
        # 定位带有 data-qa="login-button" 的元素
        page.get_by_test_id("login-button").click()
    

    示例代码:

    playwright.selectors.set_test_id_attribute("data-pw")
    

    示例代码:

    page.get_by_test_id("directions").click()
    

    注意:‌

  • 唯一性校验‌:自定义属性需确保在页面中唯一,避免多个元素共用同一属性值‌。
  • 9、通过 CSS 或 XPath 定位

    如果绝对必须使用 CSS 或 XPath 定位器,则可以使用 page.locator() 创建一个定位器,该定位器采用一个选择器来描述如何在页面中查找元素。Playwright 支持 CSS 和 XPath 选择器,如果省略 css= 或 xpath= 前缀,则会自动检测它们

    示例代码:

    page.locator("css=button").click()
    page.locator("xpath=//button").click()
     
    page.locator("button").click()
    page.locator("//button").click()

    说明:

    XPath 和 CSS 选择器可以绑定到 DOM 结构或实现。当 DOM 结构更改时,这些选择器可能会中断。

    不建议使用 CSS 和 XPath,因为 DOM 经常会更改,从而导致无法复原的测试。相反,请尝试提供一个接近用户感知页面的定位器,例如角色定位器,或者使用测试 ID 定义显式测试协定。

    10、XPath选择器

    在 Playwright 中,locator("xpath=...") 是通过 ‌XPath 表达式‌定位元素的核心方法,适用于复杂或动态元素的精准定位。

    (locator("xpath=..."))

    示例代码:

    # 定位“提交”按钮
    page.locator("xpath=//button[text()='提交']")
    
    # 定位父元素为 div 且子元素包含 span 的结构
    page.locator("xpath=//div[span]")
    

    10.1 XPath 定位语法规则

    基础定位
    page.locator("xpath=//button[@id='submit']").click()  # 显式声明 XPath
    page.locator("//div[contains(@class, 'menu-item')]").hover()  # 隐式使用(自动识别)‌
    2 ‌动态路径匹配

    a. 使用 contains() 或 starts-with() 处理动态属性:

    page.locator("//input[contains(@placeholder, 'Search')]").fill("Playwright")
    

    b. 结合文本内容定位:

    page.locator("//a[text()='Sign In']").click()
    
    显式声明 XPath 前缀

    说明:Playwright 支持显式指定定位策略,避免与其他定位方式混淆‌

    # 显式添加 "xpath=" 前缀(推荐)  
    page.locator("xpath=//div[@class='container']/button‌:ml-citation{ref="1" data="citationList"}")  
    
    隐式省略前缀

    说明:当表达式以 // 或 .// 开头时,Playwright 自动识别为 XPath 定位‌

    # 直接以 "//" 开头时,可省略 "xpath="  
    page.locator("//div[@class='container']/button‌:ml-citation{ref="1" data="citationList"}")  
    

    10.2 XPath 表达式规范

    a. 路径表达式要求

    XPath 表达式需以 // 开头,表示从根节点或任意位置开始匹配‌

    # 正确写法  
    page.locator("xpath=//input[@id='username']")  
    # 错误写法(缺少 "//")  
    page.locator("xpath=input[@id='username']")  # 无法生效  
    
    b. 动态属性与文本匹配

    说明:支持 contains()starts-with() 等函数处理动态生成的属性或文本‌

    # 结合属性与文本的复合定位  
    page.locator("xpath=//button[contains(@class, 'submit') and text()='保存']")  
    # 使用函数处理动态内容  
    page.locator("xpath=//div[starts-with(@id, 'item_')]")  
    
    c. 优先使用相对路径
    # 推荐相对路径(减少对页面结构的依赖)  
    page.locator("xpath=//*[@data-test='login-button']")  
    # 避免完整路径(易受结构变动影响)  
    page.locator("xpath=/html/body/div‌:ml-citation{ref="3" data="citationList"}/div/button")  # 维护成本高‌:ml-citation{ref="1,3" data="citationList"}  
    
    d. 避免过度复杂表达式
    # 复杂表达式示例(可读性差)  
    page.locator("xpath=//div[not(@hidden)]/span[position()=2 and @role='text']")  
    # 可拆解为多条件组合或改用 CSS 选择器‌:ml-citation{ref="3,7" data="citationList"}  
    

    10.3 高级场景与优化

    场景 示例 XPath 说明
    多层级嵌套 //form//input[@name='username'] 跨层级定位表单输入框 ‌2
    索引定位 (//ul/li)‌:ml-citation{ref="3" data="citationList"} 选择列表第三项
    逻辑运算符 //div[@class='card' and @data-type='VIP'] 多条件组合筛选元素 ‌2
    轴定位(Axes) //table//tr/td[following-sibling::td‌:ml-citation{ref="2" data="citationList"}] 定位相邻单元格

    10.4 与其他定位器对比

    定位方式 优势 局限性
    XPath 支持复杂路径、动态属性、跨层级定位 性能略低于 CSS 选择器 ‌
    CSS 选择器 简洁高效,适合静态类名/ID 定位 对动态属性支持较弱
    角色定位(Role) 语义化强,强调可访问性 依赖 ARIA 属性规范 ‌

    10.5 适用场景

  • 动态生成内容‌:如列表项、卡片等无固定属性的元素 ‌。
  • 跨框架页面‌:需穿透 Shadow DOM 时,XPath 需配合 :light 修饰符(Playwright 默认支持常规 DOM)‌。
  • 注意:

    性能优化

  • 避免过长路径(如 //body/div‌:ml-citation{ref="2" data="citationList"}/section‌:ml-citation{ref="1" data="citationList"}/div[...]),优先使用唯一属性或短路径 ‌26。
  • 优先使用 @iddata-testid 等稳定属性替代依赖 DOM 结构的 XPath。
  • 11、CSS选择器 (locator(selector))

    Playwright 的 CSS 选择器支持大多数 CSS 选择器功能,包括类名、ID、属性选择、子元素等。它是最常用的定位方法之一。

    # 定位类名为“menu-link”的元素
    page.locator(".menu-link")
    
    # 定位ID为“username”的输入框
    page.locator("#username")
    
    # 组合选择器
    page.locator("div.menu > a.link-item")
    

    基础用法-基础选择器

    11.1 元素选择器

    直接通过标签名定位元素:

    page.locator("button").click()  # 点击所有按钮中的第一个
    11.2 类与 ID 选择器

    类选择器(.前缀):

    page.locator(".submit-btn").click()   # 定位 class 包含 "submit-btn" 的元素

    ID 选择器(#前缀):

    page.locator("#search-input").fill("test")  # 定位 id="search-input" 的输入框 
    11.3 属性选择器

    通过属性名或值精准定位:

    page.locator("[type='submit']").click()       # 定位 type="submit" 的元素
    page.locator("[placeholder^='Search']").fill("test")  # 匹配以 "Search" 开头的 placeholder 
    
    11.4 层级关系定位

    后代选择器(空格分隔):

    page.locator("body .menu-item")       # 定位 body 内所有 .menu-item 元素
    11.5 直接子代选择器(>分隔)
    page.locator("ul > li:first-child")   # 定位 ul 下的第一个 li 子元素

    高级用法与优化

    11.6 属性操作符
  • ^=:匹配属性值开头(如 [href^='https']
  • $=:匹配属性值结尾(如 [src$='.png'])‌
  • *=:包含子字符串(如 [class*='error'])‌
  • 1‌1.7 组合选择器

    多条件叠加提升精准度:

    page.locator("button.submit[disabled]")  # 定位 class="submit" 且禁用的按钮
    11.8 伪类与状态匹配
  • 伪类::hover:nth-child(n) 等:
    page.locator("tr:nth-child(2)").hover()  # 悬停表格第二行
  • 状态::checked:disabled 等:
    page.locator("input:checked").click()    # 点击已勾选的复选框
    
  • 11.9 动态内容处理

    结合正则表达式或属性通配符应对动态生成的类名/ID:

    page.locator("[class~='dynamic_']").click()  # 匹配包含 "dynamic_" 片段的类名
    11.10 列表项定位优化

    使用 nth-child 或 nth-of-type 定位特定项:

    page.locator("ul.items li:nth-of-type(3)")  # 选择第三个列表项

    与 XPath 的对比

    场景 CSS 选择器优势 注意事项
    静态属性定位 语法简洁,执行效率高(如 .class)‌16 避免过度依赖 DOM 结构层级 ‌17
    动态属性匹配 支持通配符(*=^= 等)‌78 需确保属性值唯一性 ‌7
    伪类与状态交互 直接匹配元素状态(如 :checked)‌27 部分伪类需结合 Playwright 等待机制 ‌6

    注意:

    1. 优先短路径与唯一属性

  • 避免冗长路径(如 body > div > form > input),改用 #id 或 [data-testid] 直接定位。 ‌
  • 12、Frame 内定位 (frame_locator())

    如果元素位于 <iframe> 中,可以使用 frame_locator() 方法进入 iframe,再在其中定位元素。

    # 定位嵌套在 iframe 中的元素
    frame = page.frame_locator("#iframe-id")
    frame.locator("button#submit").click()
    

    13、链式选择器

    Playwright 支持链式定位,使得在复杂页面结构中逐步定位更加灵活。

    # 先找到父级菜单项,再找其中的子项链接
    page.locator("nav.menu").locator("a.link-item").click()
    

    14、过滤定位器

    可以使用 locator.filter() 方法按文本过滤定位器。它将在元素内部的某个位置(可能在后代元素中)搜索特定字符串,不区分大小写。

    注:过滤定位器必须相对于原始定位器,并且从原始定位器匹配开始查询,而不是从文档根开始。

    <ul>
      <li>
        <h3>Product 1</h3>
        <button>Add to cart</button>
      </li>
      <li>
        <h3>Product 2</h3>
        <button>Add to cart</button>
      </li>
    </ul>
    
    # 点击第2个商品对应的按钮
    page.get_by_role("listitem").filter(has_text="Product 2").get_by_role(
        "button", name="Add to cart"
    ).click()
    
    # 正则
    page.get_by_role("listitem").filter(has_text=re.compile("Product 2")).get_by_role(
        "button", name="Add to cart"
    ).click()
    

    作者:黑米粥✎

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python Playwright进阶教程:元素定位详解(二)

    发表回复