Python爬虫解析利器Xpath,由浅入深快速掌握(附源码例子)
Posted 攻城狮白玉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python爬虫解析利器Xpath,由浅入深快速掌握(附源码例子)相关的知识,希望对你有一定的参考价值。
目录
前言
咱们在爬虫的时候,通常能够把目标网页给请求到。并把整个网页的内容拿到。然而并不是整个网页的数据都是我们需要的。我们的目标数据可能只是网页里面某些特定位置的数据。这个时候我们可以使用Xpath对于数据进行定位。
一、什么是Xpath
Xpath 是在XML文档中搜索内容的一门语言。XML是可扩展标记语言。通常用于描述数据。我们熟悉的html语言其实可以看作是XML语言的一个子集。因此学习Xpath这个搜索工具也可以用在对于HTML文本中的内容搜索。
二、安装lxml
人生苦短,我选python。在python里面使用Xpath,咱们要引入lxml模块。
pip install lxml
如果下载太慢的话可以用国内清华源
pip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simple
三、lxml初体验
安装完lxml模块之后,我们把它导入进来
from lxml import etree
我们定义一个xml的文本。内容如下:
<idol>
<id>1</id>
<name>周杰伦</name>
<nick>Jay</nick>
<nick>胖伦</nick>
<nick>公举伦</nick>
<song>
<title id="1">晴天</title>
<title id="2">七里香</title>
<title id="3">龙卷风</title>
<title id="4">甜甜的</title>
</song>
<div>
<nick>第一个div的nick</nick>
<div>
<nick>第二个div的nick</nick>
<div>
<nick>第三个div的nick</nick>
</div>
</div>
</div>
<span>
<nick>span的nick</nick>
</span>
<partner>
<nick id="fws">方文山</nick>
<nick id="yrd">杨瑞代</nick>
<nick id="jp">巨炮</nick>
</partner>
</idol>
在正式进入编程之前,补充几个基本概念
- 根节点
- 父节点
- 子节点
- 同胞节点
最上层的<idol>标签是根节点,根节点就是第一个节点。,接下来的<id>标签是<idol>标签的子节点。<idol>标签是<id>标签的子节点。父子节点是相对的。<title>标签是<song>的子节点,是<idol>的孙节点。<id>和<nick>还有<song>则是同胞节点。也就是说,同一级的节点就称之为同胞节点。
我们把xml文本加载进来
xml_tree = etree.XML(xml)
加载完成后,咱们直接使用.xpath()方法就可以填入xpath路径对数据进行定位了
代码如下:
xml_tree = etree.XML(xml)
result = xml_tree.xpath('/idol') # /表示层级关系,第一个/是根节点
print(result)
如果我们想拿某个标签的值的话,我们只需要在对应的标签后面再加一个text()即可进行取值。
xml_tree = etree.XML(xml)
name = xml_tree.xpath('/idol/name/text()') # text()拿文本
print(name)
# text()拿文本,拿到周杰伦的昵称
nick = xml_tree.xpath('/idol/nick/text()')
print(nick)
上面只是拿到了/idol/nick的节点的数据
但是我想把根节点下面的所有nick标签都拿到要怎么办呢?我们只需要把xpath路径要查找的节点加上双斜杠,代码如下:
xml_tree = etree.XML(xml)
# idol标签后面是两杠连着nick标签的话,表示迭代idol里面所有的nick标签出来
all_nick = xml_tree.xpath('/idol//nick/text()')
print(all_nick)
四、lxml加载HTML文本
我们已经初步了解了xpath的使用,这里我们进一步学习,用xpath来解析HTML文件。这个在咱们爬虫的时候也是用的比较多的。在这里我先准备了一个baiyu.html文件,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<ul>
<li><h1 class="name">
<a href="https://blog.csdn.net/zhh763984017">攻城狮白玉</a>
</h1></li>
<li><h1 class="sex"><a>男</a></h1></li>
<li><h1 class="describe"><a>宇宙第一超级无敌帅</a></h1></li>
<li><h1><a>一只攻城狮</a></h1></li>
</ul>
<ol>
<li>
<a href="https://blog.csdn.net/zhh763984017/article/details/117876313">
【语言】拯救新手,半小时从零到一认识C语言基础</a>
</li>
<li>
<a href="https://blog.csdn.net/zhh763984017/article/details/118057831">
【C语言】数据类型一文详解</a>
</li>
<li>
<a href="https://blog.csdn.net/zhh763984017/article/details/118343859">
【C语言】函数详解(入门到进阶)</a>
</li>
</ol>
<div class="job">混凝土瞬间移动工程师</div>
<div class="hobby">爱好:女</div>
</body>
</html>
页面效果如下(有点丑,前端大佬们 别喷)
我们把HTML文件通过pares()方法载入进来
tree = etree.parse('baiyu.html')
索引出ul下的所有a标签的值
# 索引出所有的符合条件的a标签的值
me = tree.xpath('/html/body/ul/li/h1/a/text()') 7
print(me)
输出的列表值是,
['攻城狮白玉', '男', '宇宙第一超级无敌帅', '一只攻城狮']
但是我此时只想要第一个的值,即我的名字的值,此时我们只需要在li索引第一个的值就好了,xpath的索引初始值是1,跟咱们在数组或者列表学习时的初始索引不一样。
# xpath的顺序是从1开始数的,中括号[]表示索引,数字索引表示第几个
name = tree.xpath('/html/body/ul/li[1]/h1/a/text()')
print(name)
输出列表是
['攻城狮白玉']
上面通过 tree.xpath('/html/body/ul/li/h1/a/text()') 索引出来的是所有的h1标签下的a标签
如果我只需要带有class属性的h1标签下a标签的话,那我们只需要在通过@属性来进行索引
# 索引出所有的带class属性的a标签的值
me_class = tree.xpath('/html/body/ul/li/h1[@class]/a/text()')
print(me_class) # 一只攻城狮这个标签是不带class属性的,所以没有输出
输出列表
['攻城狮白玉', '男', '宇宙第一超级无敌帅']
此时我们发现一只攻城狮,这个值没有了,因为它不带class属性
除了通过数字进行索引定位到具体的标签,我们也可以通过属性的值定位到具体的标签。例如找到class值为describe的标签
# 索引出class="describe"
describe = tree.xpath('/html/body/ul/li/h1[@class="describe"]/a/text()')
print(describe)
输出的值
['宇宙第一超级无敌帅']
在实际应用中,很多时候,我们并不直接从根节点进行数据操作。而是先确定一个范围节点作为我们的根节点。lxml也允许我们进行相对操作。
例如我在示例代码里面文章链接都是在<ol>标签下<li>标签的<a>标签里面的属性数据。于是我们可以先定位到<ol>下的<li>作为根节点,然后从当前节点找到对应的<a>标签
article_list = tree.xpath("/html/body/ol/li")
for article in article_list:
article_name = article.xpath("./a/text()") # 在li中继续寻找,./是相对查找
article_url = article.xpath("./a/@href") # 拿到属性值,@属性
print(article_name, article_url)
这里拿到所有的数据之后就进行一个遍历。然后通过text()和@属性把对应的值和属性值给取出来。
五、巧用浏览器开发工具
我们这么根据节点这样一个一个去敲xpath路径进行定位,是可行的,不过当页面比较复杂的时候呢,我们有时可能会数乱了。这个时候我们可以利用浏览器的开发者工具协助我们做一些事情。在这里我用的是谷歌浏览器chrome。
在我们打开我预先准备好的网页之后,按一下F12,打开开发者工具,点击第一个按钮“选择一个元素进行审查”
接着我们找到我们想要定位的标签。比如这里我要把我的工作描述——混凝土瞬间移动工程师。给选出来,并且赋值了xpath路径。当我们直接粘贴的时候,就是这个标签对应的xpath路径了。
此时我们复制到的值就是‘/html/body/div[1]’,粘贴到xpath打印出对应的值。
# 因为返回的值是是列表,用索引的可以取出来列表元素
job = tree.xpath('/html/body/div[1]/text()')[0]
print("工作:", job)
输出的值:
工作: 混凝土瞬间移动工程师
很多时候,我们可以通过浏览器的开发者工具,将复杂的xpath路径复制出来,然后进行一个微调。这样子可以节省很多时间。
六、教程源码
本文的所有代码如下:
from lxml import etree
# 加载xml数据
def load_xml():
xml = '''
<idol>
<id>1</id>
<name>周杰伦</name>
<nick>Jay</nick>
<nick>胖伦</nick>
<nick>公举伦</nick>
<song>
<title id="1">晴天</title>
<title id="2">七里香</title>
<title id="3">龙卷风</title>
<title id="4">甜甜的</title>
</song>
<div>
<nick>第一个div的nick</nick>
<div>
<nick>第二个div的nick</nick>
<div>
<nick>第三个div的nick</nick>
</div>
</div>
</div>
<span>
<nick>span的nick</nick>
</span>
<partner>
<nick id="fws">方文山</nick>
<nick id="yrd">杨瑞代</nick>
<nick id="jp">巨炮</nick>
</partner>
</idol>
'''
xml_tree = etree.XML(xml)
result = xml_tree.xpath('/idol') # /表示层级关系,第一个/是根节点
print(result)
# result = xml_tree.xpath('/idol/name')
name = xml_tree.xpath('/idol/name/text()') # text()拿文本
print(name)
nick = xml_tree.xpath('/idol/nick/text()') # text()拿文本
print(nick)
all_nick = xml_tree.xpath('/idol//nick/text()') # author标签后面是两杠的话,表示迭代author里面所有的nick标签出来
print(all_nick)
# 加载html文件
def load_html():
tree = etree.parse('baiyu.html')
me = tree.xpath('/html/body/ul/li/h1/a/text()') # 索引出所有的符合条件的a标签的值
print(me)
name = tree.xpath('/html/body/ul/li[1]/h1/a/text()') # xpath的顺序是从1开始数的,中括号[]表示索引,数字索引表示第几个
print(name)
sex = tree.xpath('/html/body/ul/li[2]/h1/a/text()')
print(sex)
me_class = tree.xpath('/html/body/ul/li/h1[@class]/a/text()') # 索引出所有的带class属性的a标签的值
print(me_class) # 一只攻城狮这个标签是不带class属性的,所以没有输出
describe = tree.xpath('/html/body/ul/li/h1[@class="describe"]/a/text()') # 索引出class="describe"
print(describe)
# result = tree.xpath('/html/body/ol/li/a[@href]/text()') # [@xxx]表示,属性xxx的索引
article_list = tree.xpath("/html/body/ol/li")
for article in article_list:
article_name = article.xpath("./a/text()") # 在li中继续寻找,./是相对查找
article_url = article.xpath("./a/@href") # 拿到属性值,@属性
print(article_name, article_url)
job = tree.xpath('/html/body/div[1]/text()')[0] # 因为返回的值是是列表,用索引的可以取出来列表元素
print("工作:", job)
hobby = tree.xpath('/html/body/div[@class="hobby"]/text()')[0]
print(hobby)
if __name__ == '__main__':
load_xml()
print('-------------')
load_html()
总结
通过xpath我们可以轻松定位到XML文本或者HTML文本里的内容。借助lxml库,我们可以通过python快速使用xpath对于标记文本进行解析。
写在后面
如果觉得有用的话,麻烦一键三连支持一下攻城狮白玉,并把本文分享给更多的小伙伴。你的简单支持,我的无限创作动力
以上是关于Python爬虫解析利器Xpath,由浅入深快速掌握(附源码例子)的主要内容,如果未能解决你的问题,请参考以下文章