Python爬虫解析利器Xpath,由浅入深快速掌握(附源码例子)

Posted 攻城狮白玉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python爬虫解析利器Xpath,由浅入深快速掌握(附源码例子)相关的知识,希望对你有一定的参考价值。

目录

前言

一、什么是Xpath

二、安装lxml

三、lxml初体验

四、lxml加载HTML文本

五、巧用浏览器开发工具

六、教程源码

总结

写在后面


前言

咱们在爬虫的时候,通常能够把目标网页给请求到。并把整个网页的内容拿到。然而并不是整个网页的数据都是我们需要的。我们的目标数据可能只是网页里面某些特定位置的数据。这个时候我们可以使用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,由浅入深快速掌握(附源码例子)的主要内容,如果未能解决你的问题,请参考以下文章

Python爬虫利器三之Xpath语法与lxml库的用法

快速入门 Python 爬虫常用解析库(xpathbs4)

Python爬虫利器六之PyQuery的用法

芝麻HTTP: Python爬虫利器之PyQuery的用法

14_Python_爬虫利器Requests-HTML使用方法

Python爬虫:数据解析 之 xpath