CSS 选择器定位
本教程共 59 篇 · 第 10 篇 · 更新于 2026-08-04 · 约 9 分钟阅读
本节目标:会用
locator('css=...')写 CSS 定位,了解 Playwright 给 CSS 加的几个好用伪类,并明白为什么 CSS 该当兜底、别当主力。
什么时候才用 CSS
第 9 章列的内置定位器(role、text、label、test id)是首选。它们贴近用户视角,页面一改结构也不容易挂。
但总有角落用不上它们:比如一个没有语义、没有文字、也没 test id 的纯样式 div。这时候 CSS 选择器是合理兜底。
基本写法:
await page.locator('css=button').click();
// 省略前缀也行,Playwright 会自动识别
await page.locator('button').click();
WarningCSS 绑定 DOM 结构。那种
#tsf > div:nth-child(2) > div.A8SBwf > ...的超长链条是反面教材,页面一重构就崩。能用 role 或 test id 就别写它。
Playwright 给 CSS 加了什么
标准 CSS 选择器 Playwright 都认。此外它还做了两处增强:
- CSS 选择器能穿透开放的 Shadow DOM(后面第 16 章细讲)。
- 加了一批自定义伪类,专门好用。
按文字匹配::has-text()
:has-text() 匹配「内部某处含指定文字」的元素,大小写不敏感、会去空白、按子串找。
// 反例:会匹配很多元素,连 <body> 都算,千万别单独用
await page.locator(':has-text("Playwright")').click();
// 正确写法:配合标签限定,只匹配 <article>
await page.locator('article:has-text("Playwright")').click();
还有几个文本伪类:
:text("Home"):匹配含文字的最小元素:text-is("Home"):精确相等(区分大小写):text-matches("reg?ex", "i"):用正则匹配
Note文字匹配永远先规整空白:多个空格并成一个、换行变空格、去首尾空白。
:text-is("Log")匹配不到<button>Log in</button>,因为后者整段文字是 “Log in” 而非 “Log”。
只匹配可见的::visible
css=button 会匹配页面上所有按钮,包括隐藏的。加 :visible 只留看得见的。
// 两个按钮,一个有 display:none;下面这句只点得到的那个
await page.locator('button:visible').click();
含某子元素::has()
:has() 是标准 CSS 伪类。Playwright 完全支持,用来「挑一个内部含某元素的父级」。
await page.locator('article:has(div.promo)').textContent();
按布局凑近::right-of 等
:right-of()、:left-of()、:above()、:below()、:near() 按元素相对位置找。比如页面有多个难区分的输入框时:
// 填「密码」文字右边的那个输入框
await page.locator('input:right-of(:text("Password"))').fill('value');
// 点离促销卡很近的按钮
await page.locator('button:near(.promo-card)').click();
Warning布局选择器官方已标记弃用(deprecated),将来可能移除。布局差一个像素就可能选错元素。能用语义定位器就别碰它。
取第 n 个匹配::nth-match()
当一堆相似元素难区分时,:nth-match(选择器, 序号) 按序号(从 1 开始)取一个。
// 点第三个写着「Buy」的按钮
await page.locator(':nth-match(:text("Buy"), 3)').click();
它还能用来「等够数量出现」:
await page.locator(':nth-match(:text("Buy"), 3)').waitFor();
Note和
:nth-child不同,:nth-match的元素不必是兄弟节点,可以是页面上任意位置。
快捷属性选择器
Playwright 对几个属性给了简写:id、data-testid、data-test-id、data-test。
await page.locator('id=username').fill('value');
await page.locator('data-test-id=submit').click();
Warning官方推荐改用
getByTestId(),第 13 章会讲。这里列出来主要是让你看懂老代码。
Note这类属性选择器不是真 CSS,所以
:enabled这种 CSS 伪类不支持。要带状态判断,用标准的css=[data-test="login"]:enabled。
老式 text= 选择器
还有个遗留写法 text=...,能力类似现代文本定位器,但官方建议用 getByText() 替代:
await page.locator('text=Log in').click(); // 子串、不区分大小写
await page.locator('text="Log in"').click(); // 精确、区分大小写
await page.locator('text=/Log\\s*in/i').click(); // 正则
小结
CSS 定位写 locator('css=...'),前缀省略也行。Playwright 额外送了 :has-text()、:visible、:has()、:nth-match() 这几个好用伪类。
但 CSS 绑定的是 DOM 实现,页面一重构就碎。把它当兜底:role、text、test id 都够不着的时候再上。
下一章讲最贴近用户视角、也是官方首推的按角色定位 getByRole。