bilibili弹幕情感分析

在这里插入图片描述

项目背景

随着短视频平台的快速发展,用户的互动行为(如评论、弹幕)已成为衡量视频内容受欢迎程度和观众情感的重要指标之一。在这些互动中,观众的情感倾向(积极、消极或中立)对于视频创作者和营销人员具有重要的分析价值。特别是Bilibili这一平台,以其独特的弹幕文化,吸引了大量年轻观众参与讨论与互动,弹幕成为了表达观众情感的重要方式。

本项目旨在对Bilibili视频的弹幕数据进行情感分析,探讨观众情感随视频播放进度的变化趋势。我选择了一段关于可爱小猫的视频,并爬取了视频的弹幕数据,包括弹幕的时间戳、内容、情感得分等信息。通过分析这些数据希望能够深入了解视频内容与观众情感之间的关系,并为未来的内容创作和数据分析提供新的见解和方法。

获取数据

利用python编写爬虫爬取数据和解析数据存储到csv文件

1、获取弹幕cid

import requests
import xml.etree.ElementTree as ET
import pandas as pd

## 根据视频bvid去获取cid
def get_cid_from_bvid(bvid):
    url = f"https://api.bilibili.com/x/web-interface/view?bvid={bvid}"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
        "Referer": f"https://www.bilibili.com/video/{bvid}"
    }
    response = requests.get(url, headers=headers)
    
    if response.status_code == 200:
        data = response.json()
        if data["code"] == 0 and "cid" in data["data"]:
            return data["data"]["cid"]
        else:
            print("API 返回异常:", data)
    else:
        print("请求失败,状态码:", response.status_code)
    return None
2、获取弹幕
def get_bilibili_danmaku(cid):   
    url = f"https://comment.bilibili.com/{cid}.xml"    #f前缀代表格式化字符串,里面可以包含{cid}这种占位符,使其之后能被替换
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
    }
    response = requests.get(url,headers=headers)
    if response.status_code == 200:
        return response.content
    else:
        print(f"Error accessing the API. Status Code: {response.status_code}")
    return None
3、解析弹幕
def parse_danmaku(xml_content):
    root = ET.fromstring(xml_content)    #解析xml格式的字符串
    danmaku_list = []
    # 遍历每个 <d> 标签
    for d in root.findall('d'):
        p_attrs = d.attrib['p'].split(',')
        time_sec = float(p_attrs[0])
        danmaku_type = int(p_attrs[1])
        font_size = int(p_attrs[2])
        color = f"#{int(p_attrs[3]):06X}"
        timestamp = p_attrs[4]
        user_id = p_attrs[6]
        danmaku_text = d.text
        danmaku_list.append({
                '时间': time_sec,
                '弹幕类型':danmaku_type,
                '弹幕': danmaku_text,
                '字体':font_size,
                '颜色':color,
                '时间戳': timestamp,
                '用户id':user_id,
            })
    return danmaku_list

4、存储弹幕数据

def save_danmaku_to_csv(danmaku_list, filename):    
    df = pd.DataFrame(danmaku_list)
    df.to_csv(filename, index=False)

分析数据

