Python 爬虫 · XML、xpath 与 lxml 模块基础

Python 学习第 32 天。

之前,我们具体讲解了 HTML 文档,与其相似的还有 XML 文档,而 xpath 就是一种用于解析 XML 路径的语言,本质就是识别 XML 中各节点(类似于 HTML 中的各标签)。

**补充:**HTML 与 XML 一样为树形结构,xpath 也可以解析 HTML 文档。


一、XML

XML(可扩展标记语言),是用于数据描述、存储和传输的标记语言,核心功能在于存储结构性数据。它由声明、根节点、子节点、内容、属性、注释 组成,总体分为 "文档声明 + 主体树结构"

1. 声明示例:

复制代码
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

(1) <?xml?> 为文档声明,属于处理指令,必须写在文档第一行;

(2) version="1.0" 将文档的版本定义为 1.0 (全球通用的规范版本);

(3) encoding="UTF-8" 将文档的字符编码格式定义为 utf-8;

(4) standalone="yes" 表示文档依赖外部文件。

2. 节点:字母、数字、下划线(_)、连字符(-)、英文点(.) 构成,可根据自身需要按照见名知义的原则定义,但开头必须是 字母、下划线 ,中间不能用 空格、中文字符、特殊符号连接,严格区分大小写(同一个英文字母,大小写不同会被识别为不同的节点)。

**(1) 根节点:**每个文档只有一个,所有主体内容都包含在根节点内。

**(2) 子节点:**嵌套在根节点内的子节点,可以有多个。

4. 内容: 放在节点之间需要存储的信息,格式:<节点名>需要存储的信息</节点名>

**5. 属性:**写在开始标签内部,和节点一样,属性名可以根据自身需要见名知义地定义,格式:<节点名 属性1="属性值1" 属性2="属性值2" ...... 属性n="属性值n">

6. 注释: 常用于说明该节点作用,格式:<!-- 注释内容 -->

二、xpath

xpath 是一种查询语言,本质上就是在树形结构的文档中,按照节点查找内容。这部分我们介绍它的语法格式,该语法格式与逻辑在 Python 中的 lxml 模块中可用 xpath() 函数直接套用。

1. 路径

**(1) 绝对路径:**以 / 开头,从根节点开始,每个 / 后边跟的是下一层的直接节点,// 则表示所有后代节点(既有子代,也有孙代、曾孙代、......)

(2) 相对路径: 不以 / 开头,./待查找节点名 指的是当前节点下的待查找节点,../待查找节点名 指的是当前节点的父节点下的待查找节点。

2. 符号 / 函数

与路径结合使用。

