拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

影刀RPA新手教程:XPath实战手册——六种写法在真实采集项目中的选择与避坑

影刀RPA新手教程:XPath实战手册——六种写法在真实采集项目中的选择与避坑

影刀RPA新手教程:XPath实战手册——六种写法在真实采集项目中的选择与避坑

XPath是RPA元素定位的核心技能。上一篇文章讲了元素定位的基础,这篇专攻XPath,把六种写法讲透。

我第一次写XPath的时候,照着教程抄,结果一个字符都不对。后来踩了几十个坑,才总结出这套实战经验。

这篇不讲理论,直接给用法、给代码、给坑点。

一、XPath六种写法详解

1.1 写法一:属性选择器(适合稳定元素)

语法格式:

//标签[@属性="属性值"]

什么时候用:

  • 元素的属性值是稳定的(不会随机变化)
  • 知道准确的属性名和属性值

真实项目代码(百度搜索框):

//input[@id="kw"]

代码解释:

  • //input:找页面上所有的input标签
  • [@id="kw"]:筛选出id等于"kw"的那个input

另一个真实案例(淘宝商品搜索框):

//input[@id="q"]

为什么用这个写法:百度搜索框的id是"kw",淘宝商品搜索框的id是"q",这些都是前端开发固定的,不会变。用属性选择器定位,准确率接近100%。

踩坑点1:属性值写错一个字符就匹配不到。

我第一次做的时候,把[@id="kw"]写成了[@id="kw "](多了个空格),排查了一下午,心态直接崩。

解决方案:F12打开开发者工具,直接复制属性值,不要手敲。

踩坑点2:属性值包含引号。

比如value="他说:"你好"",这种字符串里有引号,XPath会报错。

解决方案:用单引号包裹,比如[@value='他说:"你好"']。

踩坑点3:属性值很长,不想写全。

比如class="submit-btn btn-primary btn-large btn-hover",写全了太麻烦。

解决方案:用contains函数(见写法二)。

1.2 写法二:模糊匹配contains(适合只确定部分元素)

语法格式:

//标签[contains(@属性,"部分值")]

什么时候用:

  • 只知道属性值的一部分
  • 属性值太长,不想写全
  • 属性值包含多个值(比如class有多个类名)

真实项目代码(小红书号):

//span[contains(text(),"小红书号:")]

代码解释:

  • //span:找页面上所有的span标签
  • [contains(text(),"小红书号:")]:筛选出文本内容包含"小红书号:"的span

为什么用这个写法:小红书号的格式是"小红书号:xxxx",冒号后面的数字是变化的,但"小红书号:"这五个字是固定的。用contains可以匹配到整个span,然后再用正则表达式提取冒号后面的数字。

具体操作流程(在影刀中实现):

  1. 用【获取元素对象(web)】指令,定位方式选择"XPath选择器"
  2. XPath填写//span[contains(text(),"小红书号:")]
  3. 用【获取元素文本内容(web)】指令获取整个文本(比如"小红书号:abc123")
  4. 用【从文本中提取内容】指令,正则表达式填写小红书号:(.*),提取出"abc123"

另一个真实案例(匹配class包含多个值的情况):

//div[contains(@class,"note-title")]

这样可以匹配:

  • class="note-title"
  • class="note-title hot"
  • class="hot note-title"

如果用属性选择器[@class="note-title"],只能匹配第一种情况,后两种都匹配不到。

踩坑点1:contains是模糊匹配,可能匹配到多个元素。

解决方案:加上位置限制。