使用sonwnlp作为情感分析库,把用户情绪分为积极、消极和中立三种状态,试着查看弹幕情绪是否会随一天中不同时间段情绪发生变化
import pandas as pd
df = pd.read_csv('danmuku.csv')
df.head()
时间弹幕类型弹幕字体颜色时间戳用户id
00.6415这猫很贵吗?为什么只买一点点25#E7001216434623888a6973e
192.1525说了多少次猪不能染色(生气)25#E700121643380116aad8c8bd
231.0165它好像知道自己很可爱25#FFFFFF16438939671ace8411
37.2425那个小黑点是人家的修皮燕儿25#E700121643528090b9026e56
420.3155《猫猫虫》25#E700121643462540ecd1c9ba
df['日期']=pd.to_datetime(df['时间戳'],unit='s')
df.head()
时间弹幕类型弹幕字体颜色时间戳用户id日期
00.6415这猫很贵吗?为什么只买一点点25#E7001216434623888a6973e2022-01-29 13:19:48
192.1525说了多少次猪不能染色(生气)25#E700121643380116aad8c8bd2022-01-28 14:28:36
231.0165它好像知道自己很可爱25#FFFFFF16438939671ace84112022-02-03 13:12:47
37.2425那个小黑点是人家的修皮燕儿25#E700121643528090b9026e562022-01-30 07:34:50
420.3155《猫猫虫》25#E700121643462540ecd1c9ba2022-01-29 13:22:20
df = df[['用户id','弹幕','日期','时间']]
df.head()
用户id弹幕日期时间
08a6973e这猫很贵吗?为什么只买一点点2022-01-29 13:19:480.641
1aad8c8bd说了多少次猪不能染色(生气)2022-01-28 14:28:3692.152
21ace8411它好像知道自己很可爱2022-02-03 13:12:4731.016
3b9026e56那个小黑点是人家的修皮燕儿2022-01-30 07:34:507.242
4ecd1c9ba《猫猫虫》2022-01-29 13:22:2020.315
import matplotlib.pyplot as plt
from snownlp import SnowNLP
df['情感得分']=df['弹幕'].apply(lambda x: SnowNLP(x).sentiments)
df.head()
用户id弹幕日期时间情感得分
08a6973e这猫很贵吗?为什么只买一点点2022-01-29 13:19:480.6410.566113
1aad8c8bd说了多少次猪不能染色(生气)2022-01-28 14:28:3692.1520.274234
21ace8411它好像知道自己很可爱2022-02-03 13:12:4731.0160.843694
3b9026e56那个小黑点是人家的修皮燕儿2022-01-30 07:34:507.2420.508325
4ecd1c9ba《猫猫虫》2022-01-29 13:22:2020.3150.660834
#根据得分分类
def classify_sentiment(score):
    if score>0.7:
        return '积极'
    elif score <0.4:
        return '消极'
    else:
        return '中立'
df['情感']=df['情感得分'].apply(lambda x: classify_sentiment(x))
df.head()
用户id弹幕日期时间情感得分情感
08a6973e这猫很贵吗?为什么只买一点点2022-01-29 13:19:480.6410.566113中立
1aad8c8bd说了多少次猪不能染色(生气)2022-01-28 14:28:3692.1520.274234消极
21ace8411它好像知道自己很可爱2022-02-03 13:12:4731.0160.843694积极
3b9026e56那个小黑点是人家的修皮燕儿2022-01-30 07:34:507.2420.508325中立
4ecd1c9ba《猫猫虫》2022-01-29 13:22:2020.3150.660834中立
from matplotlib import rcParams

# 设置中文字体,SimHei 是黑体,适用于大多数 Windows 系统
rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体
rcParams['axes.unicode_minus'] = False    # 正常显示负号

# 统计情感分类的数量
sentiment_counts = df['情感'].value_counts()

# 扇形图绘制
labels = sentiment_counts.index
sizes = sentiment_counts.values
colors = ['#66b3ff', '#99ff99', '#ff6666']  # 分别代表积极、中立、消极
explode = (0, 0.1, 0)  # 突出显示“积极”部分

plt.pie(sizes, explode=explode, labels=labels, colors=colors,
        autopct='%1.1f%%', shadow=True, startangle=140)
plt.axis('equal')  # 保证饼图是圆形的
plt.title('用户情感比例')
plt.show()

在这里插入图片描述

# 将弹幕按视频时间每30s区分时间段 
df['时间段']=df['时间']//30+1
df.head()
用户id弹幕日期时间情感得分情感时间段
08a6973e这猫很贵吗?为什么只买一点点2022-01-29 13:19:480.6410.566113中立1.0
1aad8c8bd说了多少次猪不能染色(生气)2022-01-28 14:28:3692.1520.274234消极4.0
21ace8411它好像知道自己很可爱2022-02-03 13:12:4731.0160.843694积极2.0
3b9026e56那个小黑点是人家的修皮燕儿2022-01-30 07:34:507.2420.508325中立1.0
4ecd1c9ba《猫猫虫》2022-01-29 13:22:2020.3150.660834中立1.0
# 计算每个时间段的平均情感得分和数量
sentiment_by_time = df.groupby('时间段')['情感得分'].describe().reset_index()
sentiment_by_time
时间段countmeanstdmin25%50%75%max
01.0433.00.6229720.2302117.797457e-080.4835170.6608340.7966240.999970
12.0247.00.6223500.2754366.285078e-020.3986330.6122230.8843000.999997
23.0236.00.5834310.2741452.215580e-030.4102900.5906730.8210060.999999
34.0178.00.5902210.2693703.095113e-030.3969080.5698210.8282481.000000
45.097.00.5795210.2492132.450946e-020.4329850.5262330.8431380.999127
56.09.00.5342440.1120694.218746e-010.5000000.5000000.5262330.770679
# 显示情感得分随时间变化的趋势
fig, ax1 = plt.subplots()
# 绘制平均情感得分变化趋势线
ax1.plot(sentiment_by_time['时间段'],sentiment_by_time['mean'],'g-')
ax1.set_xlabel('时间段(秒)')
ax1.set_ylabel('平均情感得分',color='g')

