利用python对b站某GPT-4解说视频的近万条弹幕进行爬取、数据挖掘、数据分析、弹幕数量预测及情绪分类

        

目录

一、利用Python爬取弹幕

 二、利用几行代码直接生成词云

三、将弹幕属性和内容放入mysql当中

 四、分析弹幕在视频各节点的数量

1、分析视频各个片段出现的弹幕数量

2、分析视频各大章节出现的弹幕数量

3.分析视频各小节出现的弹幕数量

五、分析弹幕数量和日期的关系

1、分析不同日期的弹幕数量

2、上午、下午、晚上的弹幕数量

3、每天不同细分时间段的弹幕数量

六、利用LSTM网络对弹幕数量进行预测

七、利用SnowNLP库对弹幕进行情感分析

八、谁是弹幕发射器?

        近期,GPT-4在网络上引起了轩然大波,b站上也出现了许许多多关于GPT-4的解说视频,其中有一个解说视频受到了网友的热烈追捧,目前已填充有2万多的弹幕,这也引起了本人的极大兴趣,因此对该视频的弹幕进行了爬取,并记录于mysql数据库中,以进行数据分析、数据挖掘、弹幕数量预测和情绪分类等等。话不多说,正文开始。

一、利用Python爬取弹幕

        首先打开以下链接,该链接便是弹幕的视频来源,点击以下链接并打开,右键点击-检查,查看网页编写代码,再依此点击--网络--Fetch-XHR,然后播放视频,随着视频中弹幕的出现,右侧出现一次次请求,直到看到cid代号的出现,如下图右下角,记下cid的值,将该值填入下述网址中:https://comment.bilibili.com/cid值.xml,打开该网址就可以看到一条条弹幕信息了,我们要爬取的对象便是这条网址了。(爬取技术请用于正途)

【渐构】万字科普GPT4为何会颠覆现有工作流;为何你要关注微软Copilot、文心一言等大模型_哔哩哔哩_bilibili

 确定了网址,下面开始利用python对该网址进行爬取,代码如下:

import requests
from bs4 import BeautifulSoup
response = requests.get("https://comment.bilibili.com/1054910356.xml") #要爬取的网址
response.encoding='utf8' #编码方式
html = response.text
soup = BeautifulSoup(html) #使用beautifulsoup库快速查找我们想要的信息
all_txt = soup.findAll("d") #寻找到所有包含d的行
txt=[all_txts.attrs ["p"]for all_txts in all_txt] #寻找到所有包含d的行中属性为p的值,这里边包含了弹幕的虚拟id等
txtss=[all_txts.string for all_txts in all_txt] #寻找到所有包含d的行中的字符串数据,即弹幕内容
txtsss=[txts.replace(' ','') for txts in txtss] #将字符串中的空格消除掉
print(txt,txtsss) ###打印便可看见一条条弹幕的属性和内容了。

输出结果如下:

 二、利用几行代码直接生成词云

danmustr=''.join(i for i in txtsss) #将所有弹幕拼接在一起
words=list(jieba.cut(danmustr))  ###利用jieba库将弹幕按词进行切分
words=[i for i in words if len(i)>1] ###挑出长度大于1的词语(为去除诸如?,哈,啊等字符)
wc=wordcloud.WordCloud(height=1000,width=1000,font_path='simsun.ttc')#利用wordcloud库定义词云图片的信息
wc.generate(' '.join(words))   ##生成图片
print(wc)
plt.imshow(wc)
plt.show()

执行上述代码,得到以下词云图片:

         分析:从该词云图片信息可以知道,大量弹幕中都出现了就是人类、ai、中国等词眼,看来大家都认为gpt-4是一场重大变革,ai的智能程度或可比肩人类,另外大家也在讨论中国应当如何应对这次ai的巨大变革。

三、将弹幕属性和内容放入mysql当中

        为便于对弹幕数据的调用和处理,我们需要将其存入mysql数据库中,代码如下:

import pandas as pd
from datetime import datetime
from sqlalchemy import  create_engine,text

