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()

相关推荐
阿正的梦工坊1 小时前
【Rust】20-Rust 编译器架构与 MIR/LLVM 优化管线
开发语言·架构·rust
我要打打代码1 小时前
C# 扩展方法
开发语言·c#
JackSparrow4141 小时前
彻底理解Java NIO(三)Java实现 I/O多路复用+Reactor模式及开源框架代码解读
java·c语言·开发语言·后端·nio·reactor模式
曹牧1 小时前
Java:Xml中的大、小于
java·开发语言
zavoryn1 小时前
Jackson 序列化踩坑:LocalDateTime、Long 精度丢失和 boolean isXxx 字段
java·开发语言·后端
曹牧1 小时前
Java:XML转义
xml·java·开发语言
挨踢诗人1 小时前
天猫(淘宝开放平台)集成金蝶云星空
python·数据集成
leo_yu_yty1 小时前
Go语言分布式计算(并发Debug)
开发语言·笔记·后端·golang
我认不到你1 小时前
【开源、教程】RAG全流程实现(java+完整代码):第一弹
java·开发语言·人工智能·深度学习·ai·语言模型·开源