一次完整的对bilibili数据爬取的过程
Kale

寒假在学机器学习,晚上突然想起以前看过的一个很喜欢的up主的视频,讲的是爬取B站的数据,然后用机器学习方法进行建立模型以推断点赞投币等维度的权重,一想,爬虫我会啊,机器学习也正在学,刚好练练手,虽然轮子很多,但还是自己造比较有意思(本来晚上准备深入理解svm的,时间又花在这上面了…).

数据选择

随便打开B站的一个视频,可以看到播放,弹幕,点赞,投币,收藏,转发,评论七个属性,而如果要建立模型,除了输入的x之外还需要对应的结果y,即视频的综合得分,综合得分可以在排行榜里面看到,排行榜有12个方面,动画,国创相关,音乐等等,每个榜单100个视频.接下来思路有了,只要获取12个排行榜上每个视频的播放,点赞等属性,记录下来,然后进行数据分析就好了.

数据爬取

思路很清晰,但是实现起来却遇到了很多苦难,首先遇到一个问题,在排行榜上有播放量和弹幕(猜的)以及得分三个数值可以看,但是点进视频后,却发现播放量和弹幕的数值不一致,后来才发现是排行榜每天只更新一次,而点击如视频后,视频的数据却是实时更新的,所以造成了数值上的差异.

这里我要爬取的数据是1200个,先将这些样本的av号存到列表中,这一步很简单,也没遇到什么问题,这里为了更好地提取想要的数据用到了BeautifulSoup工具.另外感叹一下我的正则表达式实在是太菜了,以后找时间再深入学习吧.

接下来就是根据av号到每个视频里面爬取对应的信息了,为了数据的完整性排行榜页面的播放量和弹幕数值我也进行了爬取.

爬取每个视频相关信息的时候遇到了很多问题,首先是发现以前常用的直接request请求页面然后在页面中提取相关信息的暴力方法行不通了,因为像播放量这些数据是实时刷新的,不是写在页面里的.上网找解决方案,发现B站有官方的api直接可以用,http://api.bilibili.com/archive_stat/stat?aid=83697364,这里面不仅有上面提到的7个主要属性,还有dislike,no_reprint以及copyright,分别是不喜欢,是否原创,著作权保护,这个著作权保护具体干嘛的还不知道.

在浏览器中测试,页面可以正常访问,但是接下来的问题就困扰了我很长时间了,用程序去request后,status_code一直都是403,这是为什么呢,上网查了很久,说是有可能被封了ip,但是我的浏览器可以正常访问,所以不应该是ip被封,查了很久,都没用成功,最后想在github上看看别人的写法,发现排名第一的是介绍官方开放的api的,认真看了下,发现了这段文字.

avatar

之前用的确实一直都是浏览器,所以一直异常,这次按照文档中介绍的方法设置成邮箱,status_code返回200,成功.

接下来就是一个视频一个视频爬取数据了,为了不被小破站封禁每爬一个都停一段时间,所以时间还挺久的,中途生怕被封了hh.爬完后,将数据写成csv,关于每个视频的信息就爬取完毕了.检查一下,没什么问题.

avatar

再接下来就是排行榜上信息的爬取了,排行榜其实也有一个api可以用https://api.bilibili.com/x/web-interface/ranking?rid=1&day=3&type=1,这是其中一个网址,只要改参数就可以了.尝试用之前爬取视频信息的方法爬排行榜信息,但是发现又是403…又花了很多时间,不解的是换了个库,换成了urllib就可以了,迷.别的步骤都是和前面一样了.这里还因为手快,写文件的代码直接复制的前面的,所以前面写好的文件直接被覆盖了…只得又重新跑一遍.

因为弄到太晚,数据分析方面就没时间做了,等以后有时间在做了.

相关代码

记录一下代码

craw.py

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import requests
from bs4 import BeautifulSoup
import re
import json
import time
import pandas as pd


def get_aids():
id = [1, 168, 3, 129, 4, 36, 188, 160, 119, 155, 5, 181]
aids = []
for i in id:
useragent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'
header = {
'referer': 'no-referrer-when-downgrade',
'user-agent': useragent,
}
posturl = 'https://www.bilibili.com/ranking/all/'+str(i)+'/0/3'
r = requests.get(posturl, headers=header)
soup = BeautifulSoup(r.text, 'lxml')
data = soup.select(
'#app > div.b-page-body > div > div.rank-container > div.rank-body > div.rank-list-wrap > ul > li > div.content')
for item in data:
ul = item.find_all('a')
for a in ul:
aids.append(re.findall(r"\d\d\d\d\d\d\d\d", a.get("href")))
break
return aids


def get_data(aids):
header = {
'referer': 'no-referrer-when-downgrade',
'User-Agent': 'BiLiBiLi WP Client/1.0.0 (邮箱)',
}
result = []
for aid in aids:
url = 'http://api.bilibili.com/archive_stat/stat?aid=' + str(aid)[2:-2]
try:
res = requests.get(url, headers=header, timeout=6).json()
time.sleep(0.6)
data = res['data']
msg = {
'aid': data['aid'], # 视频编号
'view': data['view'], # 播放量
'danmaku': data['danmaku'], # 弹幕数
'reply': data['reply'], # 评论数
'favorite': data['favorite'], # 收藏数
'coin': data['coin'], # 硬币数
'share': data['share'], # 分享数
'like': data['like'], # 点赞数
'dislike': data['dislike'], # 不喜欢
'no_reprint': data['no_reprint'], # 是否原创
'copyright': data['copyright'] # 著作权保护
}
result.append(msg)
except:
pass
return result


def write_csv(msg):
column = ['aid', 'view', 'danmaku', 'reply', 'favorite', 'coin',
'share', 'like', 'dislike', 'no_reprint', 'copyright']
data = pd.DataFrame(columns=column, data=msg)
data.to_csv('msg.csv', index=False)


if __name__ == '__main__':
aids = get_aids()
msg = get_data(aids)
write_csv(msg)

rank.py

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
import requests
import urllib
from bs4 import BeautifulSoup
import re
import json
import pandas as pd


def craw():
day = ['3']
rid = ['1', '168', '3', '129', '4', '36',
'188', '160', '119', '155', '5', '181']
result = []
for i in rid:
url = "https://api.bilibili.com/x/web-interface/ranking?rid=" + i + "&day=3&type=1"
ret = urllib.request.Request(url=url, method='GET')
res = urllib.request.urlopen(ret)
req = str(BeautifulSoup(res, 'html.parser'))
temp = json.loads(req)
data = temp["data"]
msg = data["list"]
for dic in msg:
elements = {
'aid': dic['aid'],
'coins': dic['coins'],
'play': dic['play'],
'pts': dic['pts'],
'review': dic['video_review'],
}
result.append(elements)
return result


def write_csv(msg):
column = ['aid', 'coins', 'play', 'pts', 'review']
data = pd.DataFrame(columns=column, data=msg)
data.to_csv('rank.csv', index=False)


if __name__ == '__main__':
result = craw()
write_csv(result)
  • 本文标题:一次完整的对bilibili数据爬取的过程
  • 本文作者:Kale
  • 创建时间:2020-01-19 02:19:55
  • 本文链接:https://kalew515.com/2020/01/19/一次完整的对bilibili数据爬取的过程/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!