五:爬虫-数据解析之xpath解析

五:数据解析之xpath解析

1.xpath介绍:
  • xpathXML路径语言,它可以用来确定xml文档中的元素位置,通过元素路径来完成对元素的查找,HTML就是XML的一种实现方式,所以xpath是一种非常强大的定位方式
  • XPathXML Path Language)是一种XML的查询语言,它能在XML树状图中寻找节点。XPath用于在XML文档中通过元素和属性进行导航
  • xml是一种标记语法的文本格式,xpath可以方便的定位xml中的元素和其中的属性值。lxml是Python中的一个第三方模块,它包含了将html文本转成xml对象,和对对象执行xpath的功能

lxml的安装:

python 复制代码
#在终端输入
pip install lxml

xpath的弊端:

​ 当我们在批量获取数据的时候,如果存在的特别数据比较多,这个时候只用xpath的话,会无法满足用户的需求,所以针对于不同的网页,我们要灵活的去运用我们的数据解析方式

(1)HTML树状结构图:

HTML 的结构就是树形结构,HTML 是根节点,所有的其它元素节点都是从根节点发出的,其它的元素都是这棵树上的节点,每个节点还可能有属性和文本值,而路径就是指某个节点到另一个节点的路线

(2)节点之间的关系:

  • 父节点:HTML 是 body 和 head 节点的父节点
  • 子节点:headbodyHTML 的子节点
  • 兄弟节点:拥有相同的父节点,headbody 就是兄弟节点,titlediv 不是兄弟,因为他们不是同一个父节点
  • 祖先节点:bodyform 的祖先节点,爷爷辈及以上
  • 后代节点:formHTML 的后代节点,孙子辈及以下
2.Xpath中的绝对路径与相对路径 :

Xpath中的绝对路径是从HTML根节点开始算的;而相对路径(使用的更多)则是从任意节点开始的。通过开发者工具,我们可以拷贝到Xpath的绝对路径和相对路径代码:

注意: 绝对路径是以 Elements 为基准去寻找的,我们爬虫获取的是右键的网页源代码;右键的网页源代码 != ElementsElements 是前端页面最终渲染的结果,它与网页源代码是有属性上的差异的;但右键的网页源代码与Elements是非常相似的,但是在某些元素或者元素属性上会存在不同。这就会导致我们直接右键复制的xpath获取不到真正的数据;所以说只能手写,不能复制(把数据解析全部学会之后,可以复制,因为到那个时候就有能力对复制到的内容进行微调了)

(1)绝对路径(了解即可):

​ 在Xpath中最直观的定位策略就是绝对路径,绝对路径是从根节点/html开始往下一层层的表示,直到出来需要的节点为止

(2)相对路径(常用):

​ 在Xpath中相对路径方法以 "//" 开头,相对路径可以从任意的节点开始,一般会选取一个可以唯一定位到的元素开始写,这样可以增加查找的准确性

相对路径的定位语法:

(1)基本定位语法:

表达式 说明 举例
/ 从根节点开始选取 /html/div/span
// 从任意节点开始选取 //input
. 选取当前节点
.. 选取当前节点的父节点 //input/.. 选取input的父节点
@ 选取属性或者根据属性选取 //input[@data]选取具备data属性的input元素 //@data 选取所有data属性
* 通配符,表示任意节点或任意属性

(2)元素属性定位:

(3)层级属性结合定位:

​ 遇到某些元素无法精确定位的时候,可以查找其父级及其祖先节点,找到有确定的祖先节点后通过层级依次向下定位

示例:

python 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="search" id="form" method="post">
  <span class="bg">
    <span class="soutu">搜索</span>
  </span>
  <span class="soutu">
    <input type="text" name="key" id="su">
  </span>
  <div></div>
</form>
</body>
</html>

图片解析:

(4)使用谓语定位:

​ 谓语是Xpath中用于描述元素位置,主要有数字下标、最后一个子元素last()、元素下标函数position()

注意: Xpath中的下标从 1 开始

图片解析:

