4、元素定位进阶:XPath定位、CSS选择器定位、链接文本与部分链接文本定位、标签名定位

好,咱们继续往下走。上一章我们把基础定位方法过了一遍,说实话,那些方法在日常工作中够用,但遇到复杂页面就有点力不从心了。这一章我带你看看更强大的定位方式——说白了,就是让你能精准找到页面上任何一个元素,哪怕它藏得再深。

4.1 XPath定位:最灵活,也最让人头疼

XPath,全称 XML Path Language。你想想看,它本来是为 XML 设计的,但 HTML 和 XML 结构很像,所以拿来用完全没问题。我个人习惯,遇到复杂定位第一个想到的就是 XPath。

4.1.1 绝对路径 vs 相对路径

先看个例子。假设页面上有个登录按钮,用绝对路径写是这样的:

/html/body/div[2]/form/div[4]/button

嗯,这里要注意——绝对路径非常脆弱。只要页面结构稍微调整,比如加了个 div,这个路径就废了。我在项目中遇到过,开发同事改了个布局,我这边 20 多个用例全挂了,排查了半天才发现是路径问题。

所以我强烈建议你用相对路径

//button[@id='loginBtn']

看到了吗?双斜杠开头,表示从任意位置开始查找。这样页面结构怎么变都不怕,只要按钮的 id 没改就行。

4.1.2 常用 XPath 语法

我整理了几个最常用的,你记一下:

表达式 含义 示例
// 从任意节点开始查找 //input
/ 从根节点或当前节点的子节点查找 /html/body
@ 选取属性 //input[@type='text']
text() 匹配文本内容 //button[text()='登录']
contains() 包含匹配 //button[contains(@class,'btn')]
and / or 多条件组合 //input[@type='text' and @name='username']
我的小技巧: 在浏览器开发者工具的控制台里,用 $x('//xpath表达式') 可以快速验证你的 XPath 是否写对了。省得反复跑脚本调试。

4.1.3 实战:定位一个复杂的表格单元格

假设有个表格,你想找到“状态”列里显示“失败”的那一行,然后点击该行的“重试”按钮。用 XPath 可以这样写:

//tr[td[text()='失败']]//button[text()='重试']

这个表达式的逻辑是:先找到包含文本“失败”的 td 所在的 tr,再在这个 tr 里找文本为“重试”的按钮。一层套一层,但思路很清晰。

4.2 CSS选择器定位:又快又简洁

如果你追求速度,CSS 选择器是更好的选择。大多数浏览器对 CSS 选择器的解析速度比 XPath 快。我个人在性能敏感的测试场景下,会优先用 CSS。

4.2.1 基础语法

CSS选择器 含义 示例
.class class属性 .btn-primary
#id id属性 #loginBtn
element 标签名 input
[attribute] 属性选择 [type='text']
parent > child 直接子元素 form > input
parent descendant 后代元素 form input

4.2.2 进阶用法

CSS 选择器还有一些很实用的技巧。比如你想定位页面上第三个 input 元素:

input:nth-child(3)

或者定位 class 包含“btn”但不包含“disabled”的元素:

.btn:not(.disabled)
避坑指南: 我曾经在定位一个动态生成的元素时,发现它的 class 每次刷新都会变。后来用 [class*='btn-'] 这种模糊匹配才搞定。记住,*= 表示包含,^= 表示以什么开头,$= 表示以什么结尾。

4.3 链接文本与部分链接文本定位

这个就简单了,专门用来定位 <a> 标签。说白了就是找链接。

4.3.1 完整文本匹配

driver.find_element(By.LINK_TEXT, "点击这里注册")

注意,文本必须完全一致,多一个空格都不行。我刚开始学的时候,经常因为文本前后有换行符导致定位失败,后来养成了先复制文本的习惯。

4.3.2 部分文本匹配

driver.find_element(By.PARTIAL_LINK_TEXT, "注册")

这个就宽容多了。只要链接文本里包含“注册”两个字就能匹配上。但有个问题——如果页面上有多个链接都包含“注册”,它只会返回第一个。所以尽量用更精确的匹配。

注意: 这两种方法只对 <a> 标签有效。如果你要定位 <button> 或者 <div> 里的文本,得用 XPath 的 text() 方法。

4.4 标签名定位

这个最简单,但也是最容易出问题的。直接用标签名去找元素:

driver.find_element(By.TAG_NAME, "h1")
driver.find_elements(By.TAG_NAME, "input")

你想想看,一个页面上有多少个 div?多少个 span?用标签名定位,基本等于大海捞针。所以我很少用 find_element 配合标签名,除非页面结构非常简单。

find_elements 配合标签名倒是挺实用。比如你想获取页面上所有输入框,然后逐个检查它们的状态:

inputs = driver.find_elements(By.TAG_NAME, "input")
for inp in inputs:
    print(inp.get_attribute("placeholder"))
我的建议: 标签名定位适合做批量操作,比如清空所有输入框、获取所有图片的链接等。但别用它来定位单个元素,太不可靠了。

4.5 如何选择?我的经验总结

说了这么多,你可能会问:到底用哪个好?我个人的选择优先级是这样的:

  1. 优先用 id —— 最快最稳,没有之一
  2. 其次用 CSS 选择器 —— 速度快,语法简洁
  3. 复杂场景用 XPath —— 灵活,能处理各种奇葩情况
  4. 链接文本定位 —— 专门对付 <a> 标签
  5. 标签名定位 —— 批量操作时用

嗯,这里要注意——没有银弹。不同的场景用不同的方法,这才是工程化的思维。我在项目中见过有人死磕 XPath,明明用 CSS 一行就能搞定的事,非要写十几行的 XPath 表达式。没必要,真的没必要。

好了,这一章的内容就到这。下一章我们聊聊等待机制——说白了就是怎么让脚本学会“等一等”,而不是傻乎乎地报错。到时候见。