做元素定位时,经常遇到目标元素本身没有id、没有class,甚至它的父元素也没有固定属性。
但往上一层,祖父元素或者曾祖父元素有固定id,这时候就需要层级定位——从稳定的祖先元素开始,一层层往下找到目标。
XPath的child::轴(可简写为/)专门用来做层级定位,配合*通配符和索引,能搞定90%的“没有属性”难题。
我非技术出身,一开始觉得轴语法很吓人,后来发现就是“父/子/孙”的路径写法。
一、什么是层级定位:从爷爷找到孙子
场景
页面结构如下,目标是一个<span>,没有任何属性,但它的爷爷<div>有固定id。
<div id="app">
<div class="container">
<div class="row">
<span>目标文本</span>

</div>
</div>
</div>
XPath写法
//*[@id='app']/div/div/span
或使用child::显式写法:
//*[@id='app']/child::div/child::div/child::span
影刀操作
- 捕获祖父元素(有id的那个
div) - 在元素库里,把XPath改成上面这种路径
- 用“高亮元素”测试能否定位到
<span>
二、child::轴的核心用法
语法
祖先元素/child::标签名[索引]
child::表示“直接子元素”,可以省略为/- 索引从1开始,
[1]表示第一个子元素
常用写法
| 写法 | 含义 |
|---|---|
//div[@id='app']/span | id为app的div下的直接子元素span |
//div[@id='app']/* | 所有直接子元素(不限标签) |
//div[@id='app']/div[2] | 第二个直接子元素(必须是div) |
//div[@id='app']/child::*[3] | 第三个直接子元素(不限标签) |
实战:定位表格里的第3行第2列
//table[@id='data-table']/tbody/tr[3]/td[2]
三、深入任意层级:用//跳过中间层
如果不想精确写出每一层(比如中间层数会变化),可以用//表示“跳过任意层”。
//*[@id='app']//span
这个XPath会匹配<div id="app">下所有层级的<span>,不管嵌套多深。
什么时候用/,什么时候用//?
| 符号 | 含义 | 稳定性 | 适用场景 |
|---|---|---|---|
/ | 直接子元素 | 高(路径严格) | 结构固定,层级明确 |
// | 任意后代 | 低(可能匹配多个) | 中间层会变,但最终元素唯一 |
建议: 优先用/,除非中间层级确实会变化。用//时要加更多限制确保唯一性。
四、结合标签名和属性缩小范围
层级路径很长时,可以在中间层加[]条件过滤,减少对精确层级的依赖。
示例:定位登录表单里的密码输入框
<div id="login-form">
<div class="field-group">
<div class="label">密码</div>
<input type="password">
</div>

</div>
精确路径:
//*[@id='login-form']/div/div[2]/input
问题:如果多了一个div包装,路径就断了。
改进:用属性过滤中间层
//*[@id='login-form']//div[contains(@class,'field-group')]/input
跳过中间不确定的层,直接定位到包含class='field-group'的div,再找子元素input。
五、实战案例:拼多多商品卡片的价格定位
页面结构(简化)
<div data-testid="goods-card">
<div class="goods-info">
<div class="title">商品标题</div>
<div class="price-box">
<span class="price">¥99.00</span>
</div>
</div>
</div>
层级定位方案
方案1:基于父卡片
//div[@data-testid='goods-card']//span[contains(@class,'price')]
方案2:精确路径(结构稳定时)
//div[@data-testid='goods-card']/div/div/span
方案3:结合属性和层级
//div[@data-testid='goods-card']/div/div[@class='price-box']/span
在影刀中推荐方案3,既不过分依赖层级数量,又不至于太宽泛。
六、child::与following-sibling/preceding-sibling的区别
| 轴 | 方向 | 层级关系 | 适用场景 |
|---|---|---|---|
| child:: | 向下 | 父子 | 从父找子 |
| following-sibling | 水平 | 兄弟(向后) | 从参照元素往后找兄弟 |
| preceding-sibling | 水平 | 兄弟(向前) | 从参照元素往前找兄弟 |
组合使用: 先通过兄弟定位,再往下找子元素。
示例
<div class="user">
<span class="label">小红书号:</span>
<div class="detail">
<span class="id">123456</span>
</div>
</div>
想取数字123456,但<div class="detail">没有唯一属性。
方案: 先定位“小红书号:”文本,找它的following-sibling,再往下找子元素。
//*[contains(text(),'小红书号:')]/following-sibling::div/span
七、避免过深层级的3个技巧
技巧1:找最近的有属性祖先
不要从html或body开始写,从最近的有id或固定class的祖先开始。
❌ 差:/html/body/div[3]/div[2]/div[1]/span
✅ 好://div[@id='content']//span
技巧2:用相对路径(.//)在循环中定位
在“获取相似元素列表”的循环里,基于当前元素用.//往下找。
.//span[@class='price']
不需要写完整的祖先路径。
技巧3:结合文本定位
如果元素唯一的特征是里面的文本,可以用//*[contains(text(),'固定文本')]直接定位,绕开层级。
//*[contains(text(),'立即购买')]
八、影刀中调试层级XPath的方法
- 在XPath Helper中测试(参考选题池7号)
- 分段测试:先测试祖先XPath,确认高亮正确,再逐级加
/子元素 - 用通配符
*代替不确定的标签名,比如/*/*/span,看能匹配到几个
示例分段测试
//*[@id='app'] → 高亮正确
//*[@id='app']/* → 看第一个子元素是什么
//*[@id='app']/*/* → 看孙子层级
九、常见问题速查
| 问题 | 原因 | 解决方法 |
|---|---|---|
用/写的路径很精确但运行报错 | 页面结构微调(多了/少了div) | 用//代替部分/,或用*通配 |
//匹配到了太多元素 | 范围太宽 | 在路径中加一两个有属性的中间节点 |
子元素索引[2]总是不对 | 忽略了文本节点或注释节点 | 用*代替具体标签,或检查中间是否有隐藏元素 |
相对路径.//在影刀中无效 | 没有基于父元素对象 | 确保“获取相似元素列表”输出的元素对象正确 |
| 层级XPath在XPath Helper里能跑,影刀里不行 | 影刀的元素对象不在同一页面 | 先“激活网页”或“切换到指定页面” |
十、总结:层级定位的口诀
- 有id或class的祖先,从它开始写
- 中间层级不确定,用
//跳过 - 需要精确控制,用
/和[]索引 - 循环里找子元素,用
.//相对路径 - 能近不远,不要从html根节点写
推荐资源
- 影刀官方学院: “XPath高级——层级定位与轴”(视频课程)
- 我的文章联动:
- 上一篇:[XPath Helper插件安装教程(选题池7号)]
- 下一篇预告:[影刀RPA完全指南:Pandas在影刀中的常用操作——筛选/排序/合并/去重](选题池20号)
- 在线工具: XPath Helper的层级高亮功能,可以逐层展开查看页面结构
作者:林焱
本文为《影刀RPA学习手册》系列文章之一,内容源于实操经验的整理与分享。