python 复制代码
1、使用下标的方式,从form找到input:
//form[@id="form"]/span[2]/input

2、查找最后一个子元素,选取form下的最后一个span:
//form[@id="form"]/span[last()]

3、查找倒数第几个子元素,选取 form下的倒数第二个span:
//form[@id="form"]/span[last()-1]

4、使用 position() 函数,选取 from 下第二个span:
//form[@id="form"]/span[position()=2]

5、使用 position() 函数,选取下标大于 2 的span:
//form[@id="form"]/span[position()>2]

(5)使用逻辑运算符定位:

​ 用于嵌套的标签,如果元素的某个属性无法精确定位到这个元素,还可以用逻辑运算符and连接多个属性进行定位

以百度首页为例:

python 复制代码
使用and:
//*[@name='wd' and @class='s_ipt']
#查找 name 属性为 wd 并且 class 属性为 s_ipt 的任意元素

使用or:
//*[@name='wd' or @class='s_ipt']
#查找 name 属性为 wd 或者 class 属性为 s_ipt 的任意元素,取其中之一满足即可

以上述示例代码为例:

python 复制代码
使用|同时查找多个路径,取或:
//form[@id="form"]//span | //form[@id="form"]//input

(6)使用文本定位:

​ 我们在爬取网站使用Xpath提取数据的时候,最常使用的就是Xpathtext()方法,该方法可以提取当前元素的信息,但是某些元素下包含很多嵌套元素,这时候就用到了string()方法

爬取别逗了网站示例代码:

python 复制代码
import requests
from lxml import etree

url = 'https://www.biedoul.com/article/180839'

headers= {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}

response = requests.get(url,headers=headers)
response.encoding = 'utf-8'  # 在requests.get的时候,会默认指定一个编码,但默认指定的编码不一定会是utf-8,是随机的

# 将获取的网页源代码html文件转换成xml对象,方便后续执行xpath语法
html = etree.HTML(response.text)
data = html.xpath('//div[@class="cc2"]//text()')  # //text()指的是取标签中的文本值,不是属性值
# print(data)
#
# data = [i.replace('\r\n','') for i in data]
# print('\n'.join(data))

data1 = html.xpath('//div[@class="cc2"]')[0].xpath('string(.)')
print(data1)

注意: xpath对象获取的数据返回的是一个列表

(7)使用部分匹配函数:

函数 说明 示例
contains 选取属性或者文本包含某些字符 //div[contains(@id, 'data')]选取id属性包含datadiv元素
starts-with 选取属性或者文本以某些字符开头 //div[starts-with(@id, 'data')]选取id属性以data开头的div元素
ends-with 选取属性或者文本以某些字符结尾 //div[ends-with(@id, 'require')]选取id属性以require结尾的div元素
3.lxml的使用与xpath实战:

(1)lxml的基本使用:

python 复制代码
# 导入模块
from lxml import etree
# html源代码
web_data = """
        <div>
            <ul>
                 <li class="item-0"><a href="link1.html">first item</a></li>
                 <li class="item-1"><a href="link2.html">second item</a></li>
                 <li class="item-inactive"><a href="link3.html">third item</a></li>
                 <li class="item-1"><a href="link4.html">fourth item</a></li>
                 <li class="item-0"><a href="link5.html">fifth item</a>
             </ul>
         </div>
        """
# 将html转成xml对象
element = etree.HTML(web_data)
# print(element)
# 获取li标签下面的a标签的href
links = element.xpath('//ul/li/a/@href')
print(links)  # 列表
# 获取li标签下面的a标签的文本数据
result = element.xpath('//ul/li/a/text()')
print(result)

(2)xpath实战 -- 豆瓣top250示例代码:

