Python学习从0开始——项目一day01爬虫(二)

Python学习从0开始——项目一day01爬虫`(二)`

  • 一、解析response数据
  • 二、json转换
  • 三、文件保存
  • 四、存储json对象
  • 五、完整代码

上一篇

一、解析response数据

在已经知道我们获取图片的最终URL存在于请求响应response中,下一步的重点就放在解析response。
首先给出现在的代码,以下代码暂时删除了图片写入的部分,在文章末尾会给出完整的爬虫代码。

#coding=utf-8
#!/usr/bin/python
# 导入requests库
import requests
# 导入文件操作库
import os
import bs4
from bs4 import BeautifulSoup
import sys
import importlib
importlib.reload(sys)
import re 
import json  
import urllib.parse# 给请求指定一个请求头来模拟chrome浏览器
global headers
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'}
# 爬图地址
mziTu = 'https://image.baidu.com/'
# 定义存储位置
global save_path
save_path ='./picture'# 创建文件夹
def createFile(file_path):if os.path.exists(file_path) is False:os.makedirs(file_path)# 切换路径至上面创建的文件夹os.chdir(file_path)# 下载文件
def download(page_no, file_path):global headersres_sub = requests.get(page_no, headers=headers)# 解析htmlsoup_sub = BeautifulSoup(res_sub.text, 'html.parser')# 获取页面的栏目地址all_a = soup_sub.find('div',id='bd-home-content-album').find_all('a',target='_blank')count = 0for a in all_a:count = count + 1if (count % 2) == 0:print("内页第几页:" + str(count))# 提取hrefhref = a.attrs['href']print("套图地址:" + href)res_sub_1 = requests.get(href, headers=headers)soup_sub_1 = BeautifulSoup(res_sub_1.text, 'html.parser')# 主方法
def main():res = requests.get(mziTu, headers=headers)# 使用自带的html.parser解析soup = BeautifulSoup(res.text, 'html.parser')# 创建文件夹createFile(save_path)file = save_pathcreateFile(file)print("开始执行")download(mziTu, file)if __name__ == '__main__':main()

在这里插入图片描述
在谷歌浏览器中,折叠代码块,快速定位到我们需要的<script>中,第十三个<script>是linkData所在标签,然后对代码继续修改,在53行添加如下内容:

			# 找到所有的<script>标签scripts = soup_sub_1.find_all('script')  # 第十三个是linkData所在标签script_content = BeautifulSoup(scripts[12].text, 'html.parser').text#打印值print(script_content)
