在item文件中写入
class BilibiliItem(scrapy.Item):
#明确目标
name = scrapy.Field() # 视频名称
like = scrapy.Field() # 点赞
coin = scrapy.Field() # 投币数
shoucang = scrapy.Field() # 收藏
content = scrapy.Field() # 弹幕内容
renshu = scrapy.Field() # 在线观看人数
1.b站的热门视频在主页面有八个,所以首先是获得这八个视频的url,通过检查可以看到这几个视频都在recommend-box属性里
所以通过xpath提取该节点属性,再进行遍历即可,相关代码
video_list = response.xpath('//*[@id="reportFirst1"]/div[2]/div')[0:8] for each in video_list:
2.通过xpath可以很容易获得标题,创建一个item字典,然后将标题写入字典中
3.b站除了标题,其他的比如在线人数,点赞,收藏等都是异步加载,所以我们不能直接从该页面提取到我们所需要的信息,所以需要进行抓包操作。
打开一个热门视频,通过F12,在Network的XHR中可以看到网络上所传输的数据,刷新一下能够看到有很多的数据包逐渐出现,这时我们就可以通过分析所抓取的数据包来获取我们所需要的内容。
4.我们要获取在线人数,那就抓取含有在线人数数据的包
在这个数据包的response中,可以看到有
这个就是我们所要的在线人数了,所以现在的问题是如何通过爬虫来抓取每一个视频数据包中的内容。
5.解决问题,在数据包的Headers中可以看到每一个包的URL,所以我们的思路就是通过访问该URL再通过正则或者Xpath提取出我们所需要的数据。但是因为有八个视频,每一个视频包的URL都不一样,所以我们通过找到相应的规律,将八个视频统一表达出来就行了。以在线人数为例,经过对比,可以发现,在这个URL中https://api.bilibili.com/x/player.so?id=cid%3A153733411&aid=90014355&buvid=49E1B1E8-CF64-4E58-901A-BCA65D4386F8155840infoc
cid%3A后面的一串数字可以在页面上查找再通过.split()进行截取,&aid后面的数字对应的是视频的AV号,AV号可以在页面中通过正则提取,所以将这些信息进行拼接则就可以表示出每一个视频所对应包的URL了。
6.找到在线人数后,再找到点赞投币收藏所对应的数据包,还有弹幕所对应的数据包,将他们的URL统一表达式录入字典中,方便在后面的函数中使用。
7.定义一个函数,将在这个函数中爬取点赞投币收藏的人数。
由于是js异步加载,所以通过引入包json,使用json.loads()来加载页面中的文本,再通过.get()来获取页面中的文本,通过提取,将得到的coin,favorite和like写入字典中即可。
8.因为在线人数在response中有相应的文本,所以可以在获取页面后直接通过正则来匹配到在线人数
9.最后一个就是弹幕内容了,因为弹幕很多,所以创建一个列表,在所爬取的页面信息中进行for in循环,在弹幕内容的属性名称中,有很多数字,相对应的时间就是第五个数字,所以通过.split()[4]截取第五个数字,再用time包中的方法转换成相应的时间,代码如下~~~
time_jie = int(time_base.split(’,’)[4])
time_huan = time.localtime((time_jie))
end_time = time.strftime(’%Y-%m-%d %H:%M:%S’,time_huan)
然后再将数据传入字典。
10.将字典中的数据实例化yield BilibiliItem( name=item['name'], like=item['like'], coin=item['coin'], shoucang=item['shoucang'], renshu=item['renshu'], content=item['content'])
11.在pipeline中写入将数据传入mongodb中,方法见我的另一篇文章。