(//div[contains(@class,"note-title")])[1]

意思是取第一个匹配项。

踩坑点2:text()包含空白字符。

比如页面源码是<span>小红书号: abc123 </span>(前后有空格),用contains(text(),"小红书号:")可能匹配不到。

解决方案:用normalize-space函数去掉空白字符。

//span[contains(normalize-space(text()),"小红书号:")]

1.3 写法三:参照物定位preceding-sibling/following-sibling(适合通过上下文定位)

语法格式:

//标签[@属性="属性值"]/preceding-sibling::标签 # 找前面的兄弟节点 //标签[@属性="属性值"]/following-sibling::标签 # 找后面的兄弟节点

什么时候用:

  • 要定位的元素没有明确属性,但它旁边有个有明确属性的元素
  • 元素之间的相对位置是固定的

真实项目代码(小红书笔记的点赞数):

//span[text()="点赞"]/following-sibling::span

代码解释:

  • //span[text()="点赞"]:找到文本是"点赞"的span(这就是参照物)
  • /following-sibling::span:找它后面的兄弟span(就是点赞数)

为什么用这个写法:小红书笔记详情页,点赞数、收藏数、评论数这三个数据,结构是一样的:

<span>点赞</span><span>1234</span><span>收藏</span><span>567</span><span>评论</span><span>89</span>

点赞数在"点赞"这个span的后面,所以用following-sibling::span就能定位到。

如果要定位收藏数:

//span[text()="收藏"]/following-sibling::span

如果要定位评论数:

//span[text()="评论"]/following-sibling::span

另一个真实案例(找前面的兄弟节点):

//span[text()="收藏数:100"]/preceding-sibling::span

这样可以找到"收藏数:100"前面的span,比如可能是收藏的图标。

踩坑点1:preceding-sibling和following-sibling只能找同级节点。

如果要找父节点,用parent::。

//span[text()="点赞"]/parent::div

如果要找子节点,用child::(见写法四)。

踩坑点2:兄弟节点有多个,需要调整下标。

比如"点赞"后面的第一个span是点赞数,第二个span可能是其他内容。

解决方案:用下标精确控制。

//span[text()="点赞"]/following-sibling::span[1] # 第一个兄弟节点 //span[text()="点赞"]/following-sibling::span[2] # 第二个兄弟节点

1.4 写法四:层级定位child::(适合逐层精确提取)

语法格式:

//父标签/child::子标签

简化写法(child::可以省略):

//父标签/子标签

什么时候用:

  • 要精确定位某个父节点下的第几个子节点
  • 页面结构规律,层级关系明确

真实项目代码(小红书笔记的点赞数、收藏数、评论数):

//div[@class="interact-container"]/div[1] # 点赞数 //div[@class="interact-container"]/div[2] # 收藏数 //div[@class="interact-container"]/div[3] # 评论数

代码解释:

  • //div[@class="interact-container"]:找到class是"interact-container"的div(这是点赞、收藏、评论的容器)
  • /div[1]:找它的第一个子div(点赞数)

为什么用这个写法:小红书笔记的互动数据(点赞、收藏、评论)都放在interact-container这个div里面,而且是按顺序排列的。用child::可以精确控制取第几个。

踩坑点1:如果页面结构变了(比如插入了一个新的div),下标可能错位。

我第一次做的时候,写完流程测试没问题。过了一个星期再用,发现采集到的点赞数和收藏数反了。排查了半天,发现页面改版,插入了一个新的div,导致下标全乱了。

解决方案:

  1. 优先用contains或preceding-sibling/following-sibling,减少对下标的依赖
  2. 如果必须用下标,定期维护,页面改版后及时更新XPath

踩坑点2:下标从1开始,不是从0开始。

这是XPath的语法规则,和Python的列表索引不同。

错误写法:

//div[@class="interact-container"]/div[0] # 这样写会报错

正确写法:

//div[@class="interact-container"]/div[1] # 第一个子div

1.5 写法五:starts-with/ends-with(适合属性值有规律的情况)

语法格式:

//标签[starts-with(@属性,"开头部分")] # 匹配以"开头部分"开始的属性值 //标签[ends-with(@属性,"结尾部分")] # 匹配以"结尾部分"结束的属性值

什么时候用:

  • 属性值有规律,比如都是以某个前缀开头,或以某个后缀结尾
  • 属性值的前缀或后缀是固定的,但中间部分会变化

真实项目代码(电商商品列表的商品ID):

//div[starts-with(@id,"product-")]

代码解释:

  • starts-with(@id,"product-"):匹配id以"product-"开头的div
  • 比如id="product-12345"、id="product-67890"都能匹配到

另一个真实案例(匹配以".jpg"结尾的图片):

//img[ends-with(@src,".jpg")]

这样可以匹配所有jpg格式的图片。

踩坑点1:ends-with在XPath 1.0中不支持。

Chrome浏览器使用的是XPath 1.0,所以ends-with会报错。

解决方案:用contains代替,或者升级到支持XPath 2.0的浏览器。

用contains代替ends-with:

//img[contains(@src,".jpg")]

注意:这样也会匹配到".jpg.png"这种文件名,不够精确。

更精确的解决方案:用正则表达式。

//img[matches(@src,"\.jpg$")]

但matches函数也是XPath 2.0才支持的,Chrome不支持。

最终方案:在影刀中用【从文本中提取内容】指令,用正则表达式\.jpg$过滤。

1.6 写法六:组合写法(实战中最灵活)

语法格式:把前面的写法组合起来,实现复杂定位。

真实项目代码(小红书笔记详情页,提取发布时间):

//div[@class="note-meta"]/span[contains(text(),"发布于")]/following-sibling::span[1]

代码解释(从右往左读):

  1. following-sibling::span[1]:找前面的span节点的后面第一个兄弟span
  2. /span[contains(text(),"发布于")]:这个span的文本内容包含"发布于"
  3. //div[@class="note-meta"]:这个span在class是"note-meta"的div里面

为什么用组合写法:真实项目的页面结构通常很复杂,单一写法可能搞不定。组合写法可以应对各种复杂情况。

另一个真实案例(电商商品列表,提取商品名称,但只限前两行):

//div[@class="product-list"]/div[position()<=2]/div[@class="product-name"]

代码解释:

  • position()<=2:限制只取前两个商品
  • 这样可以实现"只采集前两行数据"的需求

position()函数:返回当前节点的位置。

更多组合写法的例子:

例1:匹配class包含"note-title"且文本包含"教程"的div。

//div[contains(@class,"note-title") and contains(text(),"教程")]

例2:匹配class包含"note-title"或class包含"article-title"的div。

//div[contains(@class,"note-title") or contains(@class,"article-title")]

例3:匹配class包含"note-title"但文本不包含"广告"的div。

//div[contains(@class,"note-title") and not(contains(text(),"广告"))]

二、XPath校验工具和常见语法报错

2.1 XPath校验工具

写好的XPath,怎么验证对不对?下面两个工具可以帮到你。

工具一:Chrome开发者工具(最常用)

操作步骤:

  1. F12打开开发者工具
  2. 按Ctrl+F(Mac是Cmd+F),打开搜索框
  3. 输入XPath,回车
  4. 如果XPath正确,匹配到的元素会高亮显示,并且显示匹配数量

我第一次做的时候,不知道有这个功能的,写完XPath就直接往影刀里填,结果报错。现在都是先在开发者工具里验证,确认无误再填到影刀里。

工具二:XPath Helper(Chrome插件)

这是一个Chrome插件,可以实时验证XPath。

安装方法:

  1. 在Chrome应用商店搜索"XPath Helper"
  2. 点击"添加至Chrome"

使用方法:

  1. 打开需要采集的网页
  2. 点击浏览器右上角的XPath Helper图标
  3. 在XPath输入框中填写XPath
  4. 实时显示匹配结果

踩坑:XPath Helper在某些网站上无法使用(比如有反爬机制的网站)。

解决方案:用Chrome开发者工具代替。

2.2 常见语法报错及解决方案

报错一:SyntaxError: Invalid XPath expression

原因:XPath语法写错了。

常见错误:

  1. 引号不匹配。

    • 错误://div[@class="note-title]
    • 正确://div[@class="note-title"]
  2. 括号不匹配。

    • 错误://div[contains(@class,"note-title"
    • 正确://div[contains(@class,"note-title")]
  3. 使用了不存在的函数。

    • 错误://div[matches(@class,"note-title")](matches函数XPath 1.0不支持)
    • 正确://div[contains(@class,"note-title")]

解决方案:仔细检查XPath语法,确保引号、括号都匹配。

报错二:Unable to locate element with XPath

原因:XPath没有问题,但页面上没有匹配的元素。

常见原因:

  1. 页面还没加载完成。
  2. 元素在iframe里面。
  3. 元素在动态加载的内容里面。

解决方案:

  1. 在【获取元素对象(web)】指令中,设置"等待元素存在(s)"为5秒或更长。
  2. 如果元素在iframe里面,先用【切换到iframe(web)】指令切换到iframe,再定位元素。
  3. 如果元素是动态加载的,用【循环相似元素(web)】指令等待元素出现。

报错三:XPath returned multiple elements, expected one

原因:XPath匹配到了多个元素,但指令只接受一个元素。

解决方案:

  1. 用下标限制,只取第一个匹配项。
    (//div[@class="note-title"])[1]
  2. 改用【获取相似元素列表(web)】指令,获取所有匹配的元素。

三、案例实战:采集电商商品列表页

下面用一个完整案例,把XPath六种写法串起来。

需求:采集电商商品列表页的以下数据(每个商品):

  • 商品标题
  • 商品价格
  • 商品销量
  • 评价数

实现方案:对每个数据用不同的XPath写法(为了演示不同写法在实际项目中的选择)。

3.1 采集商品标题(用属性选择器)

商品标题通常有稳定的class或id,用属性选择器最合适。

XPath写法:

//div[@class="product-title"]

指令配置:

  1. 用【获取相似元素列表(web)】指令,定位方式选择"XPath选择器"
  2. XPath填写上面的代码
  3. 元素操作选择"获取元素文本内容"
  4. 保存到变量商品标题列表

3.2 采集商品价格(用contains模糊匹配)

商品价格的class可能包含多个值(比如class="price current-price"),用contains更稳妥。

XPath写法:

//span[contains(@class,"price")]

指令配置:

  1. 用【获取相似元素列表(web)】指令,定位方式选择"XPath选择器"
  2. XPath填写上面的代码
  3. 元素操作选择"获取元素文本内容"
  4. 保存到变量商品价格列表

3.3 采集商品销量(用preceding-sibling/following-sibling参照物定位)

商品销量通常在"销量"这个文本后面,用following-sibling定位。

XPath写法:

//span[text()="销量"]/following-sibling::span

指令配置:

  1. 用【获取相似元素列表(web)】指令,定位方式选择"XPath选择器"
  2. XPath填写上面的代码
  3. 元素操作选择"获取元素文本内容"
  4. 保存到变量商品销量列表

3.4 采集评价数(用child::层级定位)

评价数在商品信息的某个子div里面,用child::定位。

XPath写法:

//div[@class="product-info"]/div[@class="review"]

指令配置:

  1. 用【获取相似元素列表(web)】指令,定位方式选择"XPath选择器"
  2. XPath填写上面的代码
  3. 元素操作选择"获取元素文本内容"
  4. 保存到变量评价数列表

3.5 数据整合

用【ForEach列表循环】指令,遍历商品标题列表,同时取出对应位置的价格、销量、评价数,写入Excel。

具体操作流程:

  1. 用【获取相似元素列表(web)】指令,分别获取商品标题列表、价格列表、销量列表、评价数列表
  2. 用【ForEach列表循环】指令,循环商品标题列表
  3. 在循环体内,用【获取列表项】指令,按当前循环的下标取出对应位置的价格、销量、评价数
  4. 用【写入Excel行】指令,将标题、价格、销量、评价数写入Excel的一行

四、总结

XPath六种写法,每种都有适用场景:

  1. 属性选择器:适合稳定元素,准确率最高
  2. contains模糊匹配:适合只确定部分元素,最常用
  3. preceding-sibling/following-sibling:适合通过上下文定位,灵活性强
  4. child::层级定位:适合逐层精确提取,下标控制要小心
  5. starts-with/ends-with:适合属性值有规律的情况,注意浏览器兼容性
  6. 组合写法:实战中最灵活,可以应对各种复杂情况

新手最重要的是:多练。找个项目实战,把六种写法都试一遍,自然就掌握了。

踩坑经验总结:

  1. 属性值写错一个字符就匹配不到,用F12直接复制
  2. contains可能匹配到多个元素,用下标限制
  3. child::的下标从1开始,不是从0开始
  4. ends-with在Chrome中不支持,用contains代替
  5. 写好的XPath先在Chrome开发者工具中验证,再填到影刀里

更多案例在影刀RPA学习主页 home.linyan.cloud

#影刀RPA #XPath #元素定位 #网页自动化 #新手入门
作者:林焱

返回列表