这是一个python爬虫的初学练手项目,作用是从 bilibili.com
爬取弹幕并生成词云。
爬取弹幕
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| def get_cid(bvid): """获取视频cid""" url = 'https://api.bilibili.com/x/web-interface/view?bvid={}'.format(bvid) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299', 'Referer': 'https://www.bilibili.com/video/{}'.format(bvid) } response = requests.get(url, headers=headers) data = response.json() cid = data['data']['cid']
return cid
""" # 将Python对象转化为JSON格式的字符串,并输出 print(json.dumps(data, indent=4, ensure_ascii=False)) print(cid) """
|
传入视频的BV号,在headers
里面定义了一个请求头,用于描述发起请求的客户端信息。在这段代码中,我们手动设置了一个浏览器用户代理,用于模拟浏览器的行为。
然后把获取到的响应转换成json格式,从响应里提取出视频的cid
值。
这篇文章,详细解析了获取到的json:从bilibili获取到的json解析。可以看到一个视频里,不同分p有不同的cid
。
问我为什么不写不同分p的情况?因为我懒,有需要再写(2023.4.14日备注,此问题已修复)。
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
| def get_danmu(cid): """获取弹幕""" url = 'https://comment.bilibili.com/{}.xml'.format(cid) response = requests.get(url) xml_content = response.content.decode('utf-8') root = ET.fromstring(xml_content) danmu_list = [] for d in root.iter('d'): danmu = d.text p_attrs = d.attrib['p'] p_attrs_list = p_attrs.split(',') danmu_dict = { 'text': danmu, 'time': float(p_attrs_list[0]), 'mode': int(p_attrs_list[1]), 'fontsize': int(p_attrs_list[2]), 'color': int(p_attrs_list[3]), 'timestamp': int(p_attrs_list[4]), 'pool': int(p_attrs_list[5]), 'userid': p_attrs_list[6], 'rowid': int(p_attrs_list[7]), 'duration': int(p_attrs_list[8]), } danmu_list.append(danmu_dict) return danmu_list
|
传入cid
,b站的弹幕都存在https://comment.bilibili.com/{cid}.xml
里,这个地址可以用浏览器直接访问。用爬虫访问这个URL,获取弹幕列表。
生成词云
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
| def word_cloud_generator(json_name): with open(json_name, 'r', encoding='utf-8') as f: data = json.load(f)
text = '' for item in data: text += item['text']
stopwords = set() with open('cn_stopwords.txt', 'r', encoding='utf-8') as f: for line in f: stopwords.add(line.strip())
words = [word for word in jieba.cut(text) if word not in stopwords]
words_str = ' '.join(words)
wc = WordCloud(background_color='white', width=1000, height=800, font_path='msyh.ttc') wc.generate(words_str)
""" # 显示词云 plt.imshow(wc) plt.axis('off') plt.show() """
filename = os.path.splitext(json_name)[0] + '.png' wc.to_file(filename)
|
把获取的弹幕进行分词,这里使用了jieba
中文分词,把句子分成词语。然后加载停用词表,去掉诸如这个、那个、是、吧等类似无意义的词语。设置词云图片的背景颜色,图片大小,生成词云图片。