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*='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 如何选择?我的经验总结
说了这么多,你可能会问:到底用哪个好?我个人的选择优先级是这样的:
- 优先用 id —— 最快最稳,没有之一
- 其次用 CSS 选择器 —— 速度快,语法简洁
- 复杂场景用 XPath —— 灵活,能处理各种奇葩情况
- 链接文本定位 —— 专门对付
<a>标签 - 标签名定位 —— 批量操作时用
嗯,这里要注意——没有银弹。不同的场景用不同的方法,这才是工程化的思维。我在项目中见过有人死磕 XPath,明明用 CSS 一行就能搞定的事,非要写十几行的 XPath 表达式。没必要,真的没必要。
好了,这一章的内容就到这。下一章我们聊聊等待机制——说白了就是怎么让脚本学会“等一等”,而不是傻乎乎地报错。到时候见。