爬虫 — Xpath 数据解析

news/2024/7/19 12:40:35 标签: 爬虫, python

目录

  • 一、介绍
  • 二、使用
  • 三、语法
    • 1、//
    • 2、/
    • 3、@
    • 4、/text
    • 5、[]、[@]
  • 四、练习
    • 1、元组写入
    • 2、对象写入
  • 五、豆瓣电影信息爬取

一、介绍

XPath(XML Path Language)是一种 XML 的查询语言,它能在 XML 树状结构中寻找节点。XPath 用于在 XML 文档中通过元素和属性进行导航

XML 是一种标记语法的文本格式,XPath 可以方便的定位 XML 中的元素和其中的属性值。

lxml 是 Python 中的一个第三方模块,包含了将 HTML 文本转换成 XML 对象和对对象执行 XPath 的功能。

二、使用

1、在终端输入命令:pip install lxml

2、导入:from lxml import etree

3、创建对象:tree = etree.HTML(网页源代码)

4、tree.xpath(XPath 语法)

三、语法

表达式描述
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
/从根节点选取,选择当前元素的下一级
@选取属性
/text当前元素的文本内容
[]、[@]指定元素的索引或者属性特性

网页数据

python">html = '''
<li>
    <div class="item">
        <div class="pic">
            <em class="">1</em>
            <a href="https://movie.douban.com/subject/1292052/">
                <img width="100" alt="肖申克的救赎" src="https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" class="">
            </a>
        </div>
        <div class="info">
            <div class="hd">
                <a href="https://movie.douban.com/subject/1292052/" class="">
                    <span>肖申克的救赎</span>
                    <span>&nbsp;/&nbsp;The Shawshank Redemption</span>
                    <span>&nbsp;/&nbsp;月黑高飞(港)  /  刺激1995(台)</span>
                </a>
                <span class="playable">[可播放]</span>
            </div>
            <div class="bd">
                <p class="">
                    导演: 弗兰克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演: 蒂姆·罗宾斯 Tim Robbins /...<br>
                    1994&nbsp;/&nbsp;美国&nbsp;/&nbsp;犯罪 剧情
                </p>                       
                <div class="star">
                        <span class="rating5-t"></span>
                        <span class="rating_num" property="v:average">9.7</span>
                        <span property="v:best" content="10.0"></span>
                        <span>2833257人评价</span>
                </div>
                <p class="quote">
                    <span class="inq">希望让人自由。</span>
                </p>
            </div>
        </div>
    </div>
