有时候感觉B站视频的封面很好看,想要保存,但在网页中右键→检查,然后定位元素一张一张手动保存很麻烦。这时可以写一个Python爬虫程序进行批量下载


挑一个想要下载的UP主

我来随便选一个,嘿嘿就她了漫罗拉,来到她的首页,首页的网址最后的数字314480501是UP主的UID,这是个重要参数,后面会用到。点击投稿栏目会看到所有的视频。


定位我们需要的请求地址

我们需要的地址就是浏览器地址栏上这个简单的地址吗?https://space.bilibili.com/314480501/video,右键检查找到这个请求,看看返回了什么,在返回的html里搜索几个视频标题,搜索不到标题。

这说明这些视频信息可能是是动态加载的,我们把筛选切换到Fetch/XHR重新查看这些过滤后的请求。经过一番检查发现有一个search?开头的请求是我们要找的,请求地址是https://api.bilibili.com/x/space/arc/search?mid=314480501&ps=30&tid=0&pn=1&keyword=&order=pubdate&jsonp=jsonp。返回的结果是一个json,里面有视频封面地址,标题等等信息。请求里有几个用到的参数,mid=314480501是UP主的UID,pn=1是页数,第几页。在json里有几个字段可能会用到authorUP主名字,bvid视频的BV号,pic视频的封面地址,count视频总数,count/30+1count/30+1就是总页数了


Python爬虫程序

先发一次请求拿到count视频总数,计算还有几页,保存第一次的所有图片地址,再发请求拿到剩下的图片地址,最后遍历所有图片地址进行下载,保存到本地文件夹里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import requests
import json
import os
from time import sleep, time
if __name__=="__main__":
start=time()
header={
'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36'
} #请求头,假装浏览器发起请求
UP_id='314480501'#漫罗拉314480501
urls='https://api.bilibili.com/x/space/arc/search?mid=%s&ps=30&tid=0&pn=1&keyword=&order=pubdate&jsonp=jsonp'%UP_id #请求地址,要传UP主ID进来
page=requests.get(url=urls,headers=header,timeout=(5,5)).json()

page_info=page['data']
fenye=page_info['page']
total=fenye['count'] #视频总数
size=fenye['ps']
fenlei=page_info['list']['tlist']
videos=page_info['list']['vlist'] #图片地址和BV号都在这个字段里
author=videos[0]['author']#作者
folder='./'+author
page_max=total//size+1 #总页数
if(not os.path.exists(folder)):
os.mkdir(folder) #创建文件夹
img_list=[] #图片地址列表

for i in videos:
img_list.append((i['pic'],i['bvid'])) #保存图片地址


for page_index in range(2,page_max+1): #获取剩下的图片地址
urls='https://api.bilibili.com/x/space/arc/search?mid=%s&ps=30&tid=0&pn=%d&keyword=&order=pubdate&jsonp=jsonp'%(UP_id,page_index)
page=requests.get(url=urls,headers=header,timeout=(5,5)).json()
page_info=page['data']
videos=page_info['list']['vlist']
for i in videos:
img_list.append((i['pic'],i['bvid']))


cnt=0
for i in img_list: #遍历地址列表
pic_url,name=i
pic_data=requests.get(url=pic_url,headers=header,timeout=(5,5)).content
with open(folder+'/'+name,'wb') as fp:
fp.write(pic_data) #保存图片
cnt+=1
print('%s %d'%(name,cnt),' 爬取结束') #打印BV号和计数
time_use=time()-start
print('%s 共%d张'%(author,total))
print('实际爬取 %d 张'%cnt)
print('用时: %.2fs'%time_use)
print(len(img_list))

大功告成

运行一下看看结果,133张,完美。程序写得不好见谅。如果运行提示超时,等一会儿重试即可。