写XPath时最头疼的是元素属性会变:ID带随机数字、class有多个值、文字带换行。 用精确匹配经常找不到元素,改用模糊匹配和属性选择器就能解决。
核心方法:掌握
contains()、starts-with()、@属性的灵活组合。
一、场景一:class有多个空格分隔的值,用contains
页面上的按钮class往往是
"btn btn-primary large" 这种多值。
直接写 @class='btn btn-primary large' 少一个空格就失效。
解决方法
用
contains(@class, 'btn-primary') 匹配其中任意一个固定部分。
# 捕获元素:确认按钮(class包含btn-primary)

//button[contains(@class, 'btn-primary')]
# 捕获元素:禁用状态的按钮(class包含disabled)
//button[contains(@class, 'disabled') and @disabled]

# 捕获元素:价格区域(class包含price)
//span[contains(@class, 'price')]
二、场景二:ID是动态数字,用starts-with
后台系统的ID经常变化,比如 id="item_123456"、id="order_789",但前缀固定。
# 捕获元素:ID以"item_"开头的div
//div[starts-with(@id, 'item_')]
# 实战案例:拼多多SKU选择面板(ID以sku-panel-开头)

//div[starts-with(@id, 'sku-panel-')]
# 淘宝购物车:checkbox以"check_"开头
//input[starts-with(@id, 'check_') and @type='checkbox']
注意: starts-with 只在开头固定时有效。如果动态部分在中间或结尾,用 contains。
三、场景三:文本含空格或图标,用contains模糊匹配
按钮上的文字可能是“加载更多”、“加载更多 >”、“加载更多…”等等。
用精确的 text()='加载更多' 容易失败。
# 捕获元素:文本包含“加载”的按钮
//button[contains(text(), '加载')]
# 捕获元素:下一页链接(含“下一页”或“next”)
//a[contains(text(), '下一页') or contains(text(), 'next')]
# 捕获元素:包含“已售”的文本(销量)
//span[contains(text(), '已售')]
# 注意:如果文字被其他标签包裹(如<span>已售</span>100件),text()可能取不到
# 改用 contains(., '已售') .代表当前元素内所有文本
//span[contains(., '已售')]
四、场景四:多属性组合定位
单一属性不够精确时,用 and 组合多个条件。
# 捕获元素:input框,type=text 且 name=username
//input[@type='text' and @name='username']
# 捕获元素:按钮,type=submit 且 class包含primary
//button[@type='submit' and contains(@class, 'primary')]
# 捕获元素:链接,href包含product 且 不含disabled类
//a[contains(@href, 'product') and not(contains(@class, 'disabled'))]
五、场景五:或逻辑匹配多个可能
有些弹窗的确定按钮可能是 button 或 a 标签,文本也可能不同。
# 捕获元素:确定按钮(多种可能)
//button[contains(text(),'确定')] | //a[contains(text(),'确定')]
# 或者:匹配登录按钮的几种文本变体
//button[contains(text(),'登录') or contains(text(),'Login') or contains(text(),'Sign in')]

# 注意:竖线表示“或”,两边XPath都要完整,不要空格,否则影刀可能解析错误。
六、模糊匹配速查表
| 需求 | XPath写法 | 示例 |
|---|---|---|
| class包含某值 | contains(@class, 'value') | contains(@class, 'price') |
| ID以某前缀开头 | starts-with(@id, 'prefix') | starts-with(@id, 'post_') |
| 文本包含关键词 | contains(text(), '关键词') | contains(text(), '加载更多') |
| 任意位置文本包含 | contains(., '关键词') | contains(., '已售') |
| 属性不等于某值 | @attr != 'value' | @aria-hidden != 'true' |
| 多个条件同时满足 | 条件1 and 条件2 | @type='submit' and @disabled |
| 多个条件满足其一 | 条件1 or 条件2 | @id='ok' or @class='confirm' |
七、影刀中测试XPath的小技巧
- 点击“捕获元素”,浏览器打开
- 按
Ctrl + F打开XPath搜索框 - 粘贴写好的XPath,回车
- 匹配到的元素会高亮,底部显示匹配数量
如果数量 >1:加更多限定条件(如父级、索引)。 如果数量 =0:检查大小写、标签名、属性名。
八、易错速查表
| 错误 | 原因 | 修复 |
|---|---|---|
| 匹配不到元素 | class写完整值但实际有空格 | 改用 contains(@class,'部分') |
| ID动态变化匹配失败 | 用了@id='xxx' | 改用 starts-with(@id,'固定前缀') |
| 文本匹配失败 | 文本有换行或子标签 | 改用 contains(., '关键词') |
| or逻辑不生效 | 竖线两边有空格或写错 | 写成 `//a |
九、推荐资源
- XPath Helper插件:实时验证模糊匹配表达式
- 影刀官方XPath教程:指令面板搜索“XPath”有案例
- 我的经验:能写模糊匹配就别写精确匹配,容错率高很多
作者:林焱
本文为《影刀RPA学习手册》系列文章之一,内容源于实操经验的整理与分享。
