3、元素定位基础:CSS选择器、XPath定位、文本定位、相对定位器、定位策略选择
好,咱们进入第三讲。元素定位,说白了就是让浏览器知道「你要操作哪个东西」。我刚开始做自动化的时候,觉得这玩意儿没啥技术含量,不就是找个按钮嘛。结果呢?脚本跑着跑着就报错,一查,元素没找到。嗯,从那以后我再也不敢小看定位了。
这一章,我会把五种主流定位方式掰开揉碎讲清楚。你跟着走一遍,以后遇到任何页面,心里都有底。
3.1 CSS选择器:又快又稳的老大哥
CSS选择器,我个人最常用。为什么?因为它快。浏览器解析CSS选择器是原生支持的,性能上比XPath好不少。我在做双十一大促的自动化脚本时,页面元素几百个,用CSS选择器定位,响应速度明显快一截。
常用的几种写法,我列出来:
| 选择器类型 | 示例 | 说明 |
|---|---|---|
| ID选择器 | #login-btn |
定位id="login-btn"的元素 |
| 类选择器 | .product-card |
定位class包含"product-card"的元素 |
| 属性选择器 | [data-type="submit"] |
定位data-type属性值为submit的元素 |
| 后代选择器 | div .price |
定位div内部class为price的元素 |
| 子元素选择器 | ul > li |
定位ul的直接子元素li |
| 相邻兄弟选择器 | h2 + p |
定位紧跟在h2后面的p元素 |
举个例子,你要定位一个「加入购物车」按钮,它的HTML可能是这样:
<button class="btn btn-primary" data-action="add-to-cart">加入购物车</button>
用CSS选择器可以这么写:
button.btn-primary[data-action="add-to-cart"]
你看,组合使用类选择器和属性选择器,定位非常精准。我在项目中遇到过一个问题:页面上有多个「加入购物车」按钮,但只有一个是当前商品对应的。这时候加上属性选择器,就能精确锁定目标。
3.2 XPath定位:功能最全的瑞士军刀
XPath,功能是真的强。它能往上找父元素,能根据文本内容定位,还能做复杂的逻辑判断。CSS选择器做不到的,它基本都能做。但代价是什么?性能稍差,语法也啰嗦一些。
XPath有两种写法,我简单说一下:
- 绝对路径:从根节点开始写,比如
/html/body/div[2]/div[1]/button。这种写法很脆弱,页面结构稍微一变就挂了。我从来不用。 - 相对路径:用
//开头,比如//button[@class='btn-primary']。灵活,好维护,推荐。
常用的XPath表达式:
| 表达式 | 示例 | 说明 |
|---|---|---|
| 根据属性定位 | //input[@id='username'] |
定位id为username的input |
| 根据文本定位 | //button[text()='提交订单'] |
定位文本为"提交订单"的按钮 |
| 包含文本 | //span[contains(text(),'优惠')] |
定位文本包含"优惠"的span |
| 多条件组合 | //div[@class='item' and @data-id='123'] |
同时满足两个条件 |
| 轴定位 | //label[@for='email']/following-sibling::input |
定位label后面的兄弟元素input |
[0],结果死活定位不到。查了半天文档才发现这个坑。你记住,XPath里 [1] 才是第一个元素。
举个例子,你想定位一个「确认删除」的弹窗按钮,但页面上可能有多个弹窗。这时候可以结合文本定位:
//div[contains(@class,'modal')]//button[text()='确认删除']
先找到弹窗容器,再在里面找按钮。这样即使页面其他地方有同名按钮,也不会误定位。
3.3 文本定位:最直观的方式
文本定位,说白了就是「看到什么就定位什么」。你想想看,用户操作页面时,眼睛看的是文字,手点的是按钮。那自动化脚本为什么不能直接用文字来定位呢?
在Selenium 4里,文本定位被正式支持了。有两种:
By.LINK_TEXT:精确匹配链接文本By.PARTIAL_LINK_TEXT:模糊匹配链接文本
不过要注意,这两个只能用于 <a> 标签。如果你想定位普通元素的文本,还是得用XPath的 text() 函数。
举个例子:
# 精确匹配
driver.find_element(By.LINK_TEXT, "查看订单详情")
# 模糊匹配
driver.find_element(By.PARTIAL_LINK_TEXT, "订单")
我在项目中遇到过一个问题:一个「立即购买」按钮,它的文本是动态生成的,有时候是「立即购买」,有时候是「马上抢购」。这时候用精确匹配就不行了,得用 contains(text(),'购买') 或者 PARTIAL_LINK_TEXT。
3.4 相对定位器:Selenium 4的新玩具
相对定位器,是Selenium 4引入的新功能。它允许你根据元素之间的相对位置来定位。比如「在某个元素左边的按钮」、「在某个元素下方的输入框」。
常用的相对定位方法:
| 方法 | 说明 |
|---|---|
above() |
定位目标元素上方的元素 |
below() |
定位目标元素下方的元素 |
toLeftOf() |
定位目标元素左侧的元素 |
toRightOf() |
定位目标元素右侧的元素 |
near() |
定位目标元素附近(50像素内)的元素 |
举个例子,你有一个商品列表,每个商品下面都有一个「加入购物车」按钮。你想定位第三个商品下面的按钮,可以这样:
from selenium.webdriver.support.relative_locator import locate_with
# 先找到第三个商品
third_product = driver.find_element(By.XPATH, "//div[@class='product'][3]")
# 再定位它下方的按钮
add_cart_btn = driver.find_element(
locate_with(By.TAG_NAME, "button").below(third_product)
)
3.5 定位策略选择:什么时候用什么
好,五种定位方式都讲完了。你可能会问:那我到底该用哪个?
我个人的选择优先级是这样的:
- 优先用ID:如果元素有唯一的ID,直接用
By.ID。最快,最稳。 - 其次用CSS选择器:ID没有,就用CSS。性能好,语法简洁。
- 文本定位做补充:链接、按钮这些,用文本定位最直观。
- XPath兜底:前面都不行,或者需要复杂逻辑(比如根据文本、属性、层级组合定位),上XPath。
- 相对定位器处理特殊场景:比如「某个元素旁边的按钮」,用相对定位器最合适。
我总结了一个简单的决策表:
| 场景 | 推荐定位方式 | 示例 |
|---|---|---|
| 元素有唯一ID | By.ID | #submit-btn |
| 元素有唯一class或属性 | CSS选择器 | .btn-primary |
| 需要根据文本定位 | XPath text() 或 LINK_TEXT | //button[text()='提交'] |
| 需要根据相对位置定位 | 相对定位器 | below(element) |
| 需要复杂逻辑组合 | XPath | //div[@class='item' and .//span='价格'] |
| 页面结构经常变化 | 文本定位或相对定位器 | 减少对DOM结构的依赖 |
核心原则: 定位器越简单越好,越稳定越好。不要为了炫技写复杂的XPath,能用一行CSS搞定的,别写五行的XPath。你想想看,脚本是要长期维护的,简单的东西出错的概率更低。
嗯,这一章的内容就到这里。五种定位方式,每一种都有它的用武之地。你平时写脚本的时候,多试试不同的方式,慢慢就会形成自己的判断。下一章,咱们聊聊「等待机制」,这可是解决脚本不稳定问题的关键。