B站弹幕爬取与数据分析
一、项目背景
在互联网时代,用户生成内容(UGC)成为了研究社交行为和文化趋势的重要数据来源。B站(哔哩哔哩)作为一个主要的弹幕视频分享平台,聚集了大量的用户评论和互动数据。弹幕作为一种实时的用户反馈形式,具有即时性和高互动性的特点,为数据分析提供了丰富的素材。本项目旨在通过爬取B站上一个关于萝卜快跑无人驾驶汽车的视频弹幕数据,进行数据分析,挖掘用户的评论内容和行为模式。
二、项目目标
- 弹幕数据爬取:使用Python编写爬虫程序,从指定视频中获取用户发布的弹幕数据。
- 数据清洗与预处理:对爬取到的弹幕数据进行清洗和预处理,去除无效信息。
- 数据分析:对弹幕数据进行词频统计、情感分析等,揭示用户的评论热点和情感倾向。
- 结果可视化:通过词云图和情感分布图等可视化手段展示分析结果。
三、项目文件
本项目包括以下主要文件:
danmu_crawler.py
: 爬取弹幕数据的Python脚本。data_cleaning.py
: 数据清洗与预处理脚本。word_frequency.py
: 分词和词频统计脚本。wordcloud.py
: 生成词云图的脚本。sentiment_analysis.py
: 进行情感分析的脚本。sentiment_distribution.py
: 生成情感分布图的脚本。
四、使用说明
环境配置
pip install requests pandas jieba snownlp pyecharts
- 确保安装了Python 3.x版本。
- 安装必要的依赖库:
requests
、pandas
、jieba
、snownlp
、pyecharts
。
五、技术细节
(一)弹幕爬取
1. 源码
运行 danmu_crawler.py
脚本,根据提示输入视频的oid、开始时间、结束时间和Cookie信息,爬取指定时间范围内的视频弹幕数据并保存到本地文本文件。(如何找到视频oid和cookie将放在文末)
import re
import requests
import pandas as pd
import time
from tqdm import trange
HEADERS_TEMPLATE = {
"origin": "https://www.bilibili.com",
"user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36"
}
# 获取弹幕URL的函数
def get_danmu_urls(oid, start, end):
"""
获取指定日期范围内的弹幕URL列表
oid: 视频的唯一标识符
start: 开始日期
end: 结束日期
return: 弹幕URL列表
"""
date_list = pd.date_range(start, end).strftime('%Y-%m-%d').tolist()
url_list = [
f"https://api.bilibili.com/x/v2/dm/web/history/seg.so?type=1&oid={oid}&date={date}"
for date in date_list
]
return url_list
# 解析弹幕文件的函数
def parse_so_file(filepath):
"""
解析 .so 文件并提取弹幕内容
filepath: .so文件路径
return: 弹幕内容列表
"""
with open(filepath, 'rb') as file:
data = file.read()
text = data.decode('utf-8', errors='ignore')
danmu_list = re.findall(r':(.*?)@', text) # 利用正则表达式提取so文件的弹幕内容
return danmu_list
# 下载并解析弹幕的函数
def download_and_parse_danmu(url_list, headers):
"""
下载弹幕文件并解析为文本
url_list: 弹幕文件URL列表
headers: HTTP请求头
return: 所有弹幕内容的列表
"""
danmakus = []
for i in trange(len(url_list)): # 显示进度条
url = url_list[i]
response = requests.get(url, headers=headers)
so_filepath = f"danmu_{i}.so"
with open(so_filepath, 'wb') as so_file:
so_file.write(response.content)
danmu_list = parse_so_file(so_filepath)
danmakus.extend(danmu_list)
time.sleep(2)
return danmakus
# 保存弹幕到文本文件的函数
def save_danmu_to_file(danmakus, filename):
"""
将弹幕内容保存到本地文本文件
danmakus: 弹幕内容列表
filename: 保存文件的名称
"""
with open(f"{filename}.txt", 'w', encoding='utf-8') as file:
for danmu in danmakus:
file.write(danmu + '\n')
print(f"{filename}.txt 已生成")
# 主函数
def main():
print("=" * 30)
print("请先按照本项目最后cookie及oid获取方式获取你的cookie和对应视频oid")
print("=" * 30)
print("请按照下面提示输入需要爬取的弹幕时间,建议不要超过最近两个月")
print("=" * 30)
start = input("请输入弹幕开始时间,格式年-月-日,例2020-09-01:")
end = input("请输入弹幕结束时间,格式年-月-日,例2020-09-20:")
cookie = input("请输入你的Cookie:")
oid = input("请输入对应视频oid:")
name = input("请输入保存文件名称:")
headers = HEADERS_TEMPLATE.copy()
headers["cookie"] = cookie
headers["referer"] = f"https://www.bilibili.com/video/BV19z421q7GM/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=5ec0bdf3923f0e72967dd9c6650e7943&oid={oid}"
print("========正在爬取弹幕=========")
url_list = get_danmu_urls(oid, start, end)
danmakus = download_and_parse_danmu(url_list, headers)
print("========正在保存弹幕文本文件========")
save_danmu_to_file(danmakus, name)
if __name__ == "__main__":
main()
2. 运行结果
我这里爬取弹幕的时间区间是2024/7/13-2024/7/21,所以最后输出了九个原始的so文件,通过对so文件进行分析并利用正则表达式提取九个文件中的弹幕内容到一个txt文件中。
爬取的SO文件内容
我们不难发现弹幕内容在:和@之间,所以我们用正则表达式很轻松的就能提取出来,但是里边有很多无关的内容,我们将在下一步数据清洗时去掉无关内容。
提取的弹幕内容
(二) 数据清洗
1. 源码
运行 data_cleaning.py
脚本,对爬取到的弹幕数据进行清洗,去除无效内容并保存为新的文本文件。
import re
def clean_danmu_content(danmakus):
"""
清洗弹幕内容,去除每行前面的无效内容
:param danmakus: 弹幕内容列表
:return: 清洗后的弹幕内容列表
"""
cleaned_danmakus = []
for danmu in danmakus:
# 去除每行前面的无效内容,只保留中文字符、英文字符、数字和标点符号
danmu = re.sub(r'^[^\u4e00-\u9fa5a-zA-Z0-9,。!?、;:‘’“”()【】《》]*', '', danmu)
# 去除空白行
if danmu.strip():
cleaned_danmakus.append(danmu.strip())
return cleaned_danmakus
def read_danmu_file(file_path):
"""
读取弹幕文件内容
:param file_path: 文件路径
:return: 弹幕内容列表
"""
with open(file_path, 'r', encoding='utf-8') as file:
return file.readlines()
def write_danmu_file(file_path, danmakus):
"""
将弹幕内容写入文件
:param file_path: 文件路径
:param danmakus: 弹幕内容列表
"""
with open(file_path, 'w', encoding='utf-8') as file:
for danmu in danmakus:
file.write(danmu + '\n')
def main():
# 读取原始弹幕内容文件
input_file_path = '弹幕内容.txt'
output_file_path = 'clean弹幕内容.txt'
danmakus = read_danmu_file(input_file_path)
print("========原始弹幕内容========")
for danmu in danmakus[:10]: # 打印前10条原始弹幕
print(danmu.strip())
# 清洗弹幕内容
cleaned_danmakus = clean_danmu_content(danmakus)
print("\n========清洗后的弹幕内容========")
for danmu in cleaned_danmakus[:10]: # 打印前10条清洗后的弹幕
print(danmu)
# 将清洗后的弹幕内容写入新文件
write_danmu_file(output_file_path, cleaned_danmakus)
print(f"\n清洗后的弹幕内容已保存到 {output_file_path}")
if __name__ == "__main__":
main()
2. 运行结果
上面代码将生成一个叫'clean弹幕内容'的一个文件,但是这个数据清洗还是做的不到位,因为在每个弹幕内容前面有的还有一些无关紧要的数字或者字母。
数据清洗后的txt文件
(三)分词和词频统计
1. 源码
运行 word_frequency.py
脚本,对清洗后的弹幕数据进行分词和词频统计,并将结果保存为CSV文件。此脚本包括三部分任务,一是删除txt文件中的常用中文词汇如那么、他们、不管等,以尽量消除对生成的词云图的影响。第二是利用结巴分词对弹幕内容进行分词。第三是进行词频统计。
# coding=utf-8
import time
import jieba
import re
from collections import Counter
# 停用词文件路径
stopwords_path = 'cn_stopwords.txt'
# 读取停用词
with open(stopwords_path, 'r', encoding='utf-8') as f:
stop_words = set([line.strip() for line in f])
#------------------------------------中文分词------------------------------------
# Output file for segmented words
output_file = 'C-class-fenci.txt'
with open(output_file, 'w', encoding='utf-8') as f:
# Input file
input_file = 'clean弹幕内容.txt'
for line in open(input_file, encoding='utf-8'):
line = line.strip('\n') # Ensure line.strip() affects line
seg_list = jieba.cut(line, cut_all=False)
# 过滤掉停用词
seg_list_filtered = [word for word in seg_list if word not in stop_words]
cut_words = " ".join(seg_list_filtered)
f.write(cut_words + "\n") # Ensure each line is written separately
# 为了词频统计,我们需要把所有分词结果合并在一起
with open(output_file, 'r', encoding='utf-8') as f:
all_words = f.read().split()
# 输出结果
print(all_words)
# 词频统计
c = Counter()
for x in all_words:
if len(x) > 1 and x != '\r\n':
c[x] += 1
# 输出词频最高的前10个词
print('\n词频统计结果:')
for (k, v) in c.most_common(10):
print("%s:%d" % (k, v))
# 存储数据
name = time.strftime("%Y-%m-%d") + "-fc.csv"
with open(name, 'w', encoding='utf-8') as fw:
i = 1
for (k, v) in c.most_common(len(c)):
fw.write(str(i) + ',' + str(k) + ',' + str(v) + '\n')
i = i + 1
print("Over write file!")
2. 运行结果
输出包括两个文件一个是分词后的文件“C-class-fenci.txt”和词频统计文件“2024-07-21-fc.csv”。(注意:停用词库可以在网上寻找下载)
分词后的txt文件
词频统计csv文件
(四)生成词云图
1. 源码
运行 wordcloud.py
脚本,使用词频统计结果生成词云图并保存为HTML文件。(注意:这里使用的是pyecharts库生成的词云图,请确保安装该库)
import pandas as pd
from pyecharts.charts import WordCloud
from pyecharts import options as opts
# 指定列名
column_names = ['SerialNumber', 'Content', 'Frequency']
# 步骤2:读取CSV文件,并指定列名
df = pd.read_csv('2024-07-21-fc.csv', header=None, names=column_names)
# 步骤3:筛选前80条数据
top80 = df.iloc[0:80]
# 步骤4:生成词云数据
# 确保频率列中的数据是有效的整数
word_freq = []
for index, row in top80.iterrows():
content, frequency = row['Content'], str(row['Frequency']) # 将频率转换为字符串
if frequency.isdigit(): # 检查字符串是否只包含数字
word_freq.append((content, int(frequency))) # 添加到词云数据列表
# 步骤5:使用pyecharts生成词云图
wordcloud = (
WordCloud()
.add("", word_freq, word_size_range=[20, 100], shape='circle')
.set_global_opts(title_opts=opts.TitleOpts(title="Word Cloud"))
)
# 步骤6:渲染和保存词云图
wordcloud.render('wordcloud.html') # 保存为HTML文件
2. 运行结果
词云图
3. 数据分析:
通过对B站弹幕数据进行词频统计,我们可以获得用户在讨论萝卜快跑五人驾驶汽车视频时最常提到的词汇。这些词汇反映了用户关注的热点话题和主要观点。以下是对前100个高频词汇的分析 。
(1)前100高频词
词频统计表
(2)词频统计分析详解
① 交通与职业相关
- 出租车(713次) :作为讨论的主要对象,高频出现的“出租车”一词反映了用户对传统出租车行业的关注。用户可能在讨论无人驾驶技术如何影响现有的出租车服务,或者比较无人驾驶与传统出租车的优劣。
- 司机(615次) :与“无人驾驶”对比,用户可能在探讨司机职业的未来,讨论中包括担忧和期待,例如无人驾驶是否会完全取代人类司机,以及司机转型的可能性。
- 网约车(425次) :讨论无人驾驶技术对网约车行业的影响,用户可能在讨论无人驾驶网约车的优缺点,和传统网约车的对比。
- 外卖(288次) :这可能涉及无人驾驶在外卖配送中的应用,用户在探讨无人驾驶是否会应用于外卖行业,及其可能带来的影响。
- 就业(144次) 、失业(192次) :用户对无人驾驶技术对就业市场的影响表示担忧,特别是对驾驶员等相关岗位的失业问题。
② 技术与公司
- 无人驾驶(551次) 、无人(283次) 、人工智能(80次) :这些词汇表明用户对无人驾驶技术及其背后的AI技术有着浓厚的兴趣,讨论中可能包括技术原理、发展现状和未来前景。
- 苹果(199次) 、特斯拉(197次) 、华为(69次) :用户讨论不同科技公司在无人驾驶领域的进展和竞争。例如,苹果和特斯拉作为领先的科技公司,其在无人驾驶领域的成就和动向引起了广泛关注。
③ 担忧与反对
- 没有(351次) 、问题(286次) 、不能(143次) :用户对无人驾驶技术的现存问题和局限性进行了讨论,可能包括技术上的瓶颈、安全隐患和政策法规等方面的挑战。
- 取代(258次) 、淘汰(118次) :反映了用户对无人驾驶技术可能取代现有工作岗位的担忧。
- 失业(192次) 、泡面(141次) :可能是对失业问题的调侃,表达了对未来生活的不确定性和担忧。
④ 前景与期望
- 需要(250次) 、进步(193次) 、发展(189次) 、市场(188次) :用户讨论无人驾驶技术的发展需求和市场前景,可能包括对政策支持、技术创新和市场需求的讨论。
- 便宜(173次) 、价格(96次) :用户期待无人驾驶技术能够降低出行成本,提高运输服务的性价比。
- 安全(91次) :安全性是用户关注的重点,讨论中可能包括无人驾驶技术如何保证乘客和行人的安全。
⑤ 情感与态度
- 可能(255次) 、真的(132次) 、完全(110次) :用户对无人驾驶技术的可行性和可靠性进行了探讨,表达了各种观点。
- 确实(178次) 、肯定(108次) 、支持(86次) :一些用户对无人驾驶技术表示认可和支持,认为其未来具有广阔前景。
- 根本(70次) 、不好(61次) :部分用户对无人驾驶技术表示质疑和否定,认为其在某些方面存在不可逾越的障碍。
⑥ 具体案例分析
- 偷换概念(153次) :可能是用户在讨论中遇到的误导性言论或错误观点,并对此进行了反驳。例如,一些用户可能认为将无人驾驶与人类司机的优势进行对比时,存在偷换概念的现象。
- 萝卜(153次) :特指萝卜快跑这个品牌或技术,用户可能在讨论其在无人驾驶领域的应用和表现。
- 滴滴(100次) :作为网约车行业的代表,用户可能在讨论滴滴在无人驾驶技术中的表现和未来,或将其与其他无人驾驶技术进行比较。
⑦ 地域与文化
- 重庆(104次) :讨论视频或弹幕中提到的特定城市,该城市在无人驾驶技术方面的进展。萝卜快跑首先在重庆运营,重庆作为中国西南地区的一个大城市,在无人驾驶技术的应用上有一些独特的实践和案例。
- 中国(68次) 、美国(64次) :讨论中涉及不同国家在无人驾驶技术领域的竞争和发展,用户可能在比较中美两国在该领域的技术水平和政策支持。
总结
用户对无人驾驶技术的讨论涵盖了技术发展、就业影响、安全性、市场前景等多个方面。从高频词汇中可以看出,用户既有对新技术的期待和支持,也有对其潜在问题和负面影响的担忧。这些讨论反映了公众对无人驾驶技术的复杂态度和多元化观点。
(五)情感分析/生成情感分布图
1.源码
运行 sentiment_analysis.py
脚本和 sentiment_distribution.py
脚本,对弹幕数据进行情感分析,计算平均情感分数并保存分析结果,生成情感分布图并保存为HTML文件。
from snownlp import SnowNLP
def read_danmu_file(file_path):
"""读取弹幕内容文件"""
with open(file_path, 'r', encoding='utf-8') as file:
return file.readlines()
def analyze_sentiment(danmakus):
"""分析弹幕的情感"""
sentiments = [SnowNLP(danmu).sentiments for danmu in danmakus]
return sentiments
def main():
input_file_path = 'clean弹幕内容.txt'
danmakus = read_danmu_file(input_file_path)
# 进行情感分析
sentiments = analyze_sentiment(danmakus)
average_sentiment = sum(sentiments) / len(sentiments)
print(f"所有弹幕的平均情感分数是: {average_sentiment:.2f}")
# 保存结果到文件(可选)
with open('sentiment_analysis_results.txt', 'w', encoding='utf-8') as file:
file.write(f"所有弹幕的平均情感分数是: {average_sentiment:.2f}\n")
file.write("\n弹幕情感分数如下:\n")
for idx, sentiment in enumerate(sentiments):
file.write(f"弹幕 {idx + 1}: {sentiment:.2f}\n")
print("情感分析结果已保存到 sentiment_analysis_results.txt")
if __name__ == "__main__":
main()
from pyecharts import options as opts
from pyecharts.charts import Bar
from snownlp import SnowNLP
def read_danmu_file(file_path):
"""读取弹幕内容文件"""
with open(file_path, 'r', encoding='utf-8') as file:
return file.readlines()
def analyze_sentiment(danmakus):
"""分析弹幕的情感"""
sentiments = [SnowNLP(danmu).sentiments for danmu in danmakus]
return sentiments
def generate_sentiment_distribution_chart(sentiments):
"""生成情感分布图"""
sentiment_bins = [0, 0.2, 0.4, 0.6, 0.8, 1]
sentiment_labels = ['非常负面', '负面', '中性', '正面', '非常正面']
# 计算每个区间的频次
sentiment_counts = [0] * (len(sentiment_bins) - 1)
for sentiment in sentiments:
for i in range(len(sentiment_bins) - 1):
if sentiment_bins[i] <= sentiment < sentiment_bins[i + 1]:
sentiment_counts[i] += 1
break
bar = Bar()
bar.add_xaxis(sentiment_labels)
bar.add_yaxis('情感分布', sentiment_counts)
bar.set_global_opts(
title_opts=opts.TitleOpts(title="弹幕情感分布图"),
xaxis_opts=opts.AxisOpts(name="情感倾向"),
yaxis_opts=opts.AxisOpts(name="弹幕数量")
)
return bar
def main():
input_file_path = 'clean弹幕内容.txt'
sentiment_chart_path = 'sentiment_distribution.html'
# 读取弹幕内容
danmakus = read_danmu_file(input_file_path)
# 情感分析
sentiments = analyze_sentiment(danmakus)
# 生成情感分布图
sentiment_chart = generate_sentiment_distribution_chart(sentiments)
sentiment_chart.render(sentiment_chart_path)
if __name__ == "__main__":
main()
2. 运行结果
每条弹幕的情感倾向
情感分布图
3. 数据分析
(1)数据
在我们爬取并分析的弹幕数据中,涉及到无人驾驶技术的视频评论具有丰富的情感表现。以下是弹幕的情感分类及其平均情感分数:
平均情感分数 | 0.49 |
非常负面 | 1982 |
负面 | 1517 |
中性 | 1845 |
正面 | 1423 |
非常正面 | 1838 |
(2)情感分布与总体趋势
从情感分布来看,弹幕情感呈现多样化,但整体略偏向负面:
- 负面情感(非常负面 + 负面):3499条
- 中性情感:1845条
- 正面情感(正面 + 非常正面):3261条
平均情感分数为0.49,接近中性,但略偏负面。这表明用户对无人驾驶技术有较多的担忧和负面情绪,尽管也有不少正面的评价和期待。
(3)负面情感分析
- 非常负面(1982条) :高度负面的评论可能包含对无人驾驶技术的强烈批评和不满,反映出用户对技术的不信任或对其带来负面影响的强烈担忧。这些评论可能涉及到安全隐患、失业问题以及技术失败等。
- 负面(1517条) :负面评论则可能表达了用户的质疑和不安。例如,对无人驾驶技术的现状不满意,认为其在短期内难以成熟应用,或对其可能导致的社会问题表示担忧。
(4)中性情感分析
- 中性(1845条) :中性的评论往往是描述性和客观性的,用户可能在讨论无人驾驶技术的现状、原理、具体应用等,而不带有明显的情感倾向。这些评论对了解用户的理性分析和中立观点非常有价值。
(5)正面情感分析
- 正面(1423条) :正面评论反映了用户对无人驾驶技术的认可和期待。用户可能赞赏技术的先进性、对未来生活的便利性及其在解决当前交通问题上的潜力。
- 非常正面(1838条) :高度正面的评论可能表达了用户的强烈支持和乐观态度。例如,认为无人驾驶技术将带来革命性的变化,彻底改变交通和出行方式,提高生活质量。
(6)具体情感案例
结合词频统计数据,可以更深入地理解用户情感:
- 担忧与批评:高频出现的“问题”、“不能”、“取代”、“失业”、“泡面”等词汇与负面情感相关,用户对无人驾驶技术可能带来的社会问题和技术不成熟表示担忧和批评。
- 中立讨论:词汇如“现在”、“技术”、“市场”、“价格”等,与中性情感相关,用户在进行客观的技术讨论和市场分析。
- 支持与期待:高频出现的“进步”、“发展”、“便宜”、“安全”等词汇,与正面情感相关,用户对无人驾驶技术的进步、安全性和未来应用充满期待和支持。
(7)总结
通过情感分析,可以看出用户对无人驾驶技术的态度复杂且多样。尽管整体情感略偏负面,但中立和正面的评论也占据了很大比例。负面情感主要源自对技术不成熟、潜在安全问题及其对就业市场影响的担忧。而正面情感则集中在对技术进步的认可和对未来便利生活的期待。
这种情感分布反映了无人驾驶技术作为一项前沿技术,既带来了巨大的发展潜力,也引发了广泛的社会讨论和情感波动。对于相关企业和研究机构,这些情感分析提供了宝贵的用户反馈,有助于了解公众的关注点和疑虑,从而更好地推进技术研发和市场推广。
六、关于oid和Cookie的获取
(一)oid
首先,我们用chrome浏览器打开B站官网,搜索萝卜快跑,点击一个视频。进入之后按F12或者CTRL+SHIFT+i进入开发者工具。步骤:点击Network、点击弹幕列表、点击seg.so的数据包
编辑
打开后在headers页面我们可以找到requests url,里面就有我们所需要的oid
编辑
(二)Cookie和user-agent
在上一步中我们往下滑就可以找到cookie和user-agent
编辑
七、贡献指南
本人是一名普通的在校本科生,暑假闲来无事自学做此项目,总体来说项目本身较为稚嫩,功能也不是很完善。我十分欢迎大家对本项目提出建议和意见。如果你发现了bug或有新的功能需求,请联系我进行反馈。也欢迎大家提交pull request,共同完善本项目。代码后续也会在GitHub上提交。
标签:无人驾驶,danmakus,情感,爬取,danmu,file,哔哩,弹幕 From: https://www.cnblogs.com/chen-chen-ya-ya/p/18316678