可狱可囚的爬虫系列课程 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开始。
python 复制代码
# 获取第二个员工的姓名
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()'))
# ['张三', '李四']
  • [子标签名=值]、[子标签名>值]等
python 复制代码
# 获取有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路径选择器也需要灵活运用

相关推荐
WIN赢34 分钟前
【性能测试入门_01性能测试jmeter基础实操场景详解】
ide·python·pycharm
请为小H留灯2 小时前
Python中很常用的100个函数整理
开发语言·python
七月初七773 小时前
Excel多级联动下拉菜单设置
python·excel·pandas
Serendipity_Carl3 小时前
Pandas数据清洗实战之清洗猫眼电影
python·pycharm·数据分析·pandas
.昕..4 小时前
(二)seacmsv9注入管理员账号密码+orderby+limit
python·网络安全
码叔义5 小时前
X509TrustManager信任SSL证书
python·网络协议·ssl
阿波拉5 小时前
AttributeError: module ‘backend_interagg‘ has no attribute ‘FigureCanvas’问题解决
开发语言·python
m0_748247805 小时前
Python连接SQL SEVER数据库全流程
数据库·python·sql
BigBookX6 小时前
使用OpenCV来获取视频的帧率
python·opencv