pg=pd.DataFrame({"paragraphs": txt,"comment":txtsss})#将弹幕属性和弹幕内容放入dataframe中
pg["time_happen"]=pg['paragraphs'].map(lambda x:x.split(',')[0]) #将弹幕的第一个属性值拆分为time_happen列
pg["danmu_gundong"]=pg['paragraphs'].map(lambda x:x.split(',')[1]) #将弹幕的第二个属性值拆分为danmu_gundong列
pg["danmu_size"]=pg['paragraphs'].map(lambda x:x.split(',')[2]) #与上类似
pg["danmu_color"]=pg['paragraphs'].map(lambda x:x.split(',')[3]) #与上类似
pg["danmu_ture_time"]=pg['paragraphs'].map(lambda x:x.split(',')[4]) #与上类似
pg["danmu_mode"]=pg['paragraphs'].map(lambda x:x.split(',')[5]) #与上类似
pg["user_id"]=pg['paragraphs'].map(lambda x:x.split(',')[6]) #与上类似
pg["danmu_ture_time"]=pg['danmu_ture_time'].apply(lambda x:datetime.fromtimestamp(int(x))) #将时间戳先转换为datetime,可不转
pg["danmu_ture_time"]=pg['danmu_ture_time'].apply(lambda x:x.date()) #将datetime转换为date日期,可不转
engine=create_engine('mysql+pymysql://root:123456@localhost/gpt') #利用sqlalchemy库建立mysql的引擎
pg.to_sql(name='gptlast',con=engine,index=False,if_exists='replace')#记得安装pymysql库!!,将数据写入mysql

执行上述代码,便可写入mysql当中,如下:

 四、分析弹幕在视频各节点的数量

1、分析视频各个片段出现的弹幕数量

        本文爬取了近万条弹幕,绘制了弹幕数量与出现时间的曲线图,绘制曲线图的代码如下:

import matplotlib
from matplotlib import pyplot as plt
engine=create_engine('mysql+pymysql://root:123456@localhost/gpt') #利用sqlalchemy库建立mysql的引擎
df=pd.read_sql(text('select * from gptlast'),con=engine.connect())#从mysql数据库中查找出所有弹幕信息
list_time_happen=df["time_happen"].tolist()
list_count_time_happen=[]
for i in range(500):
    count_time_happen = 0
    for j in range(7200):
        if i * 6.028 <= float(list_time_happen[j]) < (i + 1) * 6.028:
            list_time_happen[j]=i
            count_time_happen +=1
    list_count_time_happen.append(count_time_happen)
print(list_count_time_happen)
matplotlib.rcParams['font.family']='SimHei'
matplotlib.rcParams['font.size']=12
plt.plot(list_count_time_happen,color='g',linewidth=2,label="视频各时段的弹幕数量")
plt.xlabel("视频的各个时段,以6.028s为一个区间")
plt.ylabel('视频各个时段的弹幕数量',
           labelpad=-40,  #调整y轴标签与y轴的距离
           y=1.02,  #调整y轴标签的上下位置
           rotation=0)
plt.grid()
plt.show()

 绘制得到的曲线图如下:

         可以看出,视频的开头和结尾弹幕数量较多,弹幕数量最多的时间段是视频的48分23秒的位置,说明这个时间段的内容广受关注,本文查看视频的该时间段可知,这段内容讲述了:中国已经错了三次工业革命,不能再错过这次的gpt-4了,该段视频截图如下。

        在笔者看来,这段内容是整个视频的重中之重,可以说是整个视频的论点。因此引起了大家的广泛关注,面对这场ai浪潮,我们到底该如何应对?

