数分实战——Python爬取视频弹幕,并进行数据分析+情感分析(SnowNLP)

本项目将使用Python爬取并分析某关于美国关税问题的解说视频的弹幕,该视频弹幕目前已填充6000+条,并将数据记录于mysql数据库中,以进行数据分析、数据挖掘、情绪分类等等。 这是我的思维导图,以理清思路:

正文开始!

一、利用Python爬取弹幕

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

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

python 复制代码
import requests
from bs4 import BeautifulSoup

# 设置请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.35 Safari/537.36'
}
url = "https://comment.bilibili.com/29347548183.xml"
response = requests.get(url, headers=headers)
response.encoding='utf8' #编码方式
html = response.text
soup = BeautifulSoup(html,'xml') #使用beautifulsoup库快速查找我们想要的信息
all_txt = soup.find_all("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)

输出结果如下:

二、词云图

代码如下:

python 复制代码
import jieba #导入jieba库
from wordcloud import WordCloud
import matplotlib.pyplot as plt
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(
    height=1000,
    width=1000,
    font_path='simsun.ttc',
    background_color = 'white'
)#利用wordcloud库定义词云图片的信息
wc.generate(' '.join(words))   #生成图片
print(wc)
plt.imshow(wc,interpolation='bilinear')
plt.axis('off')
plt.show()

运行结果如下:

还可以生成弹幕云图,代码如下:

python 复制代码
# 句子云图
# danmustr=''.join(i for i in txtsss) #将所有弹幕拼接在一起
# words=list(jieba.cut(danmustr))  #利用jieba库将弹幕按词进行切分
txtsss=[i for i in txtsss if len(i)>=2] 
wc=WordCloud(
    height=500,
    width=500,
    font_path='simsun.ttc',
    background_color = 'white',
    max_font_size = 80,
    min_font_size = 10
)
wc.generate(' '.join(txtsss))   #生成图片
print(wc)
plt.imshow(wc,interpolation='bilinear')
plt.axis('off')
plt.show()

结果如下:

三、将数据导入到MySQL中

代码如下:

python 复制代码
import pandas as pd  #用到了map()
from datetime import datetime
from sqlalchemy import  create_engine,text
from urllib.parse import quote_plus #处理URL编码

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["date"] = pg['danmu_ture_time'].dt.date
pg["time"] = pg['danmu_ture_time'].dt.time

# 数据库连接配置
username = 'your_username'
password = 'your_password'
host = 'your_host'
port = 3306
database = 'your_database'

# 对密码进行 URL 编码
encoded_password = quote_plus(password)

# 构建连接字符串
# 创建一个数据库引擎对象,负责管理数据库连接池、处理数据库连接、执行 SQL 语句等操作
connection_string = f'mysql+pymysql://{username}:{encoded_password}@{host}:{port}/{database}'
engine=create_engine(connection_string) #利用sqlalchemy库建立mysql的引擎
rows_written = pg.to_sql(name='tariff',con=engine,index=False,if_exists='replace')
print(f"成功写入{rows_written}行数据到数据库。")

填入你自己的数据库信息,代码中连接数据库部分还可以直接写成:

ini 复制代码
engine = create_engine('mysql+pymysql://username:[email protected]:3306/your_database')

这样代码更少,但由于我设置密码时最后一位设置成了特殊字符@,而连接字符串有特定的格式,@ 在其中用于分隔用户名和主机地址,因此,我用较少的那行代码运行不了。于是我选择了用 URL 编码的方式来处理密码。 当结果显示

复制代码
成功写入3600行数据到数据库。

说明数据成功导入到MySQL中了,可以刷新数据库查看数据。

四、分析弹幕

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

代码如下:

python 复制代码
import matplotlib
from matplotlib import pyplot as plt
# 数据库连接配置
username = 'your_username'
password = 'your_password'
host = 'your_host'
port = 3306
database = 'your_database'

# 对密码进行 URL 编码
encoded_password = quote_plus(password)

# 构建连接字符串
connection_string = f'mysql+pymysql://{username}:{encoded_password}@{host}:{port}/{database}'
engine=create_engine(connection_string) #利用sqlalchemy库建立mysql的引擎
df=pd.read_sql(text('select * from tariff'),con=engine.connect())#从mysql数据库中查找出所有弹幕信息
list_time_happen=df["time_happen"].tolist()
list_count_time_happen=[]
for i in range(300):
    count_time_happen = 0
    for j in range(len(list_time_happen)):
        if i * 5.256 <= float(list_time_happen[j]) < (i + 1) * 5.256:
            list_time_happen[j]=i
            count_time_happen +=1
    list_count_time_happen.append(count_time_happen)
print(list_count_time_happen)

plt.rcParams['font.family']='SimHei'
plt.rcParams['font.size']=12
plt.plot(list_count_time_happen,color='g',linewidth=2,label="视频各时段的弹幕数量")
plt.xlabel("视频的各个时段,以5.256s为一个区间")
plt.ylabel('视频各个时段的弹幕数量',
           labelpad=-40,  #调整y轴标签与y轴的距离
           y=1.02,  #调整y轴标签的上下位置
           rotation=0)
plt.grid()
plt.show()

绘制得到的曲线如下:

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

代码如下:

python 复制代码
list_happen = df["time_happen"].tolist()
# 转换成浮点数
list_happen = [float(x) for x in list_happen]
time_part = [
	(0,30),
	(30,421),
	(421,925),
	(925,1535),
	(1535,1577)
]
list_part_happen = []
for i in range(5):
	count_part = 0
	for j in range(len(list_happen)):
		if time_part[i][0] <= list_happen[j] <=time_part[i][1]:
			count_part+=1
	list_part_happen.append(count_part)
print(list_part_happen)

labels = [
    "1.前言",
    "2.美国如何使用关税",
    "3.特朗普的计划",
    "4.我们怎样看待",
    "5.结尾"
]
# 创建一个包含两个子图的图形
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
# 绘制直方图
axes[0].bar(labels, list_part_happen, color='skyblue')
axes[0].set_xlabel('章节')
axes[0].set_ylabel('弹幕数量')
axes[0].set_title('各章节弹幕数量直方图')
axes[0].tick_params(axis='x', rotation=45)

# 绘制饼状图
axes[1].pie(list_part_happen, labels=labels, autopct='%1.1f%%')
axes[1].set_title("各部分弹幕数量占比饼状图")

# 调整布局
plt.tight_layout()
# 显示图形
plt.show()

结果如下:

可以看出视频第四章节:我们怎样看待,出现的弹幕最多,看来网友对我们如何看待美国加关税,我们自己的做法比较感兴趣。但是,以上两图统计的是各个章节的弹幕数量,然而各个章节的时间长短不一,比如第一节前言只有几十秒,而其他几章有十几分钟,十几分钟内出现的弹幕数量当然比几十秒内出现的弹幕更多了,因此不区分章节时间长度而进行弹幕数量比较,是不太合理的,因此本文接着统计了各大章节每秒出现的弹幕数量,得到直方图和饼状图如下:

python 复制代码
time_part = [
	(0,30),
	(30,421),
	(421,925),
	(925,1535),
	(1535,1577)
]
labels = [
    "1.前言",
    "2.美国如何使用关税",
    "3.特朗普的计划",
    "4.我们怎样看待",
    "5.结尾"
]
# 计算每个时间段的时长
durations = [end - start for start, end in time_part]
list_seconds = [list_part_happen[i]/durations[i] for i in range(5)]
print(list_seconds)
# 创建一个包含两个子图的图形
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
# 绘制直方图
axes[0].bar(labels, list_seconds, color='skyblue')
axes[0].set_xlabel('章节')
axes[0].set_ylabel('各章节每秒弹幕数量')
axes[0].set_title('各章节每秒弹幕数量直方图')
axes[0].tick_params(axis='x', rotation=45)

# 绘制饼状图
axes[1].pie(list_seconds, labels=labels, autopct='%1.1f%%')
axes[1].set_title("各章节每秒弹幕数量占比情况")

# 调整布局
plt.tight_layout()
# 显示图形
plt.show()

还有各章节时长分布图,代码相似,不再赘述。 从上述图片可以看出,最后一章节结尾的每秒弹幕数量是最多的,因为是视频的结尾,所以这是可以理解的,另外各部分弹幕数量倒是与时长成正比。

3.分析不同日期的弹幕数量

代码如下:

python 复制代码
import time
from datetime import datetime
list_time_true=df["danmu_ture_time"].tolist() #将dataframe中的时间戳列转换成列表
dt='2025-4-10 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(10):    #该视频共公布10天,因此弹幕跨度为10天
    count_time_happen = 0 #用于记录这10天每天的弹幕数量
    for j in range(len(list_time_true)):
        # 将 datetime.date 对象转换为 datetime.datetime 对象
        dt_obj = datetime.combine(list_time_true[j], datetime.min.time())
         # 获取时间戳
        timestamp = dt_obj.timestamp()
        if  i*3600*24+time_small <= timestamp < (i+1)*3600*24+time_small:
            count_time_happen += 1 #如果是当天的弹幕,则+1
    list_count_time_happen.append(count_time_happen) #将9天每天的弹幕数量记录于该列表中
print(list_count_time_happen) 
plt.rcParams['font.family']='SimHei'
plt.rcParams['font.size']=12
color=['deepskyblue']
plt.bar(range(10), list_count_time_happen,color=color,width=0.4)
plt.xlabel("发送弹幕的日期,从4月10开始,4月19结束")
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])
plt.show()

