XPath通过路径表达式在XML或HTML文档中查找信息,选择具有特定属性值的节点是实际开发中最常用的操作之一,核心是通过属性谓词来过滤符合条件的节点。

XPath属性选择的基础语法
要选择具有特定属性值的节点,基础语法是在节点名称后添加方括号,方括号内使用@属性名='属性值'的格式进行匹配,整体结构为//节点名[@属性名='目标属性值']。
这里的//表示从当前文档的任意位置开始查找,@是XPath中用于引用属性的前缀,方括号[]是谓词,用于对节点进行筛选过滤。
精确匹配属性值
当需要完全匹配某个属性的具体值时,直接使用等号连接目标值即可,这是最常用的场景。
比如我们要在下面的HTML文档中,找到所有class属性为item的div节点:
<html>
<body>
<div class="item">第一个项目</div>
<div class="other">第二个项目</div>
<div class="item">第三个项目</div>
</body>
</html>
对应的XPath表达式为//div[@class='item'],执行后就会返回两个class为item的div节点。
如果是匹配id属性,比如找id为header的元素,表达式就是//*[@id='header'],这里的*表示匹配任意节点名。
部分匹配属性值
很多时候属性值是动态生成的,或者包含固定的前缀、后缀,这时候就需要用到部分匹配的语法,XPath提供了几个常用的函数来实现:
contains(@属性名, '部分值'):判断属性值是否包含指定的部分字符串starts-with(@属性名, '前缀'):判断属性值是否以指定字符串开头ends-with(@属性名, '后缀'):判断属性值是否以指定字符串结尾,注意部分XPath版本可能不支持该函数
比如上面的HTML中,如果要找所有class属性包含it的div节点,表达式就是//div[contains(@class, 'it')],会匹配到两个class为item的div。
如果要找class以it开头的div,表达式是//div[starts-with(@class, 'it')],同样会匹配到那两个节点。
多属性组合匹配
有时候单个属性不足以唯一确定节点,这时候可以在谓词中组合多个属性条件,使用and或者or连接多个判断条件。
比如要找class为item且id为first的div节点,表达式是//div[@class='item' and @id='first']。
如果要找class为item或者class为other的div,表达式是//div[@class='item' or @class='other']。
实际代码示例
下面用Python的lxml库演示XPath选择特定属性值节点的实际用法,首先安装lxml库:
pip install lxml
然后编写解析代码:
from lxml import etree
# 构造测试HTML
html_text = """
<html>
<body>
<div class="item" data-id="1">商品1</div>
<div class="item" data-id="2">商品2</div>
<div class="other" data-id="3">商品3</div>
<a href="https://ipipp.com" class="item">跳转链接</a>
</body>
</html>
"""
# 解析HTML
html = etree.HTML(html_text)
# 1. 精确匹配class为item的div
div_items = html.xpath('//div[@class="item"]')
print("class为item的div数量:", len(div_items))
for div in div_items:
print("div内容:", div.text)
# 2. 匹配data-id大于1的div
div_id_gt1 = html.xpath('//div[@data-id > 1]')
print("data-id大于1的div数量:", len(div_id_gt1))
# 3. 匹配href包含ipipp.com的a标签
a_links = html.xpath('//a[contains(@href, "ipipp.com")]')
print("包含ipipp.com的a标签数量:", len(a_links))
print("a标签链接:", a_links[0].get('href'))
运行上面的代码,就能看到对应的节点选择结果,验证了不同属性选择语法的效果。
注意事项
在使用XPath选择属性值时,需要注意属性值的外层要用单引号包裹,如果属性值本身包含单引号,可以换成双引号包裹,或者使用转义字符处理。
另外,HTML中的class属性可能有多个值,比如class="item active",这时候用精确匹配[@class='item']是匹配不到的,需要用contains(@class, 'item')来匹配,避免遗漏目标节点。
如果是在XML文档中使用,属性值的匹配规则和HTML一致,只需要把节点路径换成对应的XML节点结构即可。