2、分析视频各大章节出现的弹幕数量

        分析视频各大章节出现的弹幕数量,以分析网友对各个章节的喜爱程度,代码和上一小节类似,此处便不贴了。绘制直方图和饼状图如下:

 

         可以看出视频第四章节:未来影响,出现的弹幕最多,看来网友对GPT-4的未来影响比较感兴趣。但是,以上两图统计的是各个章节的弹幕数量,然而各个章节的时间长短不一,比如第一章引言只有几分钟,而其他几章有十几分钟,十几分钟内出现的弹幕数量当然比几分钟内出现的弹幕更多了,因此不区分章节时间长度而进行弹幕数量比较,是不太合理的,因此本文接着统计了各大章节每秒出现的弹幕数量,得到直方图和饼状图如下:

 

         从以上两图可以看出,第一章节开始逆袭,其每秒弹幕数量是最多的,因为是视频的开头,所以这是可以理解的,另外第三章每秒弹幕数量还是最少的,看来广大网友对这个大模型如何训练的并不感兴趣呀。

3.分析视频各小节出现的弹幕数量

        分析视频各小节出现的弹幕数量,以分析网友对各个小节的喜爱程度,代码和上上节类似,此处便不贴了。绘制直方图和饼状图如下:

 

         可以看出,4.3、5.3及4.2小节出现的弹幕数量最多,4.3是gpt-4的社会影响,5.3是gpt-4对国家竞争力的影响,4.2是gpt-4的应用价值,体现出了广大网友忧国忧民和注重实践应用的共同点呀。

        类似的,我们再来看看各小节的每秒弹幕数量,如下直方图和饼状图:

 

         通过上面两图可以发现,还是视频的开头和结尾的每秒弹幕数量比较多,另外就是2.1实质功能小节弹幕数量也比较多,这小节介绍了gpt-4的通俗原理,也引起了广大网友的积极讨论。

五、分析弹幕数量和日期的关系

1、分析不同日期的弹幕数量

import time
list_time_true=df["danmu_ture_time"].tolist() #将dataframe中的时间戳列转换成列表
dt='2023-3-15 0:0:0' #弹幕最早出现时间
time_=time.strptime(dt,"%Y-%m-%d %H:%M:%S") #将dt转换成strptime
time_small=time.mktime(time_) #将strptime转换成时间戳
list_count_time_happen=[] 
for i in range(28):    #该视频共公布28天,因此弹幕跨度为28天
    count_time_happen = 0 #用于记录这28天每天的弹幕数量
    for j in range(7200):
        if  i*3600*24+time_small <= int(list_time_true[j]) < (i+1)*3600*24+time_small:
            list_time_true[j] = i #这行代码可有可有
            count_time_happen += 1 #如果是当天的弹幕,则+1
    list_count_time_happen.append(count_time_happen) #将28天每天的弹幕数量记录于该列表中
print(list_count_time_happen) 
matplotlib.rcParams['font.family']='SimHei'
matplotlib.rcParams['font.size']=12
color=['deepskyblue','orange']
plt.bar(range(28), list_count_time_happen,color=color,width=0.4)
plt.xlabel("发送弹幕的日期,从3月15开始,4月11结束")
plt.ylabel('每天弹幕数量',
           labelpad=-40,  #调整y轴标签与y轴的距离
           y=1.02,  #调整y轴标签的上下位置
           rotation=0)
plt.xticks([0,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],[15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,1,2,3,4,5,6,7,8,9,10,11])
plt.show()

        得到每天弹幕数量的直方图如下:

         观察以上直方图我们可以发现,弹幕数量会先增多再减少,持续波浪状前进,视频刚发布初期,弹幕增长的速度是最快的,后期弹幕数量虽也有增长,但是势头没有前期高。另外查询日历可以发现,弹幕数量比较高的几天,几乎都是周末,工作日的弹幕数量较少,因此弹幕数量会出现波峰波谷,波浪状前进,看来广大网友工作日都在努力搬砖,没有过多空闲时间逛b站呀。

2、上午、下午、晚上的弹幕数量

        分析上午、下午和晚上的弹幕数量会不会有不同?代码思路和上节类似,这里便不贴了,绘制的直方图和饼状图如下图:

 

       观察以上两图可知,下午和晚上的弹幕数量最多,估计大家上午的时间都非常仓促,挣扎着起床就要去工作了,上午没有属于自己的时间,哈哈。下午的弹幕数量最高,估计大家在午休前都会逛会b站,笔者也是如此,晚上的情况大致也类似。