#终端输出如下
!function(){    window.logid = "7865333382831002903";require.async(['albumsdetail:widget/ui/app/app'], function (app) {app.setPageInfo({word: '%E6%B8%90%E5%8F%98%E9%A3%8E%E6%A0%BC%E6%8F%92%E7%94%BB',hasResult: '1',albumTab: '%E8%AE%BE%E8%AE%A1%E7%B4%A0%E6%9D%90',setId: '409',title: '渐变风格插画',logo: 'https:\/\/emoji.cdn.bcebos.com\/yunque\/pc_vcg.png',coverUrl: 'https:\/\/t7.baidu.com\/it\/u=1819248061,230866778&fm=193&f=GIF',totalNum: '314',albumLinkRn: '30',linkData: '[{\x22pid\x22:144520,\x22width\x22:1200,\x22height\x22:562,\x22oriwidth\x22:1200,\x22oriheight\x22:562,\x22thumbnailUrl\x22:\x22https:\\\/\\\/t7.baidu.com\\\/it\\\/u=1819248061,230866778&fm=193&f=GIF\x22,\x22fromUrl\x22:\x22https:\\\/\\\/www.vcg.com\\\/creative\\\/1274231988\x22,\x22contSign\x22:\x221819248061,230866778\x22},{\x22pid\x22:144521,\x22width\x22:562,\x22height\x22:1000,\x22oriwidth\x22:562,\x22oriheight\x22:1000,\x22thumbnailUrl\x22:\x22https:\\\/\\\/t7.baidu.com\\\/it\\\/u=4036010509,3445021118&fm=193&f=GIF\x22,\x22fromUrl\x22:\x22https:\\\/\\\/www.vcg.com\\\/creative\\\/1147957933\x22,\x22contSign\x22:\x224036010509,3445021118\x22},……]

经过以上操作,成功的获取了linkData所在的<script>,下一步是获取linkData,我们通过正则来获取数据:

			# 使用正则表达式来查找linkData的值  link_data_pattern = r"linkData: '([^']*)'"  match = re.search(link_data_pattern, script_content)#查看输出print(match)   
#终端输入
python3 spider.py
#终端输出
<re.Match object; span=(605, 10524), match="linkData: '[{\\x22pid\\x22:144520,\\x22width\\x22>

这看起来并不符合我们的预期,我们期望的输出是linkData里的值。
这时,我们需要关注re.search(),其返回结果是一个捕获组,可以通过group()来获取每一组的数据,group(1) 表示获取第一个捕获组的内容。如果没有捕获组或者索引超出了捕获组的范围,group() 方法会抛出 IndexError 异常。
将输出替换为以下内容:

            print(match.group(1))     
#终端输入
python3 spider.py
#捕获组终端输出
[{\x22pid\x22:144520,\x22width\x22:1200,\x22height\x22:562,\x22oriwidth\x22:1200,\x22oriheight\x22:562,\x22thumbnailUrl\x22:\x22https:\\\/\\\/t7.baidu.com\\\/it\\\/u=1819248061,230866778&fm=193&f=GIF\x22,\x22fromUrl\x22:\x22https:\\\/\\\/www.vcg.com\\\/creative\\\/1274231988\x22,\x22contSign\x22:\x221819248061,230866778\x22},^}

下一步需要将捕获组的内容转为我们可以使用的数据。

二、json转换

为什么要将捕获组转换成json数据,什么情况下需要我们转为json数据?
看上方的捕获组输出,我们能明显的识别出这些数据具有统一的属性,直接截取字符串需要经过多次split或者replace,如果通过属性去获取值,会很便于我们操作。

#继续添加如下内容if match:  # 获取第一个捕获组的内容encoded_link_data = match.group(1)print(encoded_link_data) # 解析JSON对象  link_data_list = json.loads(encoded_link_data)  else:  print("未能找到linkData的值")

继续执行代码:

#终端输入
python3 spider.py
#终端输出
Traceback (most recent call last):File "/root/Python_02/Python/Day01/learn/spider.py", line 98, in <module>main()File "/root/Python_02/Python/Day01/learn/spider.py", line 95, in maindownload(mziTu, file)File "/root/Python_02/Python/Day01/learn/spider.py", line 70, in downloadlink_data_list = json.loads(encoded_link_data)  File "/usr/lib/python3.9/json/__init__.py", line 346, in loadsreturn _default_decoder.decode(s)File "/usr/lib/python3.9/json/decoder.py", line 337, in decodeobj, end = self.raw_decode(s, idx=_w(s, 0).end())File "/usr/lib/python3.9/json/decoder.py", line 353, in raw_decodeobj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 3 (char 2)

根据提示,我们知道现在无法解析为json数据。我们来看一下json的示例数据格式:

[{"name":"a","age":1
},{"name":"b","age":2
}]

显而易见,问题出在双引号上,那么下一步就需要将’\x22’字串替换为双引号。

#修改赋值
encoded_link_data = match.group(1).replace('\x22', '"')

此时,我们会发现,经过替换后仍旧报相同的错误,而且终端的输出的encoded_link_data 值和替换前没有区别。
为什么呢?
再来观察’\x22’,我们能发现它是一个转义序列,用于表示一个ASCII值为0x22的字符,即双引号,Python会通过转义序列将其解释为双引号,这就造成实际上是双引号替换双引号,故输出不变。而我们并不需要这种转义,我们需要Python将其解释为普通的字符串。

				#修改赋值,同时替换双引号和斜杠的转义 encoded_link_data = match.group(1).replace(r'\x22', '"').replace(r'\\\/', '/')#encoded_link_data = match.group(1).replace('\x22', '"')print(encoded_link_data) # 解析JSON对象  link_data_list = json.loads(encoded_link_data)  
#终端输入
cd Python/Day01/learn/
python3 spider.py
#输出,数据正常
[{"pid":144520,"width":1200,"height":562,"oriwidth":1200,"oriheight":562,"thumbnailUrl":"https://t7.baidu.com/it/u=1819248061,230866778&fm=193&f=GIF","fromUrl":"https://www.vcg.com/creative/1274231988","contSign":"1819248061,230866778"},……]

三、文件保存

link_data_list现在已经存储了json数据,我们通过get方法获取对应的URL值,然后发送请求获取响应,继续添加以下内容:

#添加到if match:  里for item in link_data_list:  # 提取thumbnailUrl字段的值  thumbnail_url = item.get('thumbnailUrl')res_sub_2 = requests.get(thumbnail_url, headers=headers)soup_sub_2 = BeautifulSoup(res_sub_2.text, "html.parser")print("开始提取图片")file_name = thumbnail_urlf = open(file_name, 'ab')f.write(soup_sub_2)f.close()
#终端执行
python3 spider.py
#终端输出
开始提取图片
Traceback (most recent call last):File "/root/Python_02/Python/Day01/learn/spider.py", line 103, in <module>main()File "/root/Python_02/Python/Day01/learn/spider.py", line 100, in maindownload(mziTu, file)File "/root/Python_02/Python/Day01/learn/spider.py", line 79, in downloadf = open(file_name, 'ab')
FileNotFoundError: [Errno 2] No such file or directory: 'https://t7.baidu.com/it/u=1819248061,230866778&fm=193&f=GIF'

使用初始代码的方法行不通,可能是因为没加文件类型,我们做一些小更改:

                    f = open(file_name+'.jpg', 'wb')

还报错,按照文件的输入输出来说我们的操作是正常的,符合流程的,问题会不会还是出现在文件名?
换个名字试一下。

                    f = open('a.jpg', 'ab')
#终端执行
python3 spider.py
#终端输出
Traceback (most recent call last):File "/root/Python_02/Python/Day01/learn/spider.py", line 105, in <module>main()File "/root/Python_02/Python/Day01/learn/spider.py", line 102, in maindownload(mziTu, file)File "/root/Python_02/Python/Day01/learn/spider.py", line 82, in downloadf.write(soup_sub_2)
TypeError: a bytes-like object is required, not 'BeautifulSoup'

虽然还是报错,但是报错内容变了,那现在可以确定,问题出现在文件名,对于Python来说,它本身并不直接限制文件名以"https"开头。但是,当我们试图创建、读取或操作一个文件时,实际上是在与底层的操作系统和文件系统交互。因此,真正限制使用"https"作为文件名开头的因素来自这些底层系统。知道原因后,我们就能解决问题了。
同时根据以上终端输出的内容,可以知道f.write()需要的是字节对象,而不是我们现在赋值的BeautifulSoup类型。继续修改:

            file_name = thumbnail_url.replace(r'https://t7.baidu.com/it/u=','')f = open(file_name+'.jpg', 'ab')f.write(res_sub_2.content)

这次正常执行了,来看一下输出的文件:
在这里插入图片描述

四、存储json对象

 #修改代码#添加行,存储数据,json数据以字符串形式存储,不是二进制    data = open('sava.txt', 'a')     if match:  # 获取第一个捕获组的内容# 提取匹配到的linkData字符串,字符替换时一定要使用r  encoded_link_data = match.group(1).replace(r'\x22', '"').replace(r'\\\/', '/')#encoded_link_data = match.group(1).replace('\x22', '"')#print(encoded_link_data) # 解析JSON对象  link_data_list = json.loads(encoded_link_data)  for item in link_data_list:  # 提取thumbnailUrl字段的值  thumbnail_url = item.get('thumbnailUrl')res_sub_2 = requests.get(thumbnail_url, headers=headers)soup_sub_2 = BeautifulSoup(res_sub_2.text, "html.parser")print("开始提取图片")file_name = thumbnail_url#    f = open(file_name, 'ab')                    #    f = open(file_name+'.jpg', 'ab')#    f = open('a.jpg', 'ab')                file_name = thumbnail_url.replace(r'https://t7.baidu.com/it/u=','')f = open(file_name+'.jpg', 'ab')#    f.write(soup_sub_2)f.write(res_sub_2.content)
#添加,写入,json转字符串写入data.write(json.dumps(item)+'\n')f.close()else:  print("未能找到linkData的值")
#关闭输入data.close()

在这里插入图片描述

至此,完整的一次爬虫结束。

五、完整代码

代码仅供参考学习使用。

#coding=utf-8
#!/usr/bin/python
# 导入requests库
import requests
# 导入文件操作库
import os
import bs4
from bs4 import BeautifulSoup
import sys
import importlib
importlib.reload(sys)
import re 
import json  
import urllib.parse# 给请求指定一个请求头来模拟chrome浏览器
global headers
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'}
# 爬图地址
mziTu = 'https://image.baidu.com/'
# 定义存储位置
global save_path
save_path ='./picture'# 创建文件夹
def createFile(file_path):if os.path.exists(file_path) is False:os.makedirs(file_path)# 切换路径至上面创建的文件夹os.chdir(file_path)# 下载文件
def download(page_no, file_path):global headersres_sub = requests.get(page_no, headers=headers)# 解析htmlsoup_sub = BeautifulSoup(res_sub.text, 'html.parser')# 获取页面的栏目地址all_a = soup_sub.find('div',id='bd-home-content-album').find_all('a',target='_blank')count = 0for a in all_a:count = count + 1if (count % 2) == 0:print("内页第几页:" + str(count))# 提取hrefhref = a.attrs['href']print("套图地址:" + href)res_sub_1 = requests.get(href, headers=headers)soup_sub_1 = BeautifulSoup(res_sub_1.text, 'html.parser')            # 找到所有的<script>标签scripts = soup_sub_1.find_all('script')  # 第十三个是linkData所在标签script_content = BeautifulSoup(scripts[12].text, 'html.parser').text#print(script_content)# 使用正则表达式来查找linkData的值  link_data_pattern = r"linkData: '([^']*)'"  match = re.search(link_data_pattern, script_content) #print(match)   #print(match.group(1))     data = open('sava.txt', 'a')     if match:  # 获取第一个捕获组的内容# 提取匹配到的linkData字符串,字符替换时一定要使用r  encoded_link_data = match.group(1).replace(r'\x22', '"').replace(r'\\\/', '/')#encoded_link_data = match.group(1).replace('\x22', '"')#print(encoded_link_data) # 解析JSON对象  link_data_list = json.loads(encoded_link_data)  for item in link_data_list:  # 提取thumbnailUrl字段的值  thumbnail_url = item.get('thumbnailUrl')res_sub_2 = requests.get(thumbnail_url, headers=headers)soup_sub_2 = BeautifulSoup(res_sub_2.text, "html.parser")print("开始提取图片")file_name = thumbnail_url#    f = open(file_name, 'ab')                    #    f = open(file_name+'.jpg', 'ab')#    f = open('a.jpg', 'ab')                file_name = thumbnail_url.replace(r'https://t7.baidu.com/it/u=','')f = open(file_name+'.jpg', 'ab')#    f.write(soup_sub_2)f.write(res_sub_2.content)data.write(json.dumps(item)+'\n')f.close()else:  print("未能找到linkData的值")data.close()# 主方法
def main():res = requests.get(mziTu, headers=headers)# 使用自带的html.parser解析soup = BeautifulSoup(res.text, 'html.parser')# 创建文件夹createFile(save_path)file = save_pathcreateFile(file)print("开始执行")download(mziTu, file)if __name__ == '__main__':main()

本来打算继续写存入数据库相关内容,但是MySQL服务器启动要会员,就只加了写数据到文件里,后续可以通过文件导入到数据库,线上就算了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/810463.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis-底层数据结构

Redis-底层数据结构 redisObject对象机制对象共享引用计数以及对象的消毁 动态字符串SDS链表链表的优缺点: 压缩链表ziplist的缺点 字典-Dictrehash渐进式rehash 整数集-intSet内存分布图整数集合的升级 跳表 - ZSkipList快表-quicklistlistpack redisObject对象机制 typedef s…

DP10RF001一款200MHz~960MHz 低功耗(G)FSK/OOK无线收发芯片应用无线遥控工控设备无线门禁传感器等

产品概述 DP10RF001是一款工作于200MHz~960MHz范围内的低功耗、高性能、单片集成的(G)FSK/OOK无线收发机芯片。内部集成完整的射频接收机、射频发射机、频率综合器、调制解调器&#xff0c;只需配备简单、低成本的外围器件就可以获得良好的收发性能。芯片支持灵活可设的数据包…

Jmeter从数据为查找结果集数据方法随笔

一、Jmeter连接数据库 1.下载对应数据库的驱动包到jmeter安装目录的lib下ext文件中&#xff0c;并导入到jmeter的测试计划中&#xff0c;本实例中使用的是mysql如下所示&#xff1a; 点击测试计划–>点击浏览–>选中mysql驱动jar包–>打开 2.添加线程组&#xff0c;…

毕设(三)——nb-lot与onenet通信

文章目录 一、前言二、nb-lot与onenet的连接2.1 创建产品2.2 创建设备2.3 连接2.4 发送数据 三、onenet的数据可视化 刚刚看了一个关于nb-lot的视频&#xff0c;我看到up是用onenet原生的GUI就能做到数据的显示&#xff0c;十分亮眼 主要是它能把地图也一起显示出来&#xff0c…

2024mathorcup数学建模思路教学

大家好呀&#xff0c;认证杯数学建模开始了&#xff0c;来说一下选题建议以及思路吧&#xff1a; 首先定下主基调&#xff0c; 本次mathorcup数学应用挑战赛推荐大家选择C题&#xff0c;难度方面&#xff1a;A≈B&#xff1e;D&#xff1e;C。 我们预计4.13日晚上前更新完毕…

Stable Diffusion 本地部署教程:详细步骤与常见问题解析

作为一位热衷于探索前沿AI技术的博主&#xff0c;近期我深度研究了Stable Diffusion模型的本地部署过程。在这篇教程中&#xff0c;我将详述从环境准备到模型运行的每个步骤&#xff0c;并针对常见的部署问题给出解决方案&#xff0c;帮助你顺利在本地开启Stable Diffusion的创…

【图像处理】-小议YUV色彩空间-YUV和RGB格式的来由,相互关系以及转换方式,并对编程实现的YUV转为RGB程序进行介绍

小议YUV色彩空间 摘要: 在视频图像处理等相关相关领域&#xff0c;YUV是一个经常出现的格式。本文主要以图解的资料形式详细描述YUV和RGB格式的来由&#xff0c;相互关系以及转换方式&#xff0c;并对编程实现的YUV转为RGB程序进行介绍。 1 引言 自然界的颜色千变万化&#xff…

【前缀合】Leetcode 和可被 K 整除的子数组

题目解析 974. 和可被 K 整除的子数组 算法讲解 前置知识点&#xff1a; 同余定理&#xff1a;(ab) % c 0 可以得出 a % c b % cC中负数求余的结果是负数&#xff0c;但是本题需要的是正数&#xff0c;所以我们为了修正这个结果&#xff0c;需要进行(负数 % 正数 正数) %…

无法用raven-js,如何直接使用TraceKit标准化错误字符串(一次有趣的探索)

引子&#xff1a;网上三年前&#xff08;2020&#xff09;的文章介绍了一个raven-js 简单说就是把堆栈信息格式化兼容各浏览器&#xff0c;便于查看错误来源。 **but&#xff1a;**到处找了一下raven-js&#xff0c;已经没有官方出处了&#xff0c;只在Sentry的源码仓库里发现…

【数据结构】单链表(二)

目录 1.查找数据 2.指定位置插入和删除节点 2.1 指定位置之前插入节点 2.2 指定位置之后插入节点 2.3 删除指定位置节点 2.4 删除指定位置之后的节点 3.销毁链表 我们接着上一篇【数据结构】单链表&#xff08;一&#xff09;-CSDN博客 来继续实现单链表 1.查找数据 在…

2. 如何让mybatis-plus的逻辑删除注解@TableLogic临时失效

文章目录 如何让mybatis-plus的逻辑删除注解TableLogic临时失效1. 场景复现1.1 controller代码1.2 service层代码1.3 entity代码 2. 问题分析3. 解决方案3.1 说明3.2 核心代码3.3 service方法对应修改为3.4 运行结果 如何让mybatis-plus的逻辑删除注解TableLogic临时失效 1. 场…

【QT教程】QT6 QML界面布局艺术

QT6 QML界面布局艺术 使用AI技术辅助生成 QT界面美化视频课程 QT性能优化视频课程 QT原理与源码分析视频课程 QT QML C扩展开发视频课程 免费QT视频课程 您可以看免费1000个QT技术视频 免费QT视频课程 QT统计图和QT数据可视化视频免费看 免费QT视频课程 QT性能优化视频免费看…

7、configMap

1、configMap是什么 类似与pod的配置中心&#xff0c;不会因为pod的创建销毁&#xff0c;相关配置发生改变 pod定义硬编码意味着需要有效区分⽣产环境与开发过程中的pod 定义。为了能在多个环境下复⽤pod的定义&#xff0c;需要将配置从pod定义描 述中解耦出来。 2、向容器中…

Mongodb入门--头歌实验MongoDB 文档的高级查询操作

数据库存储了大量的数据&#xff0c;当我们需要特定的数据时就要使用查询方法&#xff0c;根据一定的条件&#xff0c;筛选出我们想要的数据&#xff0c;前一章我们简单介绍了条件操作符&#xff08;<、<、>、>、!等&#xff09;&#xff0c;在这一章中我们将更全面…

重生奇迹MU弓箭手装备介绍

重生奇迹MU弓箭手装备搭配什么好呢&#xff1f;装备的搭配对于角色来说帮助很大&#xff0c;所以我们更加要选择合适的装备来搭配。 装备打造 ①装备强化&#xff1a;装备强化需要强化材料 灵魂宝石、祝福宝石、玛雅宝石&#xff0c;强化有几率失败&#xff0c;失败不会导致…

贪心算法|968.监控二叉树

力扣题目链接 class Solution { private:int result;int traversal(TreeNode* cur) {// 空节点&#xff0c;该节点有覆盖if (cur NULL) return 2;int left traversal(cur->left); // 左int right traversal(cur->right); // 右// 情况1// 左右节点都有覆盖if (le…

MM-Grounding-DINO的训练推理(待更新)

1、简单介绍 继前面发布的 GroundingDino 和 Open-GroundingDino的推理 和 Open-GroundingDino的训练实现&#xff0c;作为 GroundingDino延续性的文本检测网络 MM-Grounding-DINO 也发布了较详细的 训练和推理实现教程&#xff0c;而且操作性很强。作为学习内容&#xff0c;也…

IO流【内存流、打印流、随机访问流】;初识网络编程

day37 IO流 继day36 各种流 对象流 day36 内存流 class ByteArrayInputStream – 内存输入流 class ByteArrayOutputStream – 内存输出流 注意&#xff1a; 内存流是程序和内存交互&#xff0c;跟文件无关内存流是程序到内存的通道&#xff0c;是关闭不掉的 应用场景&#x…

深度学习pytorch好用网站分享

深度学习在线实验室Featurizehttps://featurize.cn/而且这个网站里面还有一些学习教程 免费好用 如何使用 PyTorch 进行图像分类https://featurize.cn/notebooks/5a36fa40-490e-4664-bf98-aa5ad7b2fc2f 华为modelArtshttps://bbs.huaweicloud.com/forum/thread-76328-1-1.html…

阿里云飞燕平台搭建与linux程序通信(全图文教程)

阿里云飞燕平台搭建与linux程序通信&#xff08;全图文教程&#xff09; 一、MQTT理论1.1 概念1.2 理解发布和订阅1.3 MQTT传输的消息组成 二、阿里云飞燕平台搭建2.1 产品创建2.2 自定义自己的功能2.3 人机交互 三、测试3.1代码分析3.2 效果验证 一、MQTT理论 1.1 概念 MQTT…