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

更多推荐