可狱可囚的爬虫系列课程 17:lxml模块的使用

可狱可囚的爬虫系列课程 07:BeautifulSoup4(bs4)库的使用中讲到了使用 CSS 选择器进行数据的爬取,其实还有另一种方式可以更好更快的抓取数据,那就是使用 XPath(XML 路径语言)。至于 XPath 和 CSS 选择器的区别,请听我娓娓道来:

一、什么是lxml

lxml 是 Python 语言中用于处理 XML 和 HTML 的功能最丰富且易于使用的库。它利用XPath就可以实现对XML和HTML进行数据解析。

二、什么是XML

XML 指可扩展标记语言,XML 是一种很像HTML的标记语言。但是 XML 被设计用来传输和存储数据,HTML 被设计用来显示数据。

因为 XML 和 HTML 很像,所以只讲其中一种,另一种大家便可以很简单的融汇贯通。

XML长这个样子👇👇👇👇,这是我自己编写的一个 XML 用例。

xml 复制代码
<supermarket>
		<!--  这是一条平平无奇的注释  -->
    <name>沃尔玛</name>
    <address>中国四川成都</address>
    <staffs>
        <name age="20" sex="男">张三</name>
        <name age="30" sex="男">李四</name>
        <name age="23" gender="女">王五</name>
    </staffs>
    <goods>
        <name price="8">啤酒
            <count>12</count>
        </name>
        <name price="3">饮料
            <count>5</count>
        </name>
        <name price="1" count="10">矿泉水</name>
        <name price="5">花生</name>
        <name price="6">瓜子</name>
        <name price="2">火腿肠</name>
    </goods>
</supermarket>

三、什么是XPath

XPath是一门在 XML 文档中查找信息的语言,用 XPath 写出的路径表达式可以在 XML 文档中进行导航。

使用 XPath 编写的路径表达式,和我们常使用的相对路径、绝对路径非常相似。那么XPath的语法是怎样的呢,我们一起来看。

四、XPath语法

首先先来说下XPath需要理解的概念,有树、节点、根节点、元素节点、属性节点、注释节点、文本节点。

  • 树:整个html或者xml文档。
  • 节点:树结构中的每个部分(标签、文本、属性、注释等)就是一个节点。
  • 根节点:树结构中的第一个节点就是根节点(网页对应的根节点是html标签)。
  • 元素节点:一个标签就是一个元素节点,例如:<name>沃尔玛</name>
  • 属性节点:标签内的一个属性就是一个属性节点,例如:age="20"
  • 注释节点:树结构中的一个注释就是一个注释节点,例如:<!-- 这是一条平平无奇的注释 -->
  • 文本节点:标签内的文字内容就是一个文本节点,例如:沃尔玛

记住这些概念,就能很好的去寻找节点提取内容了。

五、解析

我们需要使用 lxml 模块中的 etree 包提供的 XML 方法或者 HTML 方法针对于字符串类型的 XML 或者 HTML 进行解析,返回一个 _Element 对象,针对 _Element 对象,可以使用 xpath 方法根据路径表达式进行导航。

(1)先看一下如何进行 XML 或 HTML 的解析。

python 复制代码
from lxml import etree

xmlStr = """
<supermarket>
	  <!--  这是一条平平无奇的注释  -->
    <name>沃尔玛</name>
    <address>中国四川成都</address>
    <staffs>
        <name age="20" sex="男">张三</name>
        <name age="30" sex="男">李四</name>
        <name age="23" gender="女">王五</name>
    </staffs>
    <goods>
        <name price="8">啤酒
            <count>12</count>
        </name>
        <name price="3">饮料
            <count>5</count>
        </name>
        <name price="1" count="10">矿泉水</name>
        <name price="5">花生</name>
        <name price="6">瓜子</name>
        <name price="2">火腿肠</name>
    </goods>
</supermarket>
"""

root = etree.XML(xmlStr)
print(root)
# <Element supermarket at 0x1047401c0>

上述代码通过 etree 中的 XML方法将 XML 文档转化成了一个节点对象,且已经告知我们此处的节点为 supermarket。

(2)继续向下看,我们学习 xpath 语法提取具体内容。

先来看xpath方法的语法:节点对象.xpath(路径表达式)

路径表达式分为绝对路径、相对路径。但是,一般我们都是使用相对路径,所以只需要精通相对路径即可。

  • 绝对路径:不管是哪个节点对象在调用xpath方法,都是以/开头,然后从根节点开始一层一层写起,节点和节点之间使用。
  • 相对路径:哪个节点对象在调用xpath方法,这个节点就使用.表示,然后从此处一层一层开始写。

注意:节点和节点之间使用/间隔,跨越节点要使用//

