python爬虫(十一)爬取贴吧图片

爬取贴吧图片

需求

打开百度贴吧,找到图片吧,找到每日一图,有577张图片。
在网页中图片是以二进制的形式存在的,我们要先拿到图片的url地址,去发起请求,以二进制保存到本地。

页面分析

光标在任意一张图片处,点右键,检查,光标会定位到图片所在的位置,复制里面的url,去浏览器中可以打开这张图片,但是图片的url值能并非在网页源码中,直接向这个url发起请求并不能得到想要的数据,这时候就需要分析数据接口,去查找数据
点击右键,检查,点击XHR,找到左侧 “list?kw=”的文件,依次点开preview --> data --> pic_list,可以看到下面有一系列的标签内容。

在这里插入图片描述
点开其中一个标签,可以看到有两个url地址,复制在网页中打开,第一个地址显示的是像素比较小的图片,第二个地址显示的图片像素相对较高。
在这里插入图片描述
在headers里找到url,复制到浏览器中打开,出现的格式很乱,可以装一下 “JSONView-for-Chrome-master”,辅助查看代码。
安装步骤:浏览器右上角三个点,扩展,把"JSONView-for-Chrome-master"文件夹下的"WebContent"文件拖到浏览器中,重启浏览器就可以了。
在这里插入图片描述
这时,再打开刚复制的url,就会以清晰的网页结构形式显示出网页代码,格式比较清晰,方便做数据分析。可以看到整个代码是字典结构。
在这里插入图片描述
我们可以看到需要的图片url地址,所以需要向headers里面的url发起请求就可以获得图片的信息。
在这里插入图片描述

总结:
通过分析 我们发现源码中并没有我们想要的数据,通过network 找到了真正的数据接口,要对字典格式的数据进行提取
访问的url:https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E5%9B%BE%E7%89%87&alt=jview&rn=200&tid=1433290932&pn=1&ps=1&pe=40&info=1&_=1629980362729

代码实现

import requests
import pprint
import json
import re

url = 'https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E5%9B%BE%E7%89%87&alt=jview&rn=200&tid=1433290932&pn=1&ps=1&pe=40&info=1&_=1629980362729'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.62'
    }
res = requests.get(url, headers=headers)
"""得到json数据一般有两种方式"""
# 第一种,用requests模块提供的得到json数据的方式

# print(res.json())  # 页面分析的时候网页源码是字典格式的,用json打印字典格式
# pprint.pprint(res.json())  # 打印json格式,层级关系很清晰的字典格式
# pprint.pprint(res.json()['data']['pic_list'])  #字典格式从key值为data开始,下一级key值为pic_list,逐级提取value值
# 得到是列表,每一个图片都以字典的格式存放,遍历取出每一个图片
# pic_list = res.json()['data']['pic_list']
# for pic in pic_list:  # 遍历出每一个图片,利用key值找出单个图片的url
#     print(pic['purl'])
    # print('*'*50)

# 第二种方法,需要导入python内置的json模块 import json
# 传入的是字符串,把字符串转为字典格式
# text获取响应对象里面的文本内容,res.text得到的是字符串
# content直接抓取获得的内容,对内容不做任何处理,res.content.decode()
# html = json.loads(res.text)
# pprint.pprint(html)  #字典格式从key值为data开始,下一级key值为pic_list
# 得到是列表,每一个图片都以字典的格式存放,遍历取出每一个图片
# pic_list = html['data']['pic_list']
# for pic in pic_list:  # 遍历出每一个图片,利用key值找出单个图片的url
#     print(pic['purl'])
#     # print('*'*50)