(1) *: 表示 "通用",/* 就是查找某节点下的所有子节点(直接的节点,不包含孙代、曾孙代、......)

(2) @: 表示 "调用",@属性名 就是查找某标签下的某属性,**@***就是查找某标签下的所有属性

**(3) \[\]:**跟在某标签之后,内涵属性名 / 属性名 = "属性值" / 索引 / 结合函数、逻辑运算符、@调用属性,用于限定对象

**(4) ():**表示 "分组"

(5) text(): 用于显示某节点对应的文本,格式:/节点名/text()

**(6) node():**用于显示任意类型的节点(元素、文本、注释等)

**(7) comment():**用于显示注释节点

**(8) last():**最后一个节点

**(9) position() > n:**第 n-1 个节点,n 要具体到数字

**(10) contains(@属性名, '属性值'):**包含某属性的节点

**(11) start-with(@属性名, '待识别字段'):**某属性值以待识别字段开头的节点

**(12) and:**逻辑与,两边条件都满足

**(13) or:**逻辑或,两边条件满足一个

**(14) not():**逻辑非,与条件相反

三、lxml 模块

以以下 XML 文档为例:

复制代码
xml = """<?xml version = "1.0" encoding = "utf-8"?>
<library>
    <info name="城东图书馆" address="文明路88号" tel="020-12345678">
        <total_books>20000</total_books>
    </info>
    <books>
        <book id="B001" type="文学">
            <book_name>朝花夕拾</book_name>
            <author>鲁迅</author>
            <publish>人民文学出版社</publish>
            <stock>15</stock>
        </book>
        <book id="B002" type="科技">
            <book_name>Python编程入门</book_name>
            <author>张三</author>
            <publish>机械工业出版社</publish>
            <stock>28</stock>
        </book>
        <book id="B003" type="历史">
            <book_name>明朝那些事儿</book_name>
            <author>当年明月</author>
            <publish>中国友谊出版公司</publish>
            <stock>9</stock>
        </book>
        <book id="B004" type="文学">
            <book_name>围城</book_name>
            <author>钱钟书</author>
            <publish>人民文学出版社</publish>
            <stock>12</stock>
        </book>
    </books>
</library>
"""

**注意:**将 XML 文档在代码块中赋值给变量时,""" 与 <?xml ......?> 之间不要有换行或空格,否则会在后续用 etree.XML() 或 etree.HTML() 读取中报错。

1. 安装包

在代码块中输入:

复制代码
pip install lxml

运行结果中,如果出现以下文字,说明之前已经安装过这个模块,可以直接导入使用:

如果是第一次安装,运行结果末尾部分则会出现 Successfully installed lxml - 5.3.0。5.3.0是版本号,可能会不同。

2. 导入包

在代码块中输入:

复制代码
from lxml import etree

或:

复制代码
from lxml import html
etree = html.etree

3. 解码

示例中的 XML 文档用 utf-8 编码,那么对应的用 utf-8 解码,将其转换为 bytes 格式。很关键,否则初始化对象时会报错。

复制代码
xml_bytes = xml.encode("utf-8")

4. 初始化对象

格式:变量名 = etree.XML(解码后的对象名)

复制代码
et = etree.XML(xml_bytes)

如果是 HTML 文档,就用 **etree.HTML()**函数。

5. 查找

(1) 格式:初始化后的对象名.xpath("绝对路径"),以列表的形式返回符合条件的元素所在的内容地址

复制代码
et.xpath("/library/books/book")

运行结果1:

代码示例2:初始化后的对象名.xpath("绝对路径/text()"),以列表的形式返回符合条件的元素所在的内容文本

复制代码
et.xpath("/library/books/book/book_name/text()")

运行结果2:'朝花夕拾', 'Python编程入门', '明朝那些事儿', '围城'

代码示例3:如果想取出列表中的单个元素,就结合列表的知识,用索引或遍历的方式将其取出

复制代码
result_1 = et.xpath("/library/books/book/book_name/text()")
print("---索引---")
print(result_1[1])
print("---遍历---")
for i in result_1:
    print(i)

运行结果3:

代码示例4:用相对路径写法,省略父节点,并查找指定属性的属性值,以列表的形式返回

复制代码
et.xpath("//book/@id")

运行结果4:'B001', 'B002', 'B003', 'B004'

代码示例5:使用逻辑运算符筛选多个条件下的节点(没有匹配的节点时,返回一个空列表)

复制代码
et.xpath("//book[@id = 'B002' and @type = '文学']/text()")

运行结果5:\[\]

代码示例6:使用逻辑运算符筛选多个条件下的节点,我们发现用 // 查询所有子节点的同时,返回的列表中出现了许多 "空值"

复制代码
et.xpath("//book[@id = 'B002' and @type = '科技']//text()")

运行结果6:

代码示例7:为解决示例6中出现的情况,可以用strip()函数结合列表推导式处理

复制代码
text_list = et.xpath("//book[@id='B002' and @type='科技']//text()")
clean_text = [t.strip() for t in text_list if t.strip()]
print(clean_text)

运行结果7:'Python编程入门', '张三', '机械工业出版社', '28'


用 lxml 模块中的 xpath() 解析函数查询 HTML 文档中的内容与 XML 文档同理

区别在于初始化对象时将 XML() 改为 HTML()

相关推荐
Scott9999HH5 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社6 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海6 小时前
python 列表、元组、集合和字典
开发语言·python
二十雨辰7 小时前
[爬虫]-Urllib
爬虫·python
萧瑟余晖7 小时前
JDK 26 新特性详解
java·开发语言
马优晨8 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
玉鸯8 小时前
Agent Hook:在概率推理之上,为 Agent 叠加确定性控制
python·langchain·agent
weixin_446260859 小时前
HACO:面向动态部署环境的对冲式智能计算可靠多智能体调度框架
后端·python·flask
我的xiaodoujiao9 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest