Skip to main content

选择器

Selector 是用于创建 Locator 的字符串。Locator 用于通过诸如 locator.click(**kwargs)locator.fill(value, **kwargs) 等方法对元素执行操作。有关调试 selector 的信息,请参阅 此处

编写好的 selector 既是一门艺术,也是一门科学,因此请务必查看 最佳实践 部分。

快速指南

  • 文本选择器

    page.locator("text=Log in").click()

    了解更多关于 文本选择器 的信息。

  • CSS 选择器

    page.locator("button").click()
    page.locator("#nav-bar .contact-us-item").click()

    了解更多关于 css 选择器 的信息。

  • 通过属性选择,使用 css 选择器

    page.locator("[data-test=login-button]").click()
    page.locator("[aria-label='Sign in']").click()

    了解更多关于 css 选择器 的信息。

  • 组合 css 和文本选择器

    page.locator("article:has-text('Playwright')").click()
    page.locator("#nav-bar :text('Contact us')").click()

    了解更多关于 :has-text():text() 伪类 的信息。

  • 包含另一个元素的元素,使用 css 选择器

    page.locator(".item-description:has(.item-promo-banner)").click()

    了解更多关于 :has() 伪类 的信息。

  • 基于布局选择,使用 css 选择器

    page.locator("input:right-of(:text('Username'))").click()

    了解更多关于 布局选择器 的信息。

  • 仅可见元素,使用 css 选择器

    page.locator(".login-button:visible").click()

    了解更多关于 选择可见元素 的信息。

  • 选择第 n 个匹配项

    page.locator(":nth-match(:text('Buy'), 3)").click()

    了解更多关于 :nth-match() 伪类 的信息。

  • XPath 选择器

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

    了解更多关于 XPath 选择器 的信息。

  • React 选择器 (实验性)

    page.locator("_react=ListItem[text *= 'milk' i]").click()

    了解更多关于 React 选择器 的信息。

  • Vue 选择器 (实验性)

    page.locator("_vue=list-item[text *= 'milk' i]").click()

    了解更多关于 Vue 选择器 的信息。

文本选择器

文本选择器定位包含传递文本的元素。

page.locator("text=Log in").click()

文本选择器有几种变体:

  • text=Log in - 默认匹配不区分大小写,修剪空格并搜索子字符串。例如,text=Log 匹配 <button>Log in</button>

    page.locator("text=Log in").click()
  • text="Log in" - 文本主体可以用单引号或双引号转义,以搜索修剪空格后具有确切内容的文本节点。例如,text="Log" 不匹配 <button>Log in</button>,因为 <button> 包含一个不等于 "Log" 的单个文本节点 "Log in"。但是,text="Log" 匹配 <button> Log <span>in</span></button>,因为 <button> 包含一个文本节点 " Log "。这种精确模式意味着区分大小写的匹配,因此 text="Download" 将不匹配 <button>download</button>

    引用的主体遵循通常的转义规则,例如使用 \" 在双引号字符串中转义双引号:text="foo\"bar"

    page.locator("text='Log in'").click()
  • "Log in" - 以引号("')开头和结尾的选择器被假定为文本选择器。例如,"Log in" 在内部转换为 text="Log in"

    page.locator("'Log in'").click()
  • /Log\s*in/i - 主体可以是包裹在 / 符号中的 类 JavaScript 正则表达式。例如,text=/Log\s*in/i 匹配 <button>Login</button><button>log IN</button>

    page.locator("text=/Log\s*in/i").click()
  • article:has-text("Playwright") - :has-text() 伪类可以在 css 选择器内部使用。它匹配内部某处包含指定文本的任何元素,可能在子元素或后代元素中。匹配不区分大小写,修剪空格并搜索子字符串。例如,article:has-text("Playwright") 匹配 <article><div>Playwright</div></article>

    请注意,:has-text() 应与其他 css 说明符一起使用,否则它将匹配包含指定文本的所有元素,包括 <body>

    # Wrong, will match many elements including <body>
    page.locator(':has-text("Playwright")').click()
    # Correct, only matches the <article> element
    page.locator('article:has-text("All products")').click()
  • #nav-bar :text("Home") - :text() 伪类可以在 css 选择器内部使用。它匹配包含指定文本的最小元素。此示例等效于 text=Home,但在 #nav-bar 元素内部。

    page.locator("#nav-bar :text('Home')").click()
  • #nav-bar :text-is("Home") - :text-is() 伪类可以在 css 选择器内部使用,用于严格的文本节点匹配。此示例等效于 text="Home"(注意引号),但在 #nav-bar 元素内部。

  • #nav-bar :text-matches("reg?ex", "i") - :text-matches() 伪类可以在 css 选择器内部使用,用于基于正则表达式的匹配。此示例等效于 text=/reg?ex/i,但在 #nav-bar 元素内部。
note

匹配总是规范化空格。例如,它将多个空格转换为一个,将换行符转换为空格,并忽略前导和尾随空格。

note

类型为 buttonsubmit 的输入元素通过其 value 而不是文本内容进行匹配。例如,text=Log in 匹配 <input type=button value="Log in">

CSS 选择器

Playwright 以两种方式增强了标准 CSS 选择器:

  • css 引擎默认穿透 shadow DOM。
  • Playwright 添加了自定义伪类,如 :visible:text 等。
page.locator("button").click()

选择可见元素

在 Playwright 中有两种方法仅选择 可见 元素:

  • CSS 选择器中的 :visible 伪类
  • visible= 选择器引擎

如果您希望您的选择器是 CSS 并且不想依赖 链式选择器,请像这样使用 :visible 伪类:input:visible。如果您更喜欢组合选择器引擎,请使用 input >> visible=true。后者允许您将 text=xpath= 和其他选择器引擎与可见性过滤器结合使用。

例如,input 匹配页面上的所有输入,而 input:visibleinput >> visible=true 仅匹配可见输入。这对于区分非常相似但在可见性方面不同的元素很有用。

note

通常最好遵循 最佳实践 并找到更可靠的方法来唯一标识元素。

考虑一个带有两个按钮的页面,第一个不可见,第二个可见。

<button style='display: none'>Invisible</button>
<button>Visible</button>
  • 这将找到第一个按钮,因为它是 DOM 顺序中的第一个元素。然后它将等待按钮变为可见再单击,或者在等待时超时:

    page.locator("button").click()
  • 这些将找到第二个按钮,因为它是可见的,然后单击它。

    page.locator("button:visible").click()
    page.locator("button >> visible=true").click()

选择包含其他元素的元素

按文本过滤

Locator 支持一个选项,仅选择内部某处(可能在后代元素中)具有某些文本的元素。匹配不区分大小写并搜索子字符串。

page.locator("button", has_text="Click me").click()

您也可以传递正则表达式。

按另一个 locator 过滤

Locator 支持一个选项,仅选择具有匹配另一个 locator 的后代的元素。

page.locator("article", has=page.locator("button.subscribe"))

请注意,内部 locator 是从外部 locator 开始匹配的,而不是从文档根目录开始。

在 CSS 选择器内部

:has() 伪类是一个 实验性 CSS 伪类。如果作为参数传递的任何选择器相对于给定元素的 :scope 匹配至少一个元素,则返回该元素。

以下代码段返回内部具有 <div class=promo><article> 元素的文本内容。

page.locator("article:has(div.promo)").text_content()

增强现有的 locators

您可以通过将 :scope 选择器传递给 locator.locator(selector, **kwargs) 并指定所需的选项来向任何 locator 添加过滤。例如,给定选择表中某些行的 locator row,您可以过滤为仅包含文本 "Hello" 的那些行。

row = page.locator(".row")
# ... later on ...
row.locator(":scope", has_text="Hello").click()

选择匹配条件之一的元素

CSS 选择器列表

逗号分隔的 CSS 选择器列表将匹配可以由该列表中选择器之一选择的所有元素。

# Clicks a <button> that has either a "Log in" or "Sign in" text.
page.locator('button:has-text("Log in"), button:has-text("Sign in")').click()

:is() 伪类是一个 实验性 CSS 伪类,对于指定元素上的额外条件列表可能很有用。

XPath 联合

管道运算符 (|) 可用于在 XPath 中指定多个选择器。它将匹配可以由该列表中选择器之一选择的所有元素。

# Waits for either confirmation dialog or load spinner.
page.locator("//span[contains(@class, 'spinner__loading')]|//div[@id='confirmation']").wait_for()

在 Shadow DOM 中选择元素

Playwright 的 csstext 引擎默认穿透 Shadow DOM

  • 首先,它们按迭代顺序在 light DOM 中搜索元素,并且
  • 然后,它们按迭代顺序在打开的 shadow roots 内部递归搜索。

特别是,在 css 引擎中,任何 后代组合器子组合器 都会穿透任意数量的打开 shadow roots,包括选择器开头的隐式后代组合器。它不会在关闭的 shadow roots 或 iframes 内部搜索。

如果您想退出此行为,可以使用 :light CSS 扩展或 text:light 选择器引擎。它们不穿透 shadow roots。

page.locator(":light(.article > .header)").click()

更高级的 Shadow DOM 用例:

<article>
<div>In the light dom</div>
<div slot='myslot'>In the light dom, but goes into the shadow slot</div>
#shadow-root
<div class='in-the-shadow'>
<span class='content'>
In the shadow dom
#shadow-root
<li id='target'>Deep in the shadow</li>
</span>
</div>
<slot name='myslot'></slot>
</article>
  • "article div"":light(article div)" 都匹配第一个 <div>In the light dom</div>
  • "article > div"":light(article > div)" 都匹配作为 article 直接子元素的两个 div 元素。
  • "article .in-the-shadow" 匹配 <div class='in-the-shadow'>,穿透 shadow root,而 ":light(article .in-the-shadow)" 不匹配任何内容。
  • ":light(article div > span)" 不匹配任何内容,因为两个 light-dom div 元素都不包含 span
  • "article div > span" 匹配 <span class='content'>,穿透 shadow root。
  • "article > .in-the-shadow" 不匹配任何内容,因为 <div class='in-the-shadow'> 不是 article 的直接子元素。
  • ":light(article > .in-the-shadow)" 不匹配任何内容。
  • "article li#target" 匹配 <li id='target'>Deep in the shadow</li>,穿透两个 shadow roots。

基于布局选择元素

有时,当目标元素缺乏明显的特征时,很难为其想出一个好的选择器。在这种情况下,使用 Playwright 布局选择器可能会有所帮助。这些可以与常规 CSS 结合使用以精确定位多个选择之一。

例如,input:right-of(:text("Password")) 匹配位于文本 "Password" 右侧的输入字段 - 当页面有多个难以相互区分的输入时很有用。

请注意,布局选择器通常与其他选择器(如 input)结合使用。如果单独使用布局选择器,如 :right-of(:text("Password")),您很可能得到的不是您正在寻找的输入,而是文本和目标输入之间的一些空元素。

note

布局选择器取决于页面布局,可能会产生意想不到的结果。例如,当布局改变一个像素时,可能会匹配不同的元素。

布局选择器使用 bounding client rect 来计算元素的距离和相对位置。

  • :right-of(inner > selector) - 匹配位于匹配内部选择器的任何元素右侧的元素,处于任何垂直位置。
  • :left-of(inner > selector) - 匹配位于匹配内部选择器的任何元素左侧的元素,处于任何垂直位置。
  • :above(inner > selector) - 匹配位于匹配内部选择器的任何元素上方的元素,处于任何水平位置。
  • :below(inner > selector) - 匹配位于匹配内部选择器的任何元素下方的元素,处于任何水平位置。
  • :near(inner > selector) - 匹配位于匹配内部选择器的任何元素附近(50 CSS 像素内)的元素。

请注意,生成的匹配项按其与锚元素的距离排序,因此您可以使用 locator.first 来选择最近的一个。这仅在您有类似元素列表的情况下有用,其中最近的一个显然是正确的。但是,在其他情况下使用 locator.first 很可能无法按预期工作 - 它不会针对您正在搜索的元素,而是碰巧最近的其他元素,如随机空的 <div>,或者是滚动出且当前不可见的元素。

# Fill an input to the right of "Username".
page.locator("input:right-of(:text(\"Username\"))").fill("value")

# Click a button near the promo card.
page.locator("button:near(.promo-card)").click()

# Click the radio input in the list closest to the "Label 3".
page.locator("[type=radio]:left-of(:text(\"Label 3\"))").first.click()

所有布局选择器都支持可选的最大像素距离作为最后一个参数。例如 button:near(:text("Username"), 120) 匹配距离文本为 "Username" 的元素最多 120 像素的按钮。

通过标签文本选择元素

Playwright 中的目标输入操作会自动区分标签和控件,因此您可以定位标签以对关联的控件执行操作。

例如,考虑以下 DOM 结构:<label for="password">Password:</label><input id="password" type="password">。您可以使用类似 text=Password 的内容定位标签,并对输入执行以下操作:

  • click 将单击标签并自动聚焦输入字段;
  • fill 将填充输入字段;
  • inputValue 将返回输入字段的值;
  • selectText 将选择输入字段中的文本;
  • setInputFiles 将为 type=file 的输入字段设置文件;
  • selectOption 将从选择框中选择一个选项。
# Fill the input by targeting the label.
page.locator('text=Password').fill('secret')

但是,其他方法将针对标签本身,例如 textContent 将返回标签的文本内容,而不是输入字段。

XPath 选择器

XPath 选择器等效于调用 Document.evaluate。示例:xpath=//html/body

//.. 开头的选择器被假定为 xpath 选择器。例如,Playwright 将 '//html/body' 转换为 'xpath=//html/body'

note

xpath 不穿透 shadow roots

第 n 个元素选择器

您可以使用 nth= 选择器将查询范围缩小到第 n 个匹配项。与 CSS 的 nth-match 不同,提供的索引是从 0 开始的。

# Click first button
page.locator("button >> nth=0").click()

# Click last button
page.locator("button >> nth=-1").click()

React 选择器

note

React 选择器是实验性的,前缀为 _。功能可能会在未来发生变化。

React 选择器允许通过组件名称和属性值选择元素。语法与 属性选择器 非常相似,并支持所有属性选择器运算符。

在 react 选择器中,组件名称使用 CamelCase 转录。

选择器示例:

  • 组件 匹配:_react=BookItem
  • 按组件和 确切属性值 匹配,区分大小写:_react=BookItem[author = "Steven King"]
  • 仅按属性值匹配,不区分大小写_react=[author = "steven king" i]
  • 按组件和 真值属性值 匹配:_react=MyButton[enabled]
  • 按组件和 布尔值 匹配:_react=MyButton[enabled = false]
  • 按属性 值子字符串 匹配:_react=[author *= "King"]
  • 按组件和 多个属性 匹配:_react=BookItem[author *= "king" i][year = 1990]
  • 嵌套 属性值匹配:_react=[some.nested.value = 12]
  • 按组件和属性值 前缀 匹配:_react=BookItem[author ^= "Steven"]
  • 按组件和属性值 后缀 匹配:_react=BookItem[author $= "Steven"]
  • 按组件和 key 匹配:_react=BookItem[key = '2']
  • 按属性值 正则表达式 匹配:_react=[author = /Steven(\\s+King)?/i]

要在树中查找 React 元素名称,请使用 React DevTools

note

React 选择器支持 React 15 及更高版本。

note

React 选择器以及 React DevTools,仅适用于 未压缩 的应用程序构建。

Vue 选择器

note

Vue 选择器是实验性的,前缀为 _。功能可能会在未来发生变化。

Vue 选择器允许通过组件名称和属性值选择元素。语法与 属性选择器 非常相似,并支持所有属性选择器运算符。

在 Vue 选择器中,组件名称使用 kebab-case 转录。

选择器示例:

  • 组件 匹配:_vue=book-item
  • 按组件和 确切属性值 匹配,区分大小写:_vue=book-item[author = "Steven King"]
  • 仅按属性值匹配,不区分大小写_vue=[author = "steven king" i]
  • 按组件和 真值属性值 匹配:_vue=my-button[enabled]
  • 按组件和 布尔值 匹配:_vue=my-button[enabled = false]
  • 按属性 值子字符串 匹配:_vue=[author *= "King"]
  • 按组件和 多个属性 匹配:_vue=book-item[author *= "king" i][year = 1990]
  • 嵌套 属性值匹配:_vue=[some.nested.value = 12]
  • 按组件和属性值 前缀 匹配:_vue=book-item[author ^= "Steven"]
  • 按组件和属性值 后缀 匹配:_vue=book-item[author $= "Steven"]
  • 按属性值 正则表达式 匹配:_vue=[author = /Steven(\\s+King)?/i]

要在树中查找 Vue 元素名称,请使用 Vue DevTools

note

Vue 选择器支持 Vue2 及更高版本。

note

Vue 选择器以及 Vue DevTools,仅适用于 未压缩 的应用程序构建。

Role 选择器

Role 选择器允许通过其 ARIA roleARIA 属性可访问名称 选择元素。请注意,role 选择器 不能替代 可访问性审计和一致性测试,而是提供有关 ARIA 指南的早期反馈。

语法与 CSS 属性选择器 非常相似。例如,role=button[name="Click me"][pressed] 选择具有可访问名称 "Click me" 的按下按钮。

请注意,许多 html 元素具有由 role 选择器识别的隐式 定义角色。您可以在 此处找到所有支持的角色。ARIA 指南 不建议 通过将 role 和/或 aria-* 属性设置为默认值来复制隐式角色和属性。

Role 选择器支持的属性:

  • checked - 通常由 aria-checked 或本机 <input type=checkbox> 控件设置的属性。checked 的可用值为 truefalse"mixed"。示例:

    • role=checkbox[checked=true],等效于 role=checkbox[checked]
    • role=checkbox[checked=false]
    • role=checkbox[checked="mixed"]

    了解更多关于 aria-checked 的信息。

  • disabled - 通常由 aria-disableddisabled 设置的布尔属性。示例:

    • role=button[disabled=true],等效于 role=button[disabled]
    • role=button[disabled=false]

    请注意,与大多数其他属性不同,disabled 通过 DOM 层次结构继承。了解更多关于 aria-disabled 的信息。

  • expanded - 通常由 aria-expanded 设置的布尔属性。示例:

    • role=button[expanded=true],等效于 role=button[expanded]
    • role=button[expanded=false]

    了解更多关于 aria-expanded 的信息。

  • include-hidden - 控制是否匹配隐藏元素的布尔属性。默认情况下,role 选择器仅匹配 ARIA 定义 的非隐藏元素。使用 [include-hidden],匹配隐藏和非隐藏元素。示例:

    • role=button[include-hidden=true],等效于 role=button[include-hidden]
    • role=button[include-hidden=false]

    了解更多关于 aria-hidden 的信息。

  • level - 通常出现在角色 headinglistitemrowtreeitem 中的数字属性,<h1>-<h6> 元素的默认值。示例:

    • role=heading[level=1]

    了解更多关于 aria-level 的信息。

  • name - 匹配 可访问名称 的字符串属性。支持像 =*= 这样的属性运算符,以及正则表达式。

    • role=button[name="Click me"]
    • role=button[name*="Click"]
    • role=button[name=/Click( me)?/]

    了解更多关于 可访问名称 的信息。

  • pressed - 通常由 aria-pressed 设置的属性。pressed 的可用值为 truefalse"mixed"。示例:

    • role=button[pressed=true],等效于 role=button[pressed]
    • role=button[pressed=false]
    • role=button[pressed="mixed"]

    了解更多关于 aria-pressed 的信息。

  • selected - 通常由 aria-selected 设置的布尔属性。示例:

    • role=option[selected=true],等效于 role=option[selected]
    • role=option[selected=false]

    了解更多关于 aria-selected 的信息。

示例:

  • role=button 匹配所有按钮;
  • role=button[name="Click me"] 匹配具有 "Click me" 可访问名称的按钮;
  • role=checkbox[checked][include-hidden] 匹配已选中的复选框,包括当前隐藏的复选框。

id, data-testid, data-test-id, data-test 选择器

Playwright 支持使用某些属性选择元素的简写。目前,仅支持以下属性:

  • id
  • data-testid
  • data-test-id
  • data-test
# Fill an input with the id "username"
page.locator('id=username').fill('value')

# Click an element with data-test-id "submit"
page.locator('data-test-id=submit').click()
note

属性选择器不是 CSS 选择器,因此不支持任何特定于 CSS 的内容,如 :enabled。要获得更多功能,请使用适当的 css 选择器,例如 css=[data-test="login"]:enabled

note

属性选择器穿透 shadow DOM。要退出此行为,请在属性后使用 :light 后缀,例如 page.locator('data-test-id:light=submit').click()

从查询结果中选择第 n 个匹配项

有时页面包含许多相似的元素,很难选择特定的一个。例如:

<section> <button>Buy</button> </section>
<article><div> <button>Buy</button> </div></article>
<div><div> <button>Buy</button> </div></div>

在这种情况下,:nth-match(:text("Buy"), 3) 将选择上面代码段中的第三个按钮。请注意,索引是从 1 开始的。

# Click the third "Buy" button
page.locator(":nth-match(:text('Buy'), 3)").click()

:nth-match() 对于等待指定数量的元素出现也很有用,使用 locator.wait_for(**kwargs)

# Wait until all three buttons are visible
page.locator(":nth-match(:text('Buy'), 3)").wait_for()
note

:nth-child() 不同,元素不必是兄弟元素,它们可以在页面上的任何位置。在上面的代码段中,所有三个按钮都匹配 :text("Buy") 选择器,并且 :nth-match() 选择第三个按钮。

note

通常可以通过某些属性或文本内容来区分元素。在这种情况下,优先使用 textcss 选择器而不是 :nth-match()

父选择器

可以使用 .. 选择父级,这是 xpath=.. 的缩写形式。

例如:

parent_locator = element_locator.locator('..')

链式选择器

定义为 engine=body 或缩写形式的选择器可以与 >> 标记组合,例如 selector1 >> selector2 >> selectors3。当选择器被链接时,下一个选择器是相对于上一个选择器的结果进行查询的。

例如,

css=article >> css=.bar > .baz >> css=span[attr=value]

等效于

document
.querySelector('article')
.querySelector('.bar > .baz')
.querySelector('span[attr=value]')

如果选择器需要在主体中包含 >>,则应在字符串内转义,以免与链式分隔符混淆,例如 text="some >> text"

中间匹配

默认情况下,链式选择器解析为最后一个选择器查询的元素。选择器可以以 * 为前缀,以捕获中间选择器查询的元素。

例如,css=article >> text=Hello 捕获具有文本 Hello 的元素,而 *css=article >> text=Hello(注意 *)捕获包含具有文本 Hello 的元素的 article 元素。

最佳实践

选择器的选择决定了自动化脚本的弹性。为了减少维护负担,我们建议优先考虑面向用户的属性和显式契约。

优先考虑面向用户的属性

文本内容、输入占位符、可访问性角色和标签等属性是很少更改的面向用户的属性。这些属性不受 DOM 结构更改的影响。

以下示例使用内置的 textcss 选择器引擎。

# queries "Login" text selector
page.locator('text="Login"').click()
page.locator('"Login"').click() # short-form

# queries "Search GitHub" placeholder attribute
page.locator('css=[placeholder="Search GitHub"]').fill('query')
page.locator('[placeholder="Search GitHub"]').fill('query') # short-form

# queries "Close" accessibility label
page.locator('css=[aria-label="Close"]').click()
page.locator('[aria-label="Close"]').click() # short-form

# combine role and text queries
page.locator('css=nav >> text=Login').click()

定义显式契约

当面向用户的属性经常更改时,建议使用显式测试 ID,如 data-test-id。这些 data-* 属性受 cssid 选择器 支持。

<button data-test-id="directions">Itinéraire</button>
# queries data-test-id attribute with css
page.locator('css=[data-test-id=directions]').click()
page.locator('[data-test-id=directions]').click() # short-form

# queries data-test-id with id
page.locator('data-test-id=directions').click()

避免绑定到实现的选择器

xpathcss 可以绑定到 DOM 结构或实现。当 DOM 结构更改时,这些选择器可能会中断。同样,locator.nth(index)locator.firstlocator.last 绑定到实现和 DOM 结构,如果 DOM 更改,将针对不正确的元素。

# avoid long css or xpath chains
page.locator('#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input').click()
page.locator('//*[@id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input').click()