爬取’a’+1站弹幕,发现不少关于这个网站弹幕爬取方法的帖子都被和谐了,所以我这里就不直接说这个网站的名字了。不过大家也应该知道这个以弹幕著名的网站是哪个。
本文的目的是爬去某个分区,比如:科技区,的某个标签中的500个视频的弹幕数据,从而进行数据分析的实验。
主要分为源网页html文件获取,html解析,视频cid获取和弹幕文件获取四个步骤。
1. 源网页html文件获取该步骤的任务是获取页面中的视频信息。
不少帖子是涌过selenium自动化刷懂页面从而获取视频信息。由于我不用爬取太多的视频,所以选择手动滑动窗口再手动复制html文本。
通过浏览器的开发者工具,定位到包含视频的div标签,复制该div的内容到txt文件中。注意,由于视频加载模式是懒加载,即必须手动滑动网页才能加载更多的视频信息。(滑动时可以看到该div中的子标签不断增多)
获取源html文本文件后,需要对html进行解析获取视频的信息。我的解析方法如下:(可能不适用所有情况,可能需要你自行根据html结构解析)
from bs4 import BeautifulSoup
# 使用BeatifulSoup库对html进行解析
# 参考资料:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
soup = BeautifulSoup(open(f'data/videos_div.txt'), "html.parser")
# 从每个存储视频信息的中,解析出视频信息
# 通过html的class属性,对相应的信息进行定位
videos = []
for item in soup.find_all('div', attrs={'class': 'bili-video-card'})[:800]:
video = {}
# 视频标题
video['title'] = item.find('h3', attrs={'class': "bili-video-card__info--tit"})['title']
# 视频链接
video['url'] = item.find('div', attrs={'class':'bili-video-card__info--right'}).a['href'][2:]
# 视频bvid
video['bvid'] = video['url'].split('/')[-1]
# 视频观看量
video['play_count'] = item.find('span', attrs={'class': 'bili-video-card__stats--text'}).string
# 视频时长
video['duration'] = item.find('span', attrs={'class': 'bili-video-card__stats__duration'}).string
# up主
video['author'] = item.find('span', attrs={'class': 'bili-video-card__info--author'}).string
videos.append(video)
video_df = pd.DataFrame(videos)
从而获取视频信息的DataFrame,metadata如下:
| 变量名称 | 含义 |
|---|---|
| title | 视频名称 |
| url | 视频链接 |
| bvid | 视频的bvid |
| play_count | 视频的播放量 |
| duration | 视频时长 |
| author | up主 |
视频的弹幕需要视频的cid来获取,但是我们目前只有视频的bvid,我们需要一个方法根据视频的bvid获取cid:
我找到了以下的接口通过bvid获取视频cid:
# 爬取每项视频的cid
cid_col = []
# 通过下面的url可以通过bvid找到视频的cid
base_url = "http://api.bilibili.com/x/player/pagelist?jsonp=jsonp&bvid="
for bvid in tqdm(video_df['bvid']):
cid = requests.get(base_url+bvid).json()["data"][0]["cid"]
cid_col.append(cid)
# 线程停止0.1秒,防止被ban
time.sleep(0.1)
video_df['cid'] = cid_col
video_df.head()
4. 根据视频cid获取弹幕
有了视频的cid后,我们可以获取弹幕的xml文件,再对弹幕的xml文件进行解析,即可获取视频的弹幕。
def construct_comment_attrs(attr_list, text, cid):
"""
构建弹幕的相关属性字典,需要用cid来表明该弹幕所属的视频
"""
return {
"弹幕内容": text,
"cid": cid,
"出现时间": attr_list[0],
"模式": attr_list[1],
"字体": attr_list[2],
"颜色": attr_list[3],
"评论时间": attr_list[4],
"弹幕池": attr_list[5],
"uid": attr_list[6],
"弹幕id": attr_list[7]
}
# 爬取每项视频的弹幕信息
base_url = "http://comment.bilibili.com/{}.xml"
comment_parsed_list = []
for cid in tqdm(video_df['cid']):
# 获取存储弹幕的xml文件
resp = requests.get(base_url.format(cid))
resp.encoding='utf8'
comment_str = resp.text
# 通过xml库中的xml.dom.minidom.parseString()对xml字符串进行解析
# 相关参考资料:https://blog.csdn.net/qq_36072270/article/details/105295539
dom_tree = minidom.parseString(comment_str)
root_node = dom_tree.documentElement
comment_list = root_node.getElementsByTagName("d")
for comment in comment_list:
p = comment.getAttribute("p")
attr_list = p.split(",")
text = comment.childNodes[0].nodeValue
comment_parsed_list.append(construct_comment_attrs(attr_list, text, cid))
time.sleep(0.5)
xml文件中的各个字段含义可以看这篇博客
至此,我们成功爬取了视频的弹幕。本文的技术方案存在不足,视频的获取依托于对html文件的获取,没有实现html文件获取的自动化了。