# 创建第二个坐标系
ax2 = ax1.twinx()  # 共享x轴
# 绘制第二条线
ax2.plot(sentiment_by_time['时间段'],sentiment_by_time['count'],'b-')
ax2.set_ylabel('弹幕数量',color='b')

plt.title('情感得分和弹幕数量随视频时间变化趋势')
plt.show()

在这里插入图片描述

数据分析与推论:

视频内容的节奏变化原因:视频通过不同的情节或者节奏变化,导致观众情感的波动。随着视频进度,从折线图中发现观众情绪和弹幕数量下降,对比视频,发现视频通过开头的可爱小猫吸引观众眼球,观众的情感会较为积极,接着若视频进入较为平淡的部分,情感得分开始下降。

import jieba
from wordcloud import WordCloud
import matplotlib.pyplot as plt
from collections import Counter

# 预处理:将所有弹幕文本分词
df['分词'] = df['弹幕'].apply(lambda x: ' '.join(jieba.cut(x)))

# 分组:按情感分类,合并文本
sentiment_groups = df.groupby('情感')['分词'].apply(' '.join)

# 生成词云的函数
def generate_wordcloud(text, title, save_path=None):
    wordcloud = WordCloud(
        font_path='C:/Windows/Fonts/simhei.ttf',
        width=800,
        height=400,
        background_color='white',
        max_words=100
    ).generate(text)

    plt.figure(figsize=(8, 4))
    plt.imshow(wordcloud, interpolation='bilinear')
    plt.axis('off')
    plt.title(title)

    if save_path:
        plt.savefig(save_path)  # 保存到文件
    else:
        plt.show()  # 显示词云

# 遍历每个情感类别生成词云
for sentiment, sentiment_text in sentiment_groups.items():
    generate_wordcloud(sentiment_text, f'{sentiment} 情感下的高频词词云')

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数据分析与推论:

在情感分析过程中词云图中出现与情感分类不匹配的词汇(如中立情感中出现“可爱”等积极词,消极情感中出现“卡哇伊”这种积极词)

df['hour'] = df['日期'].dt.hour  # 提取小时部分

# 计算每小时各情绪的数量
emotion_counts = df.groupby(['hour', '情感']).size().unstack().fillna(0)

# 绘制折线图
plt.figure(figsize=(10, 6))
for emotion in emotion_counts.columns:
    plt.plot(emotion_counts.index, emotion_counts[emotion], label=emotion)

plt.xlabel('时间(小时)')
plt.ylabel('情绪数量')
plt.title('一天中不同时间段的情绪变化')
plt.legend(title='情绪')
plt.grid(True)
plt.show()

在这里插入图片描述

数据分析与推论:

中午时段通常是许多人休息的时间,尤其是对于上班族或学生来说,他们可能会在午餐时间观看视频,因此中午时段的观众活跃度较高,导致弹幕数量增多。

结论

  • 视频制作者通常通过增强视频开头的吸引力去吸引观众,但为了保持更好的视频质量,同时应该在视频的中后部分设计一些转折点或情节高潮。例如,加入小猫的突发行为、令人捧腹的互动或感人的情节
  • 可以尝试更换情感分析模型或尝试通过手动校正某些词的情感类别来提高准确性,后期可以试着从多个角度入手:改进情感分析模型、调整分词和情感分类规则、去除歧义词汇,并结合上下文进行更加精细化的分析。通过这些手段,可以提高情感分析的准确性,从而生成更加符合情感分类的词云图。
  • 由于中午时间段是观众互动的高峰期,视频制作者可以考虑在此时间段发布视频或推广已有视频,以便最大化观众参与度。特别是在观众的情感得分较为积极的时段发布视频,可以进一步提升观众的情感共鸣和互动积极性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值