原创不易,本文禁止抄袭,转载请附上链接,违权必究forever!
11月6日,在英雄联盟总决赛中,EDG战队以3:2战胜韩国队,获得2021年英雄联盟全球总决赛冠军,这个比赛在全网各大平台也是备受瞩目:
1、微博热搜第一名,截止2021-11-10已有亿级观看量,微博粉丝数到达638.4万
2、哔哩哔哩已有几亿人气,总弹幕有22.3万,全站排行榜最高第2名,B站粉丝已有219.9万
3、腾讯、爱奇艺、优酷等视频平台800万人看过
4、虎牙等直播平台热度也是居高不下
5、央视新闻也发微博庆祝EDG夺冠
既然比赛热度这么高,那么本次我们就以bilibili为基准,通过采集EDG夺冠比赛视频在哔哩哔哩的3万条弹幕数据,再通过Python来分析进而感受粉丝的热情
利用爬虫技术抓取EDG战队在B站夺冠比赛视频的3万条弹幕数据
通过jieba、numpy等Python库对抓取来的弹幕数据进行分析并且可视化
利用pandas+自然语言处理(NLP)等对EDG夺冠比赛视频的3万条弹幕数据进行情感分析,根据分析结果得出一些结论
首先进入EDG夺冠比赛视频URL:
https://www.bilibili.com/video/BV1EP4y1j7kV?p=1
哔哩哔哩已为大家整理好了EDG比赛视频,从开幕式到夺冠时刻,共有7个视频
哔哩哔哩弹幕数据接口:
http://api.bilibili.com/x/v1/dm/list.so?oid=XXX
这个接口就是B站弹幕数据专用接口,我们可以直接拿来用,这个接口中的oid可以理解为每个视频中的唯一标识符,它由数字组成,每一个视频都有唯一的一个oid,那么我们只要找到oid就可以请求相应比赛视频弹幕的API接口,从而抓取弹幕数据
获取oid
打开开发者工具,切换到Network选项,然后找到以pagelist为开头的请求接口
接着找到Request URL这个请求接口,打开新窗口直接用这个API接口请求,如下图:
当我们直接请求这个API接口时可以看到JSON格式的数据,而在里面的cid就是我们需要的oid,如下所示:
{
"code":0,"message":"0","ttl":1,"data":[{
"cid":437586584,"page":1,"from":"vupload","part":"第一局 4K","duration":2952,"vid":"","weblink":"","dimension":{
"width":1920,"height":1080,"rotate":0}},{
"cid":437626309,"page":2,"from":"vupload","part":"第二局 4K","duration":3031,"vid":"","weblink":"","dimension":{
"width":1920,"height":1080,"rotate":0}},{
"cid":437659159,"page":3,"from":"vupload","part":"第三局 4K","duration":3406,"vid":"","weblink":"","dimension":{
"width":1920,"height":1080,"rotate":0}},{
"cid":437727348,"page":4,"from":"vupload","part":"第四局 4K","duration":3212,"vid":"","weblink":"","dimension":{
"width":1920,"height":1080,"rotate":0}},{
"cid":437729555,"page":5,"from":"vupload","part":"第五局 4K","duration":3478,"vid":"","weblink":"","dimension":{
"width":1920,"height":1080,"rotate":0}},{
"cid":437550300,"page":6,"from":"vupload","part":"开幕式","duration":984,"vid":"","weblink":"","dimension":{
"width":1920,"height":1080,"rotate":0}},{
"cid":437717574,"page":7,"from":"vupload","part":"夺冠时刻","duration":2017,"vid":"","weblink":"","dimension":{
"width":1920,"height":1080,"rotate":0}}]
可以看到,每个cid对应每一个比赛视频。我们也可以点击Response选项,里面的数据是真实的数据,意味着数据没有经过折叠,与直接请求Request URL返回的JSON数据是一样的
定义一个获取cid的方法
import requests
import json
def get_cid():
url = 'https://api.bilibili.com/x/player/pagelist?bvid=BV1EP4y1j7kV&jsonp=jsonp'
try:
response = requests.get(url,timeout=None)
if response is not None:
return response.text
else:
return Nnone
except Exception as e:
print(e.args)
if __name__ == '__main__':
data = get_cid()
json_data = json.loads(data)
for cid_datas in json_data['data']:
cid = cid_datas.get('cid')
print(cid)
if __name__ == '__main__':
data = get_cid()
json_data = json.loads(data)
base_api = 'http://api.bilibili.com/x/v1/dm/list.so?oid='
for cid_datas in json_data['data']:
cid = cid_datas.get('cid')
detail_api = base_api + str(cid)
print(detail_api)
控制台输出如下:
一共有7个网址,对应7个EDG比赛视频的弹幕数据,我们点开第一个网址查看
抓取弹幕数据
从上一张图可以看到,每一条弹幕数据都在每一个标签中,面对这种格式我们思考一下用哪种解析工具比较合适?答案当然是正则表达式,接下来我们要获取7个比赛视频的22.3万条数据,代码如下:
base_api = 'http://api.bilibili.com/x/v1/dm/list.so?oid='
all_api = []
for cid_datas in json_data['data']:
cid = cid_datas.get('cid')
detail_api = base_api + str(cid)
all_api.append(detail_api)
for api in all_api:
edg_datas = get_api_data(detail_api)
edg_datas = re.findall('(.*?)' ,edg_datas,re.S)
with open('EDG.txt','a',encoding='utf-8') as f:
for edg_data in edg_datas:
print(edg_data)
f.write(edg_data + '\n')
避免乱码,加上如下代码:
response.encoding = chardet.detect(response.content)['encoding']
控制台输出如下:
由于弹幕数据共有3万条,这里仅展示EDG.txt部分弹幕数据,如下图所示:
我们已经抓取到弹幕数据,接下来利用EDG背景图做一个词云图
代码如下:
import jieba
from wordcloud import WordCloud
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
def do_wordcloud():
text = open('EDG.txt','r',encoding='utf-8').read()
text = text.replace('\n','').replace('\u3000','')
text_cut = jieba.lcut(text)
text_cut = ' '.join(text_cut)
#过滤一些没有关系的词
stop_words = ['“',',',' ','我','的','是','了',':','?','!','啊','你','吗','。','我们']
background = Image.open("EDG.jpg")
graph = np.array(background)
word_cloud = WordCloud(font_path='simsun.ttc',
background_color='white',
mask=graph, # 指定词云的形状
stopwords=stop_words)
word_cloud.generate(text_cut)
plt.subplots(figsize=(12,8))
plt.imshow(word_cloud)
plt.axis('off')
plt.show()
word_cloud.to_file('edg.png')
控制台输出如下:
把迪迦奥特曼背景图片也制作一波吧,啊哈哈哈!
制作成迪迦奥特曼词云图形状,如下所示:
data = pd.read_csv('EDG.csv')
data = data.head()
print(data)
data = pd.read_csv('EDG.csv')
data = data[['id','content']]
data = data.head(10)
print(data)
先安装一下用于情感分析的Python库:
pip install snownlp -i https://pypi.doubanio.com/simple
from snownlp import SnowNLP
data1['emotion'] = data1['content'].apply(lambda x:SnowNLP(x).sentiments)
data1 = data1.head()
print(data1)
data1 = data1.describe()
控制台输出:
数据说明:emotion的平均值为0.63,中位数为0.67,25%分位数为0.49,可见不到25%的数据造成了整体均值的较大下移。另外上图的最下面可以看到,情感分析执行时间为48.8s,数据量还是挺大的。
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
bins = np.arange(0,1.1,0.1) #设置区间
plt.hist(data1['emotion'],bins,color='#4F94CD',alpha=0.9)
plt.xlim(0,1)
plt.xlabel('情感分析')
plt.ylabel('数量')
plt.title('情感分析直方图')
plt.show()
from jieba import analyse
key_words = analyse.extract_tags(sentence=text_cut,topK=10,withWeight=True,allowPOS=())
print(key_words)
控制台输出:
数据说明:
参数说明:
计算积极弹幕与消极弹幕各自的数目:
pos,neg = 0,0
for i in data1['emotion']:
if i >= 0.5:
pos += 1
else:
neg += 1
print(f'积极弹幕数据为:{
pos}' + '\n' + f'消极弹幕数据为:{
neg}')
控制台输出:
积极弹幕数据为:17941
消极弹幕数据为:6054
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
pie_labels = 'positive','negative'
plt.pie([pos,neg],labels=pie_labels,autopct='%1.2f%%',shadow=True)
plt.show()
控制台输出:
由上图可见,由74.77%的弹幕数据是积极的,有25.23%的弹幕数据是消极的,总体来看,积极弹幕还是比较多的
取出部分消极弹幕数据
data2 = data1[data1['emotion'] < 0.5]
data2 = data2.head()
print(data2)
PIL库
jieba库
numpy库
pandas库
requests库
wordcloud库
matplotlib库
json,re,chardet库
snownlp情感分析库
本人博客园原文链接:阅读原文
完整项目下载链接:下载
本人原创公众号原文链接:阅读原文
原创不易,如果觉得有趣好玩,希望可以随手点个赞,拜谢各位老铁!
最近发现CSDN上好多人抄袭本人博客,还比我热度高,哎!毕竟是10月份才刚刚开始写博客,虽然是18年创建的账号,知名度和粉丝没有别人高啊!
作者:小鸿的摸鱼日常,Goal:让编程更有趣!
原创微信公众号:『小鸿星空科技』,专注于算法、爬虫,网站,游戏开发,数据分析、自然语言处理,AI等,期待你的关注,让我们一起成长、一起Coding!
转载说明:务必注明来源(注明:来源于公众号:小鸿星空科技, 作者:小鸿的摸鱼日常)