还可以用日期来求,代码如下:

python 复制代码
# 每天弹幕数量,用日期时间戳求
import time 
from datetime import datetime
list_date = df["date"].tolist()

dt = '2025-4-10 0:0:0'
time_ = time.strptime(dt,"%Y-%m-%d %H:%M:%S")
time_min = time.mktime(time_)

list_count_date = []
for i in range(10):
	count_date = 0
	for j in range(len(list_date)):
		dt_obj = datetime.combine(list_date[j], datetime.min.time())
		timestamp = dt_obj.timestamp()
		if timestamp == i*3600*24 + time_min:
			count_date += 1
	list_count_date.append(count_date)
print(list_count_date)

得到结果如下:

csharp 复制代码
[35, 354, 927, 913, 501, 277, 192, 204, 121, 76]

4.每天不同细分时间段的弹幕数量

代码如下:

python 复制代码
# 将 'danmu_ture_time' 列转换为 datetime 类型
df['danmu_ture_time'] = pd.to_datetime(df['danmu_ture_time'])

# 定义时间段
time_intervals = [(i, i + 2) for i in range(0, 24, 2)]

# 初始化每个时间段的弹幕数量计数器
count_per_interval = [0] * len(time_intervals)

# 统计每个时间段的弹幕数量
for index, row in df.iterrows():
    hour = row['danmu_ture_time'].hour
    for i, (start, end) in enumerate(time_intervals):
        if start <= hour < end:
            count_per_interval[i] += 1
            break

