如何在Python和lxml中使用XPath语法
如何在 Python 和 lxml 中使用 XPath 语法
XML 及其衍生格式已成为各种文档的事实标准,广泛应用于 Spring 框架配置、Struts 配置、Visual Studio 项目文件、Web 服务响应以及 Android UI 布局等场景。它们构成了现代编程基础设施中不可或缺的组件。由于格式无处不在,程序员在处理数据时几乎不可避免地会遇到 XML。如果说 AST(抽象语法树)代表代码,那么 XML 则代表数据;它是描述数据和信息的理想通用语言。因此,掌握读取、解析、导航和操作 XML 文档的能力是程序员的必备技能。
lxml 是一个基于 C 库 libxml2 和 libxslt 的 Python 绑定库,易于使用且功能强大。对于简单的查询(如查找特定标签),可以使用 find 或 findtext 方法;但对于复杂的查询,则需要更强大的工具——XPath。XPath 是一种迷你语言,允许您以声明方式指定如何选择 XML 文档中的元素。在某些方面,它类似于用于选择 DOM 元素的 CSS 选择器,允许您像浏览 CSS 一样浏览 XML 文档中的元素和属性。路径标识了一组节点,包括元素、属性、文本等。
XPath 在 XSLT 和 XSL 中被大量使用,其核心作用是在输入文档中定位元素并进行转换,从而在输出文档中生成结果,这与 CSS 使用选择器在 HTML 文档中定位元素并应用样式的机制类似。
本文将通过示例 HTML 文件和 lxml API 来说明 XPath 的常用语法。
环境准备
创建示例 HTML 文件
首先,创建一个名为 xpath-test.html 的文件,内容如下:
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
</div>解析文件
使用 lxml.html 模块读取并解析该文件:
import lxml.html
html = lxml.html.parse("xpath-test.html")子节点运算符 /
/ 运算符用于分隔父级和子级节点。当路径以 / 开头时,表示这是绝对路径,即从根节点开始查找。
使用绝对路径查找节点
例如,查找 div 节点:
nodes = html.xpath('/html/body/div')注意:lxml 的 HTML 解析器会自动修复文档结构(例如添加缺失的 html 和 body 标签)。因此,根节点通常为 html。您可以打印解析后的 HTML 源文件来验证这一点:
from lxml import etree
print(etree.tostring(html))输出结果如下(格式已美化):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</li></ul>
</div>
</body></html>选择所有链接文本
基于修复后的文档结构,可以使用绝对路径选择所有链接的文本内容:
nodes = html.xpath('/html/body/div/ul/li/a/text()')
print(nodes)输出:
['first item', 'second item', 'third item', 'fourth item', 'fifth item']后代运算符 //
// 运算符用于选择父节点的所有子孙节点。如果路径以 // 开头,意味着搜索从根节点开始,匹配文档中所有符合条件的后代节点,而不仅仅是直接子节点。
修改 HTML 结构
假设我们将 HTML 文件修改为包含嵌套结构:
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
<div>
<ul>
<li><a href="link6.html">sixth item</a></li>
</ul>
</div>
</div>获取所有链接
使用后代运算符可以一次性获取所有层级的链接文本,无需关心具体的嵌套深度:
lis = html.xpath('//li/a/text()')
print(lis)输出:
['first item', 'second item', 'third item', 'fourth item', 'fifth item', 'sixth item']如果使用绝对路径,可能需要编写多个查询,而后代运算符只需一个表达式即可完成。
限定范围查找
若只想获取第二个 div 内部 ul 列表中的链接,可以结合绝对路径与后代运算符:
lis = html.xpath('/html/body/div/div//li/a/text()')
print(lis)输出:
['sixth item']属性 @ 运算符
可以使用 @ 运算符根据元素属性(例如 class 属性)来过滤元素。
按 Class 属性筛选
选择所有 class 属性为 item-0 的元素中的链接文本:
attributes = html.xpath('//li[@class="item-0"]/a/text()')
print(attributes)输出:
['first item', 'fifth item']逻辑运算符
XPath 支持逻辑查询,返回布尔值。如果匹配的元素满足查询条件,则返回 True,否则返回 False。
测试条件
例如,测试第二个 div 列表中的链接是否包含文本内容为 "first item" 的链接:
logics = html.xpath("//div/div//a/text()='first item'")
print(logics)输出:
False说明:本文示例基于 Python 3 环境及lxml库。lxml版本更新通常保持向后兼容,但具体行为可能因解析器配置略有差异。
版权声明:本文为原创文章,版权归 戴老师的博客 所有,转载请联系博主获得授权。
本文地址:https://1diff.fun/archives/ru-he-zai-python-he-lxml-zhong-shi-yong-xpath-yu-fa.html
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。