python 复制代码
import requests
from lxml import etree
'''
目标:熟悉xpath解析数的方式
需求:爬取电影的名称 评分 引言 详情页的url  翻页爬取1-10页 保存到列表中

如何实现?
设计技术与需要的库 requests lxml(etree)

实现步骤
1 页面分析(一般讲数据解析模块 都是静态页面)
   1.1 通过观察看网页源代码中是否有我们想要的数据 如果有就分析这个url
        如果没有再通过ajax寻找接口   通过分析数据在网页源代码中

   1.2 确定目标url
        https://movie.douban.com/top250?start=0&filter= 第一页
        通过页面分析发现所有我们想要的数据都在一个div[class="info"]里面

具体实现步骤
1 获取整个网页的源码 html
2 将获取的数据源码转成一个element对象(xml)
3 通过element对象实现xpath语法 对数据进行爬取(标题 评分 引言 详情页的url)
4 保存数据  先保存到字典中-->列表中

'''

# 定义一个函数用来获取网页源代码
def getsource(pagelink):
    # 请求头
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
    }
    # 获取源码
    response = requests.get(pagelink, headers=headers)
    response.encoding = 'utf-8'
    html = response.text
    return html

# 定义一个函数用于解析我们的网页源代码并获取我们想要的数据
def geteveryitem(html):
    element = etree.HTML(html)
    # 拿到[class="info"]的所有div
    movieitemlist = element.xpath('//li//div[@class="info"]')
    # print(movieitemlist,len(movieitemlist))
    # 定义一个列表
    itemlist = []
    for item in movieitemlist:
        # 定义一个字典
        itemdict = {}
        # 标题
        title = item.xpath('./div[@class="hd"]/a/span[@class="title"]/text()')
        title = "".join(title).replace("\xa0", "")
        # print(title)
        # 副标题
        othertitle = item.xpath('./div[@class="hd"]/a/span[@class="other"]/text()')[0].replace("\xa0", "")
        # print(othertitle)
        # 评分
        grade = item.xpath('./div[@class="bd"]/div[@class="star"]/span[2]/text()')[0]
        # print(grade)
        # 详情页的url
        link = item.xpath('div[@class="hd"]/a/@href')[0]
        # print(link)
        # 引言
        quote = item.xpath('div[@class="bd"]/p[@class="quote"]/span/text()')
        # print(quote)
        # list index out of range
        # 处理方式1 非空处理
        if quote:
            quote = quote[0]
        else:
            quote = ""
        # 将数据存放到字典中
        itemdict['title'] = ''.join(title + othertitle)
        itemdict['grade'] = grade
        itemdict['link'] = link
        itemdict['quote'] = quote
        # print(itemdict)
        itemlist.append(itemdict)
    # print(itemlist)
    return itemlist

if __name__ == '__main__':
    url = 'https://movie.douban.com/top250?start=0&filter='
    html = getsource(url)
    itemlist = geteveryitem(html)
    
    print(itemlist)
dict['quote'] = quote
        # print(itemdict)
        itemlist.append(itemdict)
    # print(itemlist)
    return itemlist

if __name__ == '__main__':
    url = 'https://movie.douban.com/top250?start=0&filter='
    html = getsource(url)
    itemlist = geteveryitem(html)
    
    print(itemlist)
相关推荐
谢景行^顾20 小时前
numpy
开发语言·python·numpy
上天夭21 小时前
PyTorch的Dataloader模块解析
人工智能·pytorch·python
是一个Bug21 小时前
Spring Boot 的全局异常处理器
spring boot·后端·python
dTTb21 小时前
python元组和字典
python
沐雪轻挽萤21 小时前
pytorch模型部署基础知识
人工智能·pytorch·python
xxxxxmy21 小时前
相向双指针—接雨水
python·相向双指针
nix.gnehc21 小时前
PyTorch数据加载与预处理
人工智能·pytorch·python
Sindy_he21 小时前
2025最新版微软GraphRAG 2.0.0本地部署教程:基于Ollama快速构建知识图谱
python·microsoft·大模型·知识图谱·rag
MadPrinter21 小时前
FindQC 实战 (二):挑战 Google Lens —— 基于 Playwright 的隐匿模式与反爬虫机制构建
爬虫
鲸落✗21 小时前
深入解析单HTML实现的网页版《我的世界》(附代码下载链接)
前端·python·html