3、每天不同细分时间段的弹幕数量

        上节分析了上午、下午与晚上的弹幕数量,但是时间跨度较大,分析比较粗糙,下面针对更细分的时间段进行弹幕数量分析。将一天分成12个时间段,分别为0时~2时,2时~4时,4时~6时......22时~24时,绘制了各个时间段的弹幕数量直方图和饼状图:

 

        分析以上两图可知,20时~22时、22时~24时和12时~14时的弹幕数量最多,说明广大网友都是昼伏夜出的,晚上的时间比较充足,另外中午午休也可以抽出时间逛逛b站。4时~6时、6时~8时及2时~4时的弹幕数量最小,广大网友应该进入梦乡了。

六、利用LSTM网络对弹幕数量进行预测

        由5.1可知,本文共收集了28天的弹幕数量,将28天的弹幕数量分为训练集和测试集,前22天的弹幕用作训练,后6天的弹幕用作测试,如下图所示。本文以5天的弹幕数量为滑动窗口,预测下一天的弹幕数量,因此可得到训练集17组,测试集6组。

        使用双层LSTM网络作为预测模型,网络每层神经元个数为6个(因为本文数据集较为简单,使用6个神经元足以),LSTM网络层后接一层全连接层。代码如下:

####建立数据集
device=torch.device ('cuda:0' if torch.cuda.is_available() else 'cpu')
count_max=max(list_count_time_happen)
#归一化
for i in range(28):
    list_count_time_happen[i]=list_count_time_happen[i]/count_max
train_data=list_count_time_happen[0:22]
test_data=list_count_time_happen[22:28]
train_data_x=torch.zeros((17,5))
train_data_y=torch.zeros((17,1))
for i in range(17):
    train_data_x[i,0]=torch.tensor(train_data[i])
    train_data_x[i, 1] = torch.tensor(train_data[i+1])
    train_data_x[i, 2] = torch.tensor(train_data[i+2])
    train_data_x[i, 3] = torch.tensor(train_data[i+3])
    train_data_x[i, 4] = torch.tensor(train_data[i+4])
    train_data_y[i,:]=torch.tensor((train_data[i+5]))
test_data_x=torch.zeros((6,5))
test_data_y=torch.zeros((6,1))
for i in range(6):
    test_data_x[i,0]=torch.tensor(list_count_time_happen[17+i])
    test_data_x[i, 1] =torch.tensor(list_count_time_happen[17 + i+1])
    test_data_x[i, 2] = torch.tensor(list_count_time_happen[17 + i+2])
    test_data_x[i, 3] = torch.tensor(list_count_time_happen[17 + i+3])
    test_data_x[i, 4] = torch.tensor(list_count_time_happen[17 + i+4])
    test_data_y[i,:]=torch.tensor(list_count_time_happen[17+i+5])
print(train_data_x.dtype,train_data_y.dtype,test_data_x.dtype,test_data_y.dtype)
####构建网络模型

class LsTM(nn.Module):
    def __init__(self):
        super(LsTM, self).__init__()
        # 定义LSTM
        self.rnn = nn.LSTM(1, 6,2,batch_first=True)
        # 定义回归层网络,输入的特征维度等于LSTM的输出,输出维度为1)
        self.reg = nn.Sequential(
            nn.Linear(6, 1)
        )

    def forward(self, x):
        x=x.reshape(-1,5,1)
        #x = x.view(x.size(0), -1)
        x, (ht,ct) = self.rnn(x)
        ht = ht.reshape(-1, 2, 6)
        ht=ht[:,1,:]
        x = F.sigmoid(self.reg(ht))
        return x

model = LsTM().to(device)

quanzhi_pipei=5000
criterion = nn.MSELoss()
optimizer_ExpLR = torch.optim.Adam(model.parameters(), lr=0.001,betas=(0.9,0.999),eps=1e-08,weight_decay=0,amsgrad=False)
epoch=0
a=3
for i in range(2000):
    epoch=epoch+1
    optimizer_ExpLR.zero_grad()
    outputs = model(train_data_x.cuda())
    target = train_data_y.cuda()
    loss = criterion(outputs, target)
    loss.backward()
    optimizer_ExpLR.step()
    with torch.no_grad():
        if epoch % 2 == 0:
            print("--------------历经第{}次循环------------".format(epoch))
            print('--------当前的损失率等于:{}-------'.format(loss.item()))