python 复制代码
# 问题一:使用相对路径获取staffs节点下的三个name节点
nameList = root.xpath('./staffs/name')
print(nameList)
# [<Element name at 0x105551940>, <Element name at 0x105551980>, <Element name at 0x1055519c0>]
# 结果为上述注释,注意,因为此处的root为supermarket节点,下一级便是staffs节点,此处使用的相对路径,所以.表示的便是supermarket节点

# 问题二:使用绝对路径获取staffs节点下的三个name节点
nameList = root.xpath('/supermarket/staffs/name')
print(nameList)
# [<Element name at 0x105551940>, <Element name at 0x105551980>, <Element name at 0x1055519c0>]

# 问题三:获取所有的name节点
nameList = root.xpath('//name')
print(nameList)
# [<Element name at 0x105551a00>, <Element name at 0x105551940>, <Element name at 0x105551980>, <Element name at 0x1055519c0>, <Element name at 0x105551a40>, <Element name at 0x105551ac0>, <Element name at 0x105551b00>, <Element name at 0x105551b40>, <Element name at 0x105551b80>, <Element name at 0x105551a80>]

在路径的最后添加/text(),可以得到此节点里面的内容;添加/@属性名,可以得到此节点中属性对应的值。

python 复制代码
nameList = root.xpath('./staffs/name/text()')
print(nameList)
# ['张三', '李四', '王五']

sexList = root.xpath('./staffs/name/@sex')
print(sexList)
# ['男', '男']

谓语,在路径中需要添加条件的节点后面添加[],在[]中写条件。

  • N\]:表示获取第N个节点,从数字1开始。

获取第二个员工的姓名

print(root.xpath('./staffs/name[2]/text()'))

['李四']

复制代码
* \[last()\]:表示获取最后一个节点。

```python
# 获取倒数第二个员工的姓名
print(root.xpath('./staffs/name[last()-1]/text()'))
# ['李四']
  • position():获取某些位置的标签
python 复制代码
# 获取前两个员工的年龄
print(root.xpath('./staffs/name[position()<=2]/@age'))
print(root.xpath('./staffs/name[position()<3]/@age'))
# ['20', '30']

# 获取后两个员工的年龄
print(root.xpath('./staffs/name[position()>=last()-1]/@age'))
print(root.xpath('./staffs/name[position()>last()-2]/@age'))
# ['30', '23']
  • @属性名

python 复制代码
# 获取有年龄信息的员工姓名
print(root.xpath('./staffs/name[@age]/text()'))
# ['张三', '李四', '王五']
  • @属性名=属性值

python 复制代码
# 获取属性sex="男"的员工的姓名
print(root.xpath('./staffs/name[@sex="男"]/text()'))
# ['张三', '李四']
  • 子标签名=值\]、\[子标签名\>值\]等

获取有count子标签且标签内容等于12的父标签的内容

print(root.xpath('./goods/name[count=12]/text()'))

['啤酒\n ', '\n ']

复制代码
分支(**|** ):将多个路径选择器使用`|`间隔,同时获取多个元素。

```python
print(root.xpath('./staffs/name/text()|./staffs/name/@age'))
# ['20', '张三', '30', '李四', '23', '王五']

print(root.xpath('./staffs/name/text()|./staffs/name/@sex'))
# ['男', '张三', '男', '李四', '王五']

总结,与CSS选择器一样,XPath路径选择器也需要灵活运用

相关推荐
沉到海底去吧Go18 分钟前
【图片识别改名】批量读取图片区域文字识别后批量改名,基于Python和腾讯云的实现方案
开发语言·python·腾讯云
百锦再35 分钟前
Python深度挖掘:openpyxl和pandas的使用详细
java·开发语言·python·框架·pandas·压力测试·idea
Jackilina_Stone1 小时前
【论文阅读/复现】RT-DETR的网络结构/训练/推理/验证/导出模型
论文阅读·python·目标检测·rt-detr
编程自留地1 小时前
第10次:电商项目配置开发环境
python·django·商城
IT技术员1 小时前
【Java学习】动态代理有哪些形式?
java·python·学习
q_q王1 小时前
本地知识库工具FASTGPT的安装与搭建
python·大模型·llm·知识库·fastgpt
lanboAI1 小时前
基于卷积神经网络的蔬菜水果识别系统,resnet50,mobilenet模型【pytorch框架+python源码】
pytorch·python·cnn
一刀到底2111 小时前
ai agent(智能体)开发 python3基础8 网页抓取中 selenium 和 Playwright 区别和联系
人工智能·python
剑哥在胡说1 小时前
Python三大Web框架对比:Django、Flask、Tornado的异步实现方式详解
数据库·python·django·flask·tornado
da-peng-song2 小时前
ArcGIS arcpy代码工具——根据属性结构表创建shape图层
javascript·python·arcgis