Python(爬虫篇)--- Xpath语法

本文介绍了XML的基本概念及其与HTML的区别,详细讲解了XPath在选取XML节点中的各种方法,包括谓语、通配符和路径组合。并展示了Python的lxml模块如何用于XML和HTML解析,通过实例演示了如何使用XPath提取数据。最后,给出了一个爬取网易云音乐歌手信息的案例,展示了如何通过XPath和lxml实现数据抓取和处理。
摘要由CSDN通过智能技术生成


一、XML简介

昨天分享了爬虫的正则表达式,以此来获取数据,但是难度很高,有时候并不能完全掌握,处理HTML文档很累,那么有没有其他的办法呢?答案是肯定的,那就是XPath,我们可以:

  1. 先将HTML文件转换成XML文档
  2. 然后用XPath查找HTML节点或元素

(一)什么是XML

  • XML 指可扩展标记语言(EXtensible Markup Language)。
  • XML 是一种标记语言,很类似 HTML。
  • XML 的设计宗旨是传输数据,而非显示数据。
  • XML 的标签需要我们自行定义。
  • XML 被设计为具有自我描述性。
  • XML 是 W3C 的推荐标准。

W3School 官方文档http://www.w3school.com.cn/xml/index.asp

(二)XML和HTML的区别

他们两者都是用于操作数据或者结构数据,在结构上大致相同的,但他们在本质上却存 在着明显的区别。

数据格式描述设计目标
XMLExtensible Markup Language ( 可扩展标记语言)被设计为传输和存储数据,其焦点 是数据的内容。
HTMLHyperText Markup Language(超文本标记语言)显示数据以及如何更好显示数据。
HTML DOMDocument Object Model for HTML(超文本标文档 对象模型)通过 HTML DOM,可以访问所有 的 HTML 元素, 连同它们所包含 的文本和属性。可以对其中的内容 进行修改和删除,同时也可以创建 新的元素。

二、XPATH

XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文 档中对元素和属性进行遍历。

(一)选取节点

XPath使用路径表达式来选取XML文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。下面列出最常用的路径表达式:

表达式描述
nodename选取此节点的所有子节点
/从节点选取
//从匹配选择的当前节点选择文档中的节点,而不考虑他们的位置
.选取当前节点
··选取当前节点的父节点
@选取属性

(二)谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中。
在后面会举例说明。

(三)选取未知节点

XPath 通配符可用来选取未知的 XML 元素。

通配符描述
*匹配任何元素节点。
@*匹配任何属性节点。

(四)选取若干路径

通过在路径表达式中使用“|”运算符,可以选取若干个路径。在后面会举例说明。

三、lxml模块

(一)lxml 简介与安装

lxml 是一个 HTML/XML 的解析器,主要的功能是如何解析和提取 HTML/XML 数据。 我们可以利用之前学习的 XPath 语法,来快速的定位特定元素以及节点信息。

安装方法:pip install lxml

(二)lxml 初步使用

1. 导入方式

  1. 直接导入:from lxml import etree
    注意:此种导入方式,可能会报错(etree下面会出现红色波浪线,不影响正常使用)
  2. 标准导入:
    from lxml import html
    etree = html.etree

2. 内置方法及说明

下面的例子中使用这个 XML 文档:

str = '<bookstore>' \
            '<book>' \
                '<title lang="bng" src="https://www.baidu.com">Harry Potter</title>' \
                '<price>29.99</price>' \
            '</book>' \
            '<book>' \
                '<title class="t1" lang="ang">Learning XML</title>' \
                '<price>39.95</price>' \
            '</book>' \
            '<book>' \
                '<title lang="cng">西游记</title>' \
                '<price>69.95</price>' \
            '</book>' \
            '<book>' \
                '<title  lang="dng" src="https://www.jdfgd.com">水浒传</title>' \
                '<price>29.95</price>' \
            '</book>' \
            '<book>' \
                '<title class="t1" lang="dng" src="https://www.jd.com">三国演义</title>' \
                '<price>29.95</price>' \
            '</book>' \
        '</bookstore>'

  1. etree.HTML()
    将字符串转换成HTML元素对象,可以自动添加缺失的元素

例:

html = etree.HTML(str)
print(html)  # <Element html at 0x39dec88>
  1. tostring():查看转换之后的内容(二进制类型)
    如果想要查看字符串类型,需要解码
    如果想要显示汉字,需要先编码,再解码

例:

content = etree.tostring(html,encoding='utf-8')
print(content.decode())
  1. xpath()
    作用:提取页面数据,返回值是一个列表
    xpath的使用一定是建立在etree.HTML()之后的内容中的
    问:xpath是如何来提取页面数据的?
    答:使用的是路径表达式

xpath路径分为两种:
第一种:/
代表一层层的查找,如果/存在于开头,代表根路径
例如:查找bookstore标签

bookstore = html.xpath('/html/body/bookstore')
print(bookstore)  # [<Element bookstore at 0x39d5d48>]

第二种://
任意路径 焦点在元素身上
例如:查找bookstore标签

bookstore = html.xpath('//bookstore')
print(bookstore)  # [<Element bookstore at 0x39d5d88>]

第一种和第二种结合
例如:查找bookstore标签