"""用正则同样可以提取数据"""
html = res.text
# print(html)
# 相当于findall(返回的是列表)
# 把需要匹配的图片地址用(.*?)代替,
# ?P<img_url>把标签重命名为img_url,match,find都可以用,但是findall不能用
result = re.finditer(r'"purl":"(?P<img_url>.*?)"', html, re.S)
# print(result)
"""以上的操作都是提取出图片的url值,下面的操作是对获取的url发起请求,把图片保存到本地"""
name = 1
for i in result:
    # print(i.groupdict())  # key是重命名的名字,value是取得的图片地址
    # print(i.groupdict()['img_url'])  # 方式一:通过key值取出value
    # print(i.group('img_url'))  # 方式二:直接获取
    img_down_url = i.group('img_url') # 图片的url
    # 在当前文件夹下创建img文件夹用于存放图片,用+1的方式存储图片名字,在循环前定义保存图片的name = 1
    filename = './img/{}.jpg'.format(name)  # 定义文件名
    # 向图片的url地址发起请求
    respons = requests.get(img_down_url)
    # wb以二进制的形式写入图片,视频,音频
    print('正在写入第%d张图片' % name)
    with open(filename,'wb') as f:
        # 用content获取图片,视频,音频
        f.write(respons.content)
    name += 1

程序完成之后,发现贴吧里面有500多张图片,而只写入了40张,回到网页 --> 检查 --> Network --> Preview --> data --> pic_list 中可以看到,里面存在的数据就只有40张,此时鼠标放到网页滑轮向下滚动,会发现XHR 左侧"名称"下会逐渐的多出来<list?kw类似的文件,划到最底部,会多出现4个<list?kw类似的文件,这就是懒加载的方式,用户没有需求,数据不会主动加载出来,对比一下几个<list?kw文件里的url

第一个url
https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E5%9B%BE%E7%89%87&alt=jview&rn=200&tid=1433290932&pn=1&ps=1&pe=40&info=1&_=1629980362729
第二个url
https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E5%9B%BE%E7%89%87&alt=jview&rn=200&tid=1433290932&pn=1&ps=41&pe=80&wall_type=h&_=1629988753220
第三个url
https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E5%9B%BE%E7%89%87&alt=jview&rn=200&tid=1433290932&pn=1&ps=81&pe=120&wall_type=h&_=1629988763909
第四个url
https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E5%9B%BE%E7%89%87&alt=jview&rn=200&tid=1433290932&pn=1&ps=121&pe=160&wall_type=h&_=1629988858216
第五个url
https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E5%9B%BE%E7%89%87&alt=jview&rn=200&tid=1433290932&pn=1&ps=161&pe=200&wall_type=h&_=1629988863546
可以看一下规律
pn  ps  pe
1   1   40
1   41  80
1   81  120
1   121 160
1   161 200
其中pn=1代表的是第一页,横向ps与pe相差39,纵向ps,pe相差40
for m in range(1, 162, 40):
    # print(m) # 先获取到i的值,也就是ps的值
    print(m, m+39)  # 用ps的值加上39 得到pe的值

此时就要对url进行替换,这是name定义要放在这个循环上面,否则会被重复覆盖。

name = 1
for m in range(1, 162, 40):
    time.sleep(3)
    url = 'https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E5%9B%BE%E7%89%87&alt=jview&rn=200&tid=1433290932&pn=1&ps={}&pe={}&info=1&_=1629980362729'.format(m, m+39)

注意,下面的代码都是在for循环下的,都要统一的进行缩进,此时得到的结果只有200张图片,回到网页看一下,577张图片存放在3页,所以还要有一个翻页操作,仔细看一下后两页的url,跟第一页的几乎一样,不同点在于第一页pn=1,第二页pn=2,第三页pn=3,所以对pn进行一个循环就可以了实现翻页了。

name = 1
for n in range(1, 4):
    time.sleep(3)
    for m in range(1, 162, 40):
        time.sleep(3)
        url = 'https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E5%9B%BE%E7%89%87&alt=jview&rn=200&tid=1433290932&pn={}&ps={}&pe={}&info=1&_=1629980362729'.format(n, m, m+39)

这样的话就把网页中的577张图片都爬取下来了。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值