0%

b站爬虫api和代码分享

这几天在做b站的一个爬虫项目.

先放api. 感觉爬虫阶段最难的地方就在于通过抓包或者其他手段来找api了, 需要与被爬网站斗智斗勇. 但是说实话b站对爬虫还算比较友好的了. 像京东什么的都需要直接上selenium了.

https://api.bilibili.com/x/web-interface/view?aid={}

aid应该是递增的. 所以从某个值开始遍历就可以了. 中间可能会碰到一些已经被删除了的视频, 这时返回的json文件中是没有”data”这个标签的, 直接跳过即可.

注意, 爬的太频繁会被封ip. 我自己的测试中, 不控制发送请求的速度的话会很快被封, 如果控制爬虫1秒1次请求的话在爬取3000次左右被封. 如果控制爬虫2秒1次请求的话在爬取7000次左右被封. 所以买ip池才是王道.

这里我是从aid = 40000000 开始遍历的. 对应的时间是2019年1月左右. 视频的发布时间越早, aid越小. aid = 30000000的时候就是对应2018年8月左右的时间了. 想要爬取特定的某个时间段的话就可以酌情增减aid.

爬下来的所有信息都是json格式, 很方便解析. 下面说明各个字段的含义. 参考于github和知乎上各种b站爬虫项目. 以https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/video/info.md 为主

1
2
3
4
5
6
7
insert into av_interpret(columnName, interpret) values("bvid", "视频的bvid号, 唯一"), ("aid", "视频的av号, 唯一"), ("videos", "01变量, 代表是否为视频"),
("tid", "视频标签id"), ("tname", "视频标签"), ("copyright", "1原创, 2转载"), ("title", "视频题目"), ("pubdate", "稿件发布时间. Unix时间戳类型, 自 1970 年 1 月 1 日00:00:00 GMT以来的秒数"),
("ctime", "用户提交稿件的时间"), ("descript", "视频简介"), ("state", "视频状态, 作用不详"), ("attribute", "作用不详"), ("duration", "视频总时长(秒)"), ("mid", "视频作者id, 通过此Key连接另外一张表up"),
("name_", "视频作者昵称"), ("view_", "视频播放数"), ("danmaku", "视频弹幕数"), ("reply", "视频回复数"), ("favorite", "收藏数"), ("coin", "投币数"), ("share_", "分享数"),
("now_rank", "当前排名"), ("his_rank", "历史最高排名"), ("like", "点赞数"), ("dislike", "点踩数(恒为0)"), ("dynamic_", "和视频同步发布的动态的文字内容"),
("rights_elec", "是否支持充电"), ("rights_download", "是否允许下载"), ("rights_hd5", "是否有高码率"), ("rights_no_reprint", "是否有'禁止转载'标志"),
("rights_autoplay", "是否自动播放"), ("rights_is_cooperation", "是否为联合投稿"), ("allow_submit", "是否允许提交字幕 ");

现在, 我们获得了每个视频对应的up主mid字段. 但是不清楚up主的相关信息. 例如粉丝数等.

我们还需要一个api, 通过mid获取对应up主的全部信息.

https://api.bilibili.com/x/web-interface/card?mid={}&jsonp=jsonp

爬取下来的json各个字段含义如下所示

1
2
insert into up_interpret(columnName, interpret) values("mid", "up主id"), ("name_", "up主昵称"), ("sex", "up主性别"), ("fans", "粉丝数"),("friend", "up主关注的人数"), ("sign", "个性签名"), ("current_level", "当前等级"), ("pendant_id", "头像挂件id"), ("pendant_name", "头像挂件名称(头像挂件仅手机端可见, pc端不可见)"),
("nameplate_id", "成就id"), ("nameplate_name", "成就名称(成就勋章仅手机端可见, pc端不可见)"), ("nameplate_level", "成就级别"), ("nameplate_condition", "达成成就条件"),("official_role", "意义不详"), ("official_title", "官方认证名称"), ("official_verify_type", "官方认证种类"), ("official_verify_desc", "官方认证描述"),("vipType", "会员类型. 0 无会员, 1 大会员, 2 年度大会员"), ("vipStatus", "vip状态. 0 已到期. 1 未到期"), ("archive_count", "总投稿数");

所以接下来就可以用mid作为外键连接两张表了. 爬虫到此结束. 源代码如下所示.

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
import time
import json
from time import strftime, gmtime
import requests
headers = {
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': ('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36'
'(KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36')
}

#cid 3889776
#54388599

if __name__ == '__main__':
begin = 40000000
end = 50000000
for i in range(3, 24):
with open("./bilibili{}.txt".format(i),'a',encoding='utf-8') as f:
for av in range(40005000 + i * 3600, 40005000 + (i + 1) * 3600):
try:
url = "https://api.bilibili.com/x/web-interface/view?aid={}".format(av)
# url = "https://api.bilibili.com/x/web-interface/archive/stat?aid={}".format(av)
get_json = requests.get(url=url, headers=headers)
time.sleep(1)
text = get_json.text
data = json.loads(text)
if "data" in data:
f.write(text)
f.write('\n')
print(text)
except Exception as e:
print("aid {} failed".format(av))

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
import time
import requests
headers = {
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': ('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36'
'(KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36')
}
#https://api.bilibili.com/x/web-interface/card?mid=9824766&jsonp=jsonp
if __name__ == '__main__':
with open("./AllMID.txt", 'r', encoding="utf-8") as f:
mids = f.readlines()
with open("./upInfo2.txt", 'a', encoding='utf-8') as f:
for i in range(3326,len(mids)):
try:
url = "https://api.bilibili.com/x/web-interface/card?mid={}&jsonp=jsonp".format(mids[i].strip())
get_json = requests.get(url=url, headers=headers)
time.sleep(2)
text = get_json.text
f.write(text)
print(i)
print(text)
f.write("\n")
except Exception as e:
pass