</li>
'''
python"># 创建对象,参数是指网页源码
tree = etree.HTML(html)

1、//

从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。

python"># //:不需要考虑标签位置,直接定位
# 获取 span 标签
span = tree.xpath('//span')  # 返回的是列表,查找所有的 span 标签,并存放到列表当中
print(span)
# 返回值
# [<Element span at 0x2b5be217ec8>, <Element span at 0x2b5be217e88>, <Element span at 0x2b5be217f88>, <Element span at 0x2b5be217fc8>, <Element span at 0x2b5be22e048>, <Element span at 0x2b5be22e0c8>, <Element span at 0x2b5be22e108>, <Element span at 0x2b5be22e148>, <Element span at 0x2b5be22e188>]

# 获取 img 标签
img = tree.xpath('//img')
print(img)
# 返回值
# [<Element img at 0x188dab57ec8>]

2、/

从根节点选取,选择当前元素的下一级。

python"># /:从根节点选取,选择当前元素的下一级
# 获取 p 标签下的 span 标签
span = tree.xpath('//p/span')
print(span)
# 返回值
# [<Element span at 0x28404367f08>]

3、@

选取属性。

python"># @:选取属性
# 获取 img 标签的 src 属性值
img_url = tree.xpath('//img/@src')
print(img_url)
# 返回值
# ['https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp']

# 获取 img 标签的 alt 属性值
img_title = tree.xpath('//img/@alt')
print(img_title)
# 返回值
# ['肖申克的救赎']

4、/text

当前元素的文本内容。

python"># 获取标签里面的文本内容
rank = tree.xpath('//em/text()')
print(rank)
# 返回值
# ['1']

# 获取 class 为 rating_num 标签的内容
span = tree.xpath('//span[@class="rating_num"]/text()')
print(span)
# 返回值
# ['9.7']

5、[]、[@]

指定元素的索引或者属性特性。

python">title = tree.xpath('//div[@class="hd"]/a/span[3]/text()')
print(title)
# 返回值
# ['\xa0/\xa0月黑高飞(港)  /  刺激1995(台)']

四、练习

1、元组写入

python"># 导入模块
import csv
from lxml import etree

# 数据
wb_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 = etree.HTML(wb_data)

# 找到所有的标签,并且存放在列表当中
lis = html.xpath('//li')

# 创建列表
lst = []

# 循环获取 li
for li in lis:
    # 链接
    href = li.xpath('./a/@href')[0]  # .代表当前节点的下一级
    # 标题
    texts = li.xpath('./a/text()')[0]
    # 创建元组数据
    tu = (href, texts)
    # 在列表里添加元组数据
    lst.append(tu)
# 打印列表
print(lst)

# 创建表头
head = ('链接', '值')

# 创建文件对象
with open('data1.csv', 'w', encoding='utf-8-sig', newline='') as f:
    # 创建 csv 写入对象
    writer = csv.writer(f)
    # 写入表头
    writer.writerow(head)
    # 写入数据
    writer.writerows(lst)

2、对象写入

python"># 导入模块
import csv
from lxml import etree

# 数据
wb_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 = etree.HTML(wb_data)

# 找到所有的标签,并且存放在列表当中
lis = html.xpath('//li')

# 创建列表
lst = []

# 循环获取 li
for li in lis:
    # 创建字典对象
    dic = {}
    dic['href'] = li.xpath('./a/@href')[0]  # .代表当前节点的下一级
    dic['texts'] = li.xpath('./a/text()')[0]
    lst.append(dic)

# 打印列表
print(lst)

# 创建表头,key 必须要跟表头保持一致
head = ('href', 'texts')

# 创建文件对象
with open('data2.csv', 'w', encoding='utf-8-sig', newline='') as f:
    # 创建 csv 字典写入对象  fieldnames 固定参数,不可修改
    writer = csv.DictWriter(f, fieldnames=head)  # 设置表头
    # 写入表头
    writer.writeheader()
    # 写入数据
    writer.writerows(lst)

元组写入和对象写入区别:

元组写入:可以自定义表头文字。

对象写入:表头数据必须与对象 key 值保持一致。

五、豆瓣电影信息爬取

目标网站:https://movie.douban.com/top250

需求:获取该网站所有的电影(包括翻页)标题,副标题,电影类型,评分,引言并将数据保存到 csv 表格当中。

页面分析

翻页爬取:先获取第一页数据

1、确定 url:https://movie.douban.com/top250

2、发请求,获取响应:返回网页源代码 — XPath 解析

3、每一组数据 <div class="info"></div> 包含了所需的数据

4、遍历拿详情的数据

电影名称:div[@class=“hd”]/a//text() a 标签下的子孙文本都能获取到

电影类型:div[@class=“bd”]/p/text() 获取到文本内容之后还需要处理

电影评分:div[@class=“bd”]/div[@class=“star”]/span[2]/text()

电影引言:div[@class=“bd”]/p[@class=“quote”]/span/text()

代码实现

python"># 导入模块
import requests
from lxml import etree

# 第一页目标 url
url = "https://movie.douban.com/top250"

# 请求头
head = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'
}

# 发请求,获取响应
res = requests.get(url, headers=head)

# 创建对象
html = etree.HTML(res.text)

# 数据解析
divs = html.xpath('//div[@class="info"]')

# 循环遍历拿到每一组数据
for div in divs:  # 每一组数据的获取
    # 标题
    title = div.xpath('./div[@class="hd"]/a//text()')
    titls = ''.join(title).replace(' ', '').replace('\n', '')
    # 电影类型
    types = div.xpath('./div[@class="bd"]/p/text()')[1].split('/')[-1].strip()
    # 电影评分
    star = div.xpath('./div[@class="bd"]/div[@class="star"]/span[2]/text()')[0]
    # 引言,没有获取到数据,返回是一个空列表
    quote = div.xpath('./div[@class="bd"]/p[@class="quote"]/span/text()')
    # 打印标题,电影类型,电影评分,引言
    print(titls, types, star, quote)

页面分析

翻页

第一页:https://movie.douban.com/top250?start=0&filter=

第二页:https://movie.douban.com/top250?start=25&filter=

第三页:https://movie.douban.com/top250?start=50&filter=

start 参数发生变化

第一页:(1-1)* 25 = 0

第二页:(2-1)* 25 = 25

第三页:(3-1)* 25 = 50

第 n 页:(n-1)* 25

page:(page-1) * 25

f’https://movie.douban.com/top250?start={(page-1) * 25}&filter=’

代码实现

python"># 导入模块
import requests
from lxml import etree

# 请求头
head = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'
}

# 翻页
for page in range(1, 11):
    # 目标 url
    url = f'https://movie.douban.com/top250?start={(page-1) * 25}&filter='

    # 发请求,获取响应
    res = requests.get(url, headers=head)

    # 创建对象
    html = etree.HTML(res.text)

    # 数据解析
    divs = html.xpath('//div[@class="info"]')

    # 循环遍历拿到每一组数据
    for div in divs:  # 每一组数据的获取
        # 标题
        title = div.xpath('./div[@class="hd"]/a//text()')
        titls = ''.join(title).replace(' ', '').replace('\n', '')
        # 电影类型
        types = div.xpath('./div[@class="bd"]/p/text()')[1].split('/')[-1].strip()
        # 电影评分
        star = div.xpath('./div[@class="bd"]/div[@class="star"]/span[2]/text()')[0]
        # 引言,没有获取到数据,返回是一个空列表
        quote = div.xpath('./div[@class="bd"]/p[@class="quote"]/span/text()')
        # 判断是否为空列表
        if quote: # 如果不是就直接取下标值
            quote = quote[0]
        else: # 如果是的,就赋值为空字符串
            quote = ''
        # 打印标题,电影类型,电影评分,引言
        print(titls, types, star, quote)

页面分析

数据已经全部取出

使用 csv 保存数据到表格

代码实现

1、元组写入

python"># 导入模块
import requests
from lxml import etree
import csv

# 请求头
head = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'
}

# 数据列表
lst = []

# 翻页
for page in range(1, 11):
    # 目标 url
    url = f'https://movie.douban.com/top250?start={(page-1) * 25}&filter='

    # 发请求,获取响应
    res = requests.get(url, headers=head)

    # 创建对象
    html = etree.HTML(res.text)

    # 数据解析
    divs = html.xpath('//div[@class="info"]')

    # 循环遍历拿到每一组数据
    for div in divs:  # 每一组数据的获取
        # 标题
        title = div.xpath('./div[@class="hd"]/a//text()')
        titls = ''.join(title).replace(' ', '').replace('\n', '')
        # 电影类型
        types = div.xpath('./div[@class="bd"]/p/text()')[1].split('/')[-1].strip()
        # 电影评分
        star = div.xpath('./div[@class="bd"]/div[@class="star"]/span[2]/text()')[0]
        # 引言,没有获取到数据,返回是一个空列表
        quote = div.xpath('./div[@class="bd"]/p[@class="quote"]/span/text()')
        # 判断是否为空列表
        if quote: # 如果不是就直接取下标值
            quote = quote[0]
        else: # 如果是的,就赋值为空字符串
            quote = ''
        # 标题,电影类型,电影评分,引言组成元组数据
        l = (titls, types, star, quote)
        # 在列表数据中增加元组数据
        lst.append(l)

# 设置表头
head = ('标题', '电影类型', '电影评分', '引言')

# 创建文件对象
with open('douban.csv','w',encoding='utf-8-sig',newline='') as f:
    # 创建 csv 写入对象
    writer = csv.writer(f)
    # 写入表头
    writer.writerow(head)
    # 写入数据
    writer.writerows(lst)

2、对象写入

python"># 导入模块
import requests
from lxml import etree
import csv

# 请求头
head = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'
}

# 数据列表
lst = []

# 翻页
for page in range(1, 11):
    # 目标 url
    url = f'https://movie.douban.com/top250?start={(page-1) * 25}&filter='

    # 发请求,获取响应
    res = requests.get(url, headers=head)

    # 创建对象
    html = etree.HTML(res.text)

    # 数据解析
    divs = html.xpath('//div[@class="info"]')

    # 循环遍历拿到每一组数据
    for div in divs:  # 每一组数据的获取
        # 创建对象
        dic = {}
        # 标题
        title = div.xpath('./div[@class="hd"]/a//text()')
        dic['titls'] = ''.join(title).replace(' ', '').replace('\n', '')
        # 电影类型
        dic['types'] = div.xpath('./div[@class="bd"]/p/text()')[1].split('/')[-1].strip()
        # 电影评分
        dic['star'] = div.xpath('./div[@class="bd"]/div[@class="star"]/span[2]/text()')[0]
        # 引言,没有获取到数据,返回是一个空列表
        quote = div.xpath('./div[@class="bd"]/p[@class="quote"]/span/text()')
        # 判断是否为空列表
        if quote: # 如果不是就直接取下标值
            dic['quote'] = quote[0]
        else: # 如果是的,就赋值为空字符串
            dic['quote'] = ''
        # 在列表数据中增加对象数据
        lst.append(dic)

# 设置表头,与对象中的 key 值相同
head = ('titls', 'types', 'star', 'quote')

# 创建文件对象
with open('douban.csv','w',encoding='utf-8-sig',newline='') as f:
    # 创建 csv 写入对象
    writer = csv.DictWriter(f, fieldnames=head)
    # 写入表头
    writer.writeheader()
    # 写入数据
    writer.writerows(lst)

记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~


http://www.niftyadmin.cn/n/5028299.html

相关文章

#循循渐进学51单片机#如何学习单片机#not.1

1、了解普通发光二极管的参数&#xff0c;掌握限流电阻的计算方法。 1&#xff09; LED小灯靠电流点亮&#xff0c;电压1.8v~2.2v&#xff0c;电流是1~20ma&#xff0c;在1~5ma亮度有所变化&#xff0c;5MA以上亮度不变。 2&#xff09; 限流电阻的算法一般采用欧姆定律计算。…

SRT一个简单的客户端和服务端

1.客户端 支持将UDP数据流接收后进行SRT流的推送&#xff0c;也支持从服务端拉取SRT流&#xff0c;同时支持SRT会话模式的测试。项目依赖于msprotocol: 一个轻量级的网络协议&#xff0c;扩展方便使用简单。可应用于X86和ARM64嵌入式设备&#xff0c;目前已支持file,hls,http,r…

偶现来电时手机操作出现重启

问题描述&#xff1a;偶现来电时手机操作出现重启 问题分析&#xff1a;从系统Log看 09-06 10:22:44.791829 1400 1425 W Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: Blocked in handler on main thread (main) 09-06 10:22:44.794133 1400 1425 W Watchdog: main …

SpringMVC之自定义注解

目录 一.JAVA注解简介 1.1.Java注解分类 1.2.JDK元注解 二.自定义注解 1.1.如何自定义注解 1.2.自定义注解的基本案例 1.2.1.案例一&#xff08;获取类与方法上的注解值&#xff09; 1.2.2.案例二&#xff08;获取类属性上的注解属性值&#xff09; 1.2.3. 案例三&#xff…

错误码:spark_error_00000004

错误码&#xff1a;spark_error_00000004 错误码&#xff1a;spark_error_00000004 问题原因&#xff1a;这个报错与Spark执行器&#xff08;executor&#xff09;的内存不足有关&#xff0c;程序运行时所需内存 > memory。一般是因为处理数据量或者缓存的数据量较大&#x…

Godot 和 VScode配置C#环境注意事项

前言 尽管有些博主会建议如果我们熟悉C#的话&#xff0c;最好还是使用GDscript&#xff0c;而且对于小白上手也相对简单&#xff0c;但是C#的性能终究还是比动态语言好&#xff0c;也相比CPP简单些&#xff0c;尽管现在Godot还是有些问题&#xff0c;比如不像unity那样适配swit…

leetcode做题笔记141. 环形链表

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;…

深度学习的三维重建 论文+源码+解析+译文+批注 MVSNet系列最新顶刊总结 下载

文章目录 1 内容展示2 资源下载3 MVSNet系列最新顶刊 总结笔记4 MVSNet系列最新顶刊 对比总结笔记 Word版下载1 内容展示 深度学习的三维重建 最具代表性的论文+源码+解析+译文+批注 整理集合 下载 本文总结的顶刊主要有: MVSNet(CVPR-2018),RMVSNet(CVPR2019),PointMVSNe…