# 时间段标签
labels = [f'{start}:00 - {end}:00' for start, end in time_intervals]
# 设置图片清晰度
plt.rcParams['figure.dpi'] = 300
# 设置 matplotlib 支持中文
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
# 创建一个包含两个子图的图形
fig, axes = plt.subplots(1, 2, figsize=(12, 6))

# 绘制直方图
axes[0].bar(labels, count_per_interval, color='skyblue')
axes[0].set_xlabel('时间段')
axes[0].set_ylabel('弹幕数量')
axes[0].set_title('各时间段弹幕数量直方图')
axes[0].tick_params(axis='x', rotation=45)

# 绘制饼状图
axes[1].pie(count_per_interval, labels=labels, autopct='%1.1f%%')
axes[1].set_title("各时间段弹幕数量占比饼状图")

# 调整布局
plt.tight_layout()
# 显示图形
plt.show()

结果如下:

分析以上两图可知,18-24时的弹幕数量最多,晚上的休息时间比较充足,另外12-14时弹幕数量也较多,中午午休也可以抽出时间逛逛b站。2-8时的弹幕数量最小,广大网友应该还在睡觉。

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

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

python 复制代码
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']])
plt.rcParams['font.family']='SimHei'
plt.rcParams['font.size']=12
ax = sn.histplot(df['sentiment'], color='deepskyblue', kde=True, bins=20)
for line in ax.lines:
    line.set_color('orange') 
ax.set_title("特朗普关税战解说视频整体情感倾向")
plt.show()

结果如下:

从以上情感分析图可知,弹幕中有很多积极地弹幕,但同时,消极的弹幕也不少。进一步将情感评分>0.8分的弹幕选为积极弹幕,在0.8-0.4之间的选为中性2弹幕,而情感评分<=0.4的弹幕选为消极弹幕,代码如下:

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

结果如下:

可以发现,还是积极的弹幕更多一些,大家都还是比较积极的看待本次美国关税事件,当然也与博主的幽默风趣有关。

我们来看一下最积极的弹幕是什么样的~

python 复制代码
most_positive_row = df.loc[df['sentiment'].idxmax()]
most_positive_comment = most_positive_row['comment']
most_positive_score = most_positive_row['sentiment']
print(f"情感最积极的弹幕: {most_positive_comment}")
print(f"对应的分数: {most_positive_score}")

结果竟是......

makefile 复制代码
情感最积极的弹幕: 哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
对应的分数: 0.999999999986837

有点意外,但又很合理。

相关推荐
Dxy12393102162 分钟前
Pandas数据可视化
python·信息可视化·数据分析·pandas
亚图跨际3 小时前
计算方法在单细胞数据分析中的应用及AI拓展
人工智能·数据挖掘·数据分析
赵孝正3 小时前
从EOF到REOF:如何用旋转经验正交函数提升时空数据分析精度?
数据挖掘·数据分析
Miu(数分版)6 小时前
PowerBi如何制作KPI的总览页?
数据分析·powerbi
lilye666 小时前
精益数据分析(7/126):打破创业幻想,拥抱数据驱动
大数据·人工智能·数据分析
lilye6619 小时前
精益数据分析(4/126):开启数据驱动的创业之旅
人工智能·数据挖掘·数据分析
看海的四叔20 小时前
【Python】用Python写一个俄罗斯方块玩玩
开发语言·python·数据分析·游戏开发·俄罗斯方块
RunsenLIu21 小时前
基于Djiango实现中药材数据分析与可视化系统
服务器·数据库·数据分析
goodluckyaa21 小时前
Python数据可视化
python·信息可视化·数据分析