影刀RPA进阶教程:XPath参照物定位preceding-sibling与following-sibling实战
有一种定位场景非常普遍:页面上某个元素没有任何唯一属性,但它的哥哥/弟弟/邻居有。
比如小红书的评论区。每条评论的时间文本是一样的<span>刚刚</span>,没ID也没唯一class。但时间前面紧挨着的就是用户名,用户名每条都不一样。
这种用参照物定位最省事。
一、什么场景必须用参照物定位
前两篇文章讲了属性选择器(contains/starts-with)、父子定位,现在讲第三种:参照物定位。
使用场景特征:
- 目标元素本身没有唯一属性(没有唯一id、没有唯一class、文本内容每条都不一样)
- 但它旁边有一个唯一特征明显的元素(文本固定、class固定、位置固定)
- 找哥哥(preceding-sibling)或者找弟弟(following-sibling)
| 实际案例 | 参照物 | 目标元素 | 方向 |
|---|---|---|---|
| 电商SKU列表 | "已选"标记 | 用户选中的规格值 | 后面兄弟 |
| 表格操作列 | "编辑"按钮 | 同一行的"删除"按钮 | 前面兄弟 |
| 评论列表 | 用户名 | 用户的评论内容 | 后面兄弟 |
| 商品详情页 | "价格"标签 | 价格数值 | 后面兄弟 |
二、preceding-sibling:找前面的兄弟
"preceding-sibling"从当前元素往前找同级的元素。
# 含义:找到文本为"价格"的元素,然后往前找它的前一个兄弟元素//*[contains(text(),'价格')]/preceding-sibling::*[1]# 含义:往前找第2个兄弟[video(video-on2gr0Vm-1781112567605)(type-csdn)(url-https://live.csdn.net/v/embed/525000)(image-https://v-blog.csdnimg.cn/asset/23da3fe1f67a47106d725406cfde9a97/cover/Cover0.jpg)(title-拼多多店群自动化上架方案)]//*[text()='价格']/preceding-sibling::*[2]实战案例:小红书中提取用户昵称
小红书的评论结构里,用户名和评论时间是两个相邻的兄弟元素。时间的class固定为date,用户名没有。
# 参照物:评论时间(文本固定、有索引)# 目标:评论时间前面的用户昵称# 捕获元素:通过时间定位到昵称(时间是昵称的后一个兄弟)//span[@class='date']/preceding-sibling::*[1]反过来操作也行——先定位时间,然后找前面的昵称。关键是搞清楚谁在前面。
三、following-sibling:找后面的兄弟
# 含义:找到文本为"用户名"的元素,然后往后找第一个兄弟//*[text()='用户名']/following-sibling::*[1]# 含义:找到input标签,往后找第3个兄弟//input/following-sibling::*[3]实战案例:表格里的操作按钮
HTML表格一行有4个按钮:查看、编辑、复制、删除。其中"编辑"按钮有独特的文本标识,删除按钮没有。
# 参照物:编辑按钮(文本固定"编辑")# 目标:同一行的删除按钮(编辑后面的兄弟)# 捕获元素:从编辑找删除//button[text()='编辑']/following-sibling::button[3]# 或者更保险的写法:找父容器再往下定位//tr[.//td[text()='商品001']]//button[text()='删除']第二种写法更稳——通过行里的某个唯一值来定位行,再从行里找目标。建议优先用这种方式。
四、通过父容器定位(推荐优先用这个)
参照物定位有时会出问题——DOM结构变了,兄弟位置也跟着变。
更稳的套路是:先找到能唯一定位的父容器,再从父容器里往下找目标。
# 思路:找到包含"订单号:12345678"这一行,再定位这一行里的操作按钮# 第一步:定位父容器(包含唯一文本的行)//tr[contains(.,'12345678')]# 第二步:从父容器里往下找目标元素//tr[contains(.,'12345678')]//button[text()='删除']这比preceding-sibling稳定得多。兄弟元素的位置只要HTML不重新排列就不会变,但DOM结构微调在电商平台更新中是家常便饭。
五、…/ 回到上一层(别忽略这个)
参照物定位里有一个特别常用的符号:..,表示回到父级。
# 场景:当前定位到一个span(已知),需要找它父容器里的另一个元素# 上到父级,再往下找title//span[@class='price']/../div[@class='title']# 上到父级,再上到父级,再找兄弟//span[@class='price']/../../following-sibling::div[1]实际案例:拼多多商品卡片的"已拼xx万件"。
销量文本已拼1.2万件每次都不一样,没法用文本匹配。但它旁边有一个固定的"已拼"标签。
# 找"已拼"的父容器(整个销量块),然后在父容器里找具体数字//span[text()='已拼']/..# 更直接:通过"已拼"的父容器找数字span//span[text()='已拼']/../span[@class='num']六、完整实战:批量提取小红书评论区数据
# 小红书笔记评论区采集打开网页("https://www.xiaohongshu.com/explore/xxxxxxxxxx")等待元素出现("评论区容器",5秒)# 获取所有评论的相似元素列表# 捕获元素:每条评论的外层容器# //div[@class='comment-item']获取相似元素列表("评论列表")->评论列表 新建Excel->评论数据表 写入行数据(评论数据表,["序号","用户名","评论内容","发布时间"])遍历列表(评论列表,当前评论):序号=当前循环索引+1# 方法1:用preceding-sibling通过时间定位用户名# 时间元素有date class,用户名在时间前面获取元素文本(当前评论,".//span[contains(@class,'date')]/preceding-sibling::a[1]")->用户名# 方法2:直接取评论内容(有class可以直接定位)获取元素文本(当前评论,".//span[@class='content']")->评论内容# 获取发布时间(有class可以直接定位)获取元素文本(当前评论,".//span[contains(@class,'date')]")->发布时间 写入行数据(评论数据表,[序号,用户名,评论内容,发布时间])导出表格(评论数据表,"D:\小红书评论_20260609.xlsx")TEMU店群如何管理运营?
七、参照物定位的三个坑
坑1:以为兄弟位置固定,结果DOM结构悄悄变了
这在实际项目中很常见。电商平台隔几个月改版一次,原来紧挨着的兄弟元素中间插了一个<div>。
预防:不要依赖[1](紧挨着的兄弟),尝试用更大的偏移量或用父容器定位兜底。
坑2:不同浏览器渲染的DOM层级可能不一样
Chrome的开发者工具和影刀内置浏览器的解析结果偶尔会有差异。
解决方法:用影刀自带的"捕获元素"看XPath,不要直接抄Chrome开发者工具的XPath。
坑3:preceding-sibling::*[1]可能返回你没想到的元素
*匹配所有标签,包括<br>、<img>、空白文本节点。
改善:
# ❌ 可能匹配到空白或换行//span[@class='date']/preceding-sibling::*[1]# ✅ 指定标签类型//span[@class='date']/preceding-sibling::a[1]//span[@class='date']/preceding-sibling::div[1]八、速查:三种定位方式的选择优先级
| 优先级 | 定位方式 | 适用场景 |
|---|---|---|
| 1(最稳) | 父容器定位 | 目标有唯一文本或属性的父级(订单号、商品ID) |
| 2 | 属性/文本直接匹配 | 元素自身有id、唯一class、固定文本 |
| 3(兜底) | 参照物定位 | 目标没有唯一特征,但邻居有 |
我的习惯:先尝试直接匹配,不行就上父容器定位,最后才考虑兄弟参照物。
作者:林焱
本文为《影刀RPA学习手册》系列文章之一,内容源于实操经验的整理与分享。