book = html.xpath('//bookstore/book')
print(book)  # [<Element book at 0x39d5d48>, <Element book at 0x39d5c48>, <Element book at 0x39d5d88>, <Element book at 0x39d5dc8>, <Element book at 0x39d5e08>]
  1. /text():获取标签之间的内容
    例如:获取所有title标签的内容
    步骤:
    1.找到所有title标签
    2.获取内容
title = html.xpath('//book/title/text()')
print(title)  # ['Harry Potter', 'Learning XML', '西游记', '水浒传', '三国演义']
  1. 谓语使用:可以理解成条件
  • [n] 代表获取第n个元素,n是数字,n>=1
    例如:获取第二个title标签
title = html.xpath('//book[2]/title/text()')
print(title)  # ['Learning XML']
  • last():获取最后一个
    同理:last()-1 获取倒数第二个
    例如:获取最后一本书的title标签之间的内容
title = html.xpath('//book[last()]/title/text()')
print(title)  # ['三国演义']
  • position():位置,范围 支持 > / < / = / >= / <= / !=
    例如:获取最后两本书的title标签之间的内容
    步骤:
    1.先获取后两本书
    2.获取内容
title = html.xpath('//book[position()>3]/title/text()')
title = html.xpath('//book[position()>last()-2]/title/text()')
print(title)  # ['水浒传', '三国演义']
  • 获取属性值:@属性名
    例如:获取lang属性值为cng的title标签的内容
title = html.xpath('//book/title[@lang="cng"]/text()')
print(title)   # ['西游记']
  • and :与
    连接的是谓语(条件)
    例如:获取lang="dng"并且class="t1"的title标签的内容
title = html.xpath('//book/title[@lang="dng" and @class="t1"]/text()')
title = html.xpath('//book/title[@lang="dng"][@class="t1"]/text()')
print(title)  # ['三国演义']
  • or:或
    例如:查找lang="cng"或者lang="bng"的title标签的内容
title = html.xpath('//book/title[@lang="cng" or @lang="bng"]/text()')
print(title)
  1. | 使用 :连接路径
    例如:获取所有title标签和price标签之间的内容
title_price = html.xpath('//title/text() | //price/text()')
print(title_price) # ['Harry Potter', '29.99', 'Learning XML', '39.95', '西游记', '69.95', '水浒传', '29.95', '三国演义', '29.95']
  1. parse():从文件中读取数据
    注意:读取的文件,必须满足xml格式(不存在单标签,全部都是双标签)
content = etree.parse('Node.html')
print(content)  # <lxml.etree._ElementTree object at 0x00000000039D5D48>
res = etree.tostring(content)
print(res)

四、案例:网易云音乐歌手信息爬取

需求:
获取每一个大分类下的每一个子分类下的所有歌手名

在这里插入图片描述
思路:

  1. 获取大分类的URL,并请求
  2. 获取小分类的URL,并请求
  3. 获取歌手名
import requests
from lxml import etree

# 定义请求函数
def get_requests(url):
    response = requests.get(url=url,headers=headers)
    return etree.HTML(response.text)

# 定义获取完整链接的函数
def get_full_href(url):
    return 'https://music.163.com'+url

# 定义获取大分类url的函数
def get_big_type(url):
    # 发起请求,接收响应
    # response = requests.get(url=url,headers=headers)
    # 转换成HTML元素对象
    html = get_requests(url)
    # 获取大分类的URL
    big_type_list = html.xpath('//div[@class="blk"]/ul/li')
    for big_type in big_type_list:
        # 获取大标题链接
        big_href = big_type.xpath('./a/@href')[0]
        # 需要拼接成完整的链接
        big_href_full = get_full_href(big_href)
        get_small_type(big_href_full)
        # print(big_href_full)
    pass

# 定义获取小分类URL的函数
def get_small_type(big_href_full):
    html = get_requests(big_href_full)
    # 获取每一个小分类
    small_li_list = html.xpath('//ul[@id="initial-selector"]/li')
    for small_li in small_li_list:
        # 获取小分类名字
        small_name = small_li.xpath('./a/text()')[0]
        # 获取小分类的链接
        small_href = small_li.xpath('./a/@href')[0]
        small_full_href = get_full_href(small_href)
        # print(small_full_href)
        get_singer(small_name,small_full_href)
        ...
# 定义获取歌手的函数
def get_singer(small_name,small_full_href):
    html = get_requests(small_full_href)
    # 获取歌手名
    # 前五个://ul[@id="m-artist-box"]/li/p/a/text()
    # 中间五个://ul[@id="m-artist-box"]/li[@class="line"]/p/a/text()
    # 其它://ul[@id="m-artist-box"]/li[@class="sml"]/a/text()
    # 最终得到:
    # //ul[@id="m-artist-box"]/li//a/text()
    singer = html.xpath('//ul[@id="m-artist-box"]/li//a/text()')
    # 保存数据
    write_to_txt(small_name,singer)
    # print(singer)
    ...

# 定义保存数据函数
def write_to_txt(small_name,singer):
    dic = {}
    dic['小标题'] = small_name
    dic['歌手'] = singer
    with open('网易云歌手.txt','a',encoding='utf-8') as fp:
        fp.write(str(dic)+'\n')


if __name__ == '__main__':
    # 定义基础URL
    base_url = 'https://music.163.com/discover/artist'
    # 定义请求头
    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36',
    }
    get_big_type(base_url)

感谢浏览
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值