test_outputs = model(test_data_x.cuda()).cpu().detach().numpy()
test_outputs=test_outputs.reshape((6,1))
####绘制真实值与预测值的对比图
matplotlib.rcParams['font.family']='SimHei'
matplotlib.rcParams['font.size']=12
plt.plot(range(6),test_data_y,range(6),test_outputs)
plt.legend(['true value','predicted value'])
plt.xlabel("时间")
plt.ylabel('弹幕数量占比',
           labelpad=-40,  #调整y轴标签与y轴的距离
           y=1.02,  #调整y轴标签的上下位置
           rotation=0)
plt.show()

得到预测值与真实值的对比图如下:

         预测效果不太理想,但是这是情有可原的,因为训练集太小,只有17组!!!尽力了老铁!

七、利用SnowNLP库对弹幕进行情感分析

        利用snownlp库对弹幕进行情感分析,这个库非常方便,直接调用其作为函数处理dataframe即可,返回对弹幕内容的评分,评分越高越积极,所以代码也是非常的简洁,如下所示:

import snownlp
import seaborn as sn
df['sentiment']=df["comment"].apply(lambda x:snownlp.SnowNLP(x).sentiments)
pd.set_option('display.max_rows', None)  # 显示所有行
# print(df[["comment",'sentiment']])
matplotlib.rcParams['font.family']='SimHei'
matplotlib.rcParams['font.size']=12
matplotlib.rcParams['axes.unicode_minus']=False
ax=sn.distplot(df['sentiment'],hist_kws={'color':'deepskyblue'},kde_kws={'color':'orange'},bins=20)
ax.set_title("GPT-4解说视频整体情感倾向")
plt.show()

利用库seaborn可得到如下整体弹幕情绪分析图如下:

         从以上情感分析图可知,弹幕中有很多积极地弹幕,但同时,消极的弹幕也不少。进一步的,笔者将情感评分>0.9分的弹幕选作为积极的弹幕,而情感评分<0.5的弹幕选作为消极的弹幕,如以下代码所示:

sentiment_list=df['sentiment'].tolist()
count_=[0,0]
for i in range(7200):
    if sentiment_list[i]>=0.9:
        count_[0]=count_[0]+1
    elif sentiment_list[i]<0.5:
        count_[1]=count_[1]+1
matplotlib.rcParams['font.family']='SimHei'
matplotlib.rcParams['font.size']=12
color=['deepskyblue','orange']
plt.bar(range(2),count_,color=color,width=0.3)
plt.xlabel("情绪种类")
plt.ylabel('各情绪种类的弹幕数量',
           labelpad=-40,  #调整y轴标签与y轴的距离
           y=1.02,  #调整y轴标签的上下位置
           rotation=0)
plt.xticks(range(2),['积极','消极'])
plt.show()

绘制得到积极弹幕数量和消极弹幕数量对比图如下:

         可以发现,消极的弹幕比积极地弹幕更多,部分原因是国内难以使用gpt-4,这引起了部分网友的怨言。

八、谁是弹幕发射器?

        本节统计了这近万条弹幕的虚拟id,得到了所有不同用户发送的弹幕数量,如下图所示:

         观察上图可知,第1名用户发送了35条弹幕,第2名用户发送了大概30条,依此递减,大部分用户都只发送了一条弹幕,大致是从第1200名用户开始,至第4800名用户,这三千多用户都只发送了一条弹幕。发送了35条弹幕的这位用户的弹幕内容,多为对未来的思考和担忧,可见这位用户对中国未来充满信心,又觉得中国的路还很长,足见其忧国忧民的形象。

        以上便是本条博客的全部内容了,完结,撒花~感谢观看

猜你喜欢

转载自blog.csdn.net/Z2021101258/article/details/130149319