寒假在学机器学习,晚上突然想起以前看过的一个很喜欢的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的,认真看了下,发现了这段文字.
之前用的确实一直都是浏览器,所以一直异常,这次按照文档中介绍的方法设置成邮箱,status_code
返回200,成功.
接下来就是一个视频一个视频爬取数据了,为了不被小破站封禁每爬一个都停一段时间,所以时间还挺久的,中途生怕被封了hh.爬完后,将数据写成csv,关于每个视频的信息就爬取完毕了.检查一下,没什么问题.
再接下来就是排行榜上信息的爬取了,排行榜其实也有一个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 requestsfrom bs4 import BeautifulSoupimport reimport jsonimport timeimport pandas as pddef 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 requestsimport urllibfrom bs4 import BeautifulSoupimport reimport jsonimport pandas as pddef 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)