此次爬取的信息有:
1、视频名称
2、在线观看人数
3、弹幕内容
4、弹幕发送时间
5、弹幕在视频中的位置
6、点赞
7、收藏
8、投币数
由于b站的很多信息是动态加载的。所以部分信息,需要自己抓包,进入对应的网址抽取信息。例如在线观看视频人数,投币数,收藏数等等。
我的思路
首先拿到这个小项目时,分析出 要获取的数据如上。观察,不同信息对应的url。首先,我们应先在B站首页,获取出 要爬取视频的 名字,url地址。但此时存在一个问题:
若直接发送请求获取响应,只能的到8个视频的url和名字,其实这一栏共有24个视频信息,但这个是轮播图,不能一次性得到。起先,我试图通过抓包,希望能够得到接口地址,得到所有信息。但事与愿违,经过使用开发者工具及分析页面源码,我发现这个网页 用的vue的响应式,就是监听左右翻,然后把对应页数里的数据改到html上的href的里面 不是xhr请求。翻页更新是通过js改的html的数据。与是乎,我想到了用selenium来进行 翻页操作。并用
webdriver.Chrome().page_source来获取当前网页源码,来获得翻页后的视频信息。
上代码:
#通过selenium 间隔0.1秒点击3次 右翻页 获取 视频的名称 地址video_names = []video_urls = []chrome = webdriver.Chrome()url = 'https://www.bilibili.com/'chrome.get(url)for i in range(3):response = chrome.page_sourcee = etree.HTML(response)video_names += e.xpath('//div[@class="info"]/p[@class="title"]/text()')video_urls += e.xpath('//div[@class="recommend-box"]//a/@href')chrome.find_element_by_xpath('//i[@class="bilifont bili-icon_caozuo_xiangyou"]').click() #点击翻页time.sleep(0.1)
此时,得到了 两个列表,一个是视频名,视频url。各有24个元素,对应24个视频。
接下来我们要 进入具体某个视频 得到其他信息。
经过对网页的分析,其过程我不再赘述。发现了储存点赞 投币 收藏 信息的网址 格式为:
aid
url = 'https://api.bilibili.com/x/web-interface/archive/stat?aid='
数据形式以json形式展现
而弹幕是存放在一个xml文件地址里的
cid
xml_url='http://comment.bilibili.com/{}.xml'.format(cids[i])
举个栗子
<d p="122.59100,1,25,16777215,1580443864,0,6080b8b9,27945436399534080">还有个地图和求生之路里完全一样……那个桥洞</d>
这其中,122.59100指的是 弹幕在视频出现的时间戳,27945436399534080指的是弹幕发送时的时间戳。分别需要转化为x分x秒,x月x日x时x秒。具体代码:
# # #----------------------------------------------------------------弹幕内容 时间--------------------------------------------------------------------------# 合成弹幕xml文件地址xml_url='http://comment.bilibili.com/{}.xml'.format(cids[i])response = requests.get(url=xml_url)response.encoding = 'utf-8_sig'# print(response.text)Barrage_html = response.textsoup = BS(Barrage_html, 'lxml')all_d = soup.select('d')for d in all_d:# 把d标签中P的各个属性分离开Barrage_list = d['p'].split(',')# d.get_text()是弹幕内容Barrage_list.append(d.get_text())#删去xml解析信息的列表里,不要的元素for i in range(3):del Barrage_list[1]for j in range(3):del Barrage_list[2]#将弹幕在视频出现的时间戳,转化并替换为 分 秒total_time = time.strftime("%M:%S", time.gmtime(float(Barrage_list[0])))del Barrage_list[0]Barrage_list.insert(0, total_time)#将时间戳转化为北京时间,并替换timeNum = int(Barrage_list[1])timeArray = time.localtime(timeNum)otherStyleTime = time.strftime("%m-%d %H:%M", timeArray)del Barrage_list[1]Barrage_list.insert(1, otherStyleTime)#d弹幕在视频的时间video_time = Barrage_list[0]#发送弹幕时间Barrage_time = Barrage_list[1]#弹幕内容Barrage_content = Barrage_list[2]
在线人数信息的获取,需要aid
向wss://broadcast.chat.bilibili.com:7823/sub
发送请求建立连接。
def connect(plz):url = "wss://broadcast.chat.bilibili.com:7823/sub"normal = base64.b64decode('AAAAIQASAAEAAAACAAAACQAAW29iamVjdCBPYmplY3Rd')ws = websocket.create_connection(url, timeout=10)ws.send(bytes(plz))get = ws.recv()# print(get)ws.send(bytes(normal))get = ws.recv()# print(get)if get.find(b'online') != -1:# online = get_online(get)online = get_online(get)return onlineelse:print("None")def get_online_from_av(av):send = make_send(av)online = connect(send)return onlineaudience_online = get_online_from_av(avid)
最后将得到 信息返回, 写入数据库。
共计24351行。
其他小的问题,利用好
都没问题,善于使用搜索引擎,省时又省力。
Github也是一个不错的好地方。