|
|
|
|
# 2.1
|
|
|
|
|
# 数据获取
|
|
|
|
|
|
|
|
|
|
# 导入必要的库
|
|
|
|
|
import requests # 用于发送HTTP请求
|
|
|
|
|
import json # 用于处理JSON数据
|
|
|
|
|
import re # 用于正则表达式匹配
|
|
|
|
|
import openpyxl # 用于操作Excel文件
|
|
|
|
|
import pandas as pd # 用于数据处理和分析
|
|
|
|
|
import matplotlib.pyplot as plt # 导入matplotlib模块pyplot函数并使用as给函数起个别名plt
|
|
|
|
|
import jieba # 导入jieba分词模块
|
|
|
|
|
import wordcloud # 导入词云图模块
|
|
|
|
|
import numpy as np # 导入numpy模块
|
|
|
|
|
from wordcloud import ImageColorGenerator # 用于从图片生成颜色以渲染词云
|
|
|
|
|
from PIL import Image # 从PIL模块中导入Image函数
|
|
|
|
|
from collections import Counter # 导入Counter类,用于计数
|
|
|
|
|
|
|
|
|
|
# 定义目标URL,用于搜索Bilibili视频
|
|
|
|
|
url = "https://api.bilibili.com/x/web-interface/wbi/search/type?page_size=50&keyword=2024%E5%B7%B4%E9%BB%8E%E5%A5%A5%E8%BF%90%E4%BC%9A&search_type=video"
|
|
|
|
|
|
|
|
|
|
# 设置请求头,模拟浏览器访问
|
|
|
|
|
headers = {
|
|
|
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 SLBrowser/9.0.3.5211 SLBChan/105"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 设置Cookies
|
|
|
|
|
cookies = {
|
|
|
|
|
"buvid3":"11680F37-E62C-C9EF-B7B2-D198332B61D003377infoc",
|
|
|
|
|
"LIVE_BUVID": "AUTO6416610696475006",
|
|
|
|
|
"rpdid": "|(u))kkYu|R~0J'uY~|)R)Ylm",
|
|
|
|
|
"header_theme_version": "CLOSE",
|
|
|
|
|
"FEED_LIVE_VERSION": "V8",
|
|
|
|
|
"buvid4": "3385D89E-82EA-B792-EDDB-1C760C74377804485-022082013-T76gCyS8edfpVC%2B%2FEm%2F9gg%3D%3D",
|
|
|
|
|
"CURRENT_FNVAL": "4048",
|
|
|
|
|
"DedeUserID": "476167968",
|
|
|
|
|
"DedeUserID__ckMd5": "99a92c4d7eeebff0",
|
|
|
|
|
"b_nut": "100",
|
|
|
|
|
"_uuid": "62A11A33-AE63-6B810-5BA8-74B644C9153733847infoc",
|
|
|
|
|
"buvid_fp_plain": "undefined",
|
|
|
|
|
"enable_web_push": "DISABLE",
|
|
|
|
|
"buvid_fp": "283c30b12d458a0311744e346aebd9e9",
|
|
|
|
|
"home_feed_column": "5",
|
|
|
|
|
"fingerprint": "c828157aaa66d22b3a4b841dc0dd5a96",
|
|
|
|
|
"PVID": "2",
|
|
|
|
|
"browser_resolution": "2074-1144",
|
|
|
|
|
"SESSDATA": "82243f05%2C1742112657%2C2d174%2A92CjA9CO3snstNoEvGickntljsVXZ2EcZHTxBcUE6h9oSQ1xl21MqQVX6gOpdj74xy2VoSVkJfdzRzTy1RUkVyNGhjcDQtejBMMHBHUEUxbWI0bWowU1lWVG9mUmVoQkE4X3lPS2phUjVqS2tHRTVpdlo1U19WQVd4dzQ4RzRpNUtIZjdPX0ZkOS13IIEC",
|
|
|
|
|
"bili_jct": "efe32125b9809a8323328e31b7fa7e99",
|
|
|
|
|
"hit-dyn-v2": "1",
|
|
|
|
|
"bili_ticket": "eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjY4MjUxMDYsImlhdCI6MTcyNjU2NTg0NiwicGx0IjotMX0.n0BlSThp9ye0k6US20pEh5gz191I6-1IgplXC1yJ2uI",
|
|
|
|
|
"bili_ticket_expires": "1726825046",
|
|
|
|
|
"b_lsid": "13EA7118_191FFF83B6D",
|
|
|
|
|
"bp_t_offset_476167968": "978129864806629376",
|
|
|
|
|
"sid": "6bro4vni",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 初始化一个空列表,用于存储弹幕内容
|
|
|
|
|
danmu_list = []
|
|
|
|
|
|
|
|
|
|
# 定义一个函数,用于获取指定视频的弹幕
|
|
|
|
|
def get_danmu(bvid,headers):
|
|
|
|
|
cid_url = "https://api.bilibili.com/x/web-interface/view?bvid=" + bvid # 构造获取视频cid的URL
|
|
|
|
|
cid_req = requests.get(cid_url, headers=headers) # 发送请求获取视频cid
|
|
|
|
|
cid_res = json.loads(cid_req.text) # 将响应内容转换为JSON格式
|
|
|
|
|
cid = cid_res['data']['cid'] # 从响应中提取视频的cid
|
|
|
|
|
danmu_url = "https://comment.bilibili.com/" + str(cid) + ".xml" # 构造获取弹幕的URL
|
|
|
|
|
danmu_req = requests.get(danmu_url, headers=headers) # 发送请求获取弹幕内容
|
|
|
|
|
danmu_req.encoding = 'utf-8' # 设置响应内容的编码为utf-8
|
|
|
|
|
danmu_list = re.findall('<d p=".*?">(.*?)</d>',danmu_req.text) # 使用正则表达式匹配弹幕内容
|
|
|
|
|
return danmu_list # 返回匹配到的弹幕列表
|
|
|
|
|
|
|
|
|
|
# 循环发送请求,获取多页视频数据
|
|
|
|
|
for i in range(10):
|
|
|
|
|
sess = requests.session() # 创建一个requests.session()对象,用于维持会话
|
|
|
|
|
req = sess.get(url + "&page=" + str(i+1), headers=headers, cookies=cookies) # 构造分页请求的URL,发送请求
|
|
|
|
|
res = json.loads(req.text) # 将响应内容转换为JSON格式
|
|
|
|
|
for video in res['data']['result']: # 遍历响应中的视频数据
|
|
|
|
|
danmu_list = danmu_list + get_danmu(video['bvid'],headers) # 调用函数获取每个视频的弹幕,并追加到danmu_list列表中
|
|
|
|
|
|
|
|
|
|
df = pd.DataFrame(danmu_list) # 将弹幕列表转换为pandas DataFrame
|
|
|
|
|
df.to_excel('danmu.xlsx',index=False,engine='openpyxl') # 将DataFrame保存到Excel文件
|
|
|
|
|
print("弹幕已保存") # 打印提示信息
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 2.2
|
|
|
|
|
# 数据统计
|
|
|
|
|
|
|
|
|
|
# 定义关键词列表
|
|
|
|
|
keywords = ['Ai','智能','3D','技术','科学']
|
|
|
|
|
|
|
|
|
|
# 过滤包含关键词的弹幕
|
|
|
|
|
filtered_danmu_list = [danmu for danmu in danmu_list if any(keyword in danmu.lower() for keyword in keywords)]
|
|
|
|
|
|
|
|
|
|
# 对过滤后的弹幕进行计数
|
|
|
|
|
danmu_count = Counter(filtered_danmu_list)
|
|
|
|
|
|
|
|
|
|
# 获取数量排名前8的弹幕
|
|
|
|
|
top_8_count = danmu_count.most_common(8)
|
|
|
|
|
|
|
|
|
|
# 创建新的Excel表,写入统计结果
|
|
|
|
|
workbook = openpyxl.Workbook()
|
|
|
|
|
sheet = workbook.active
|
|
|
|
|
|
|
|
|
|
# 写入表头
|
|
|
|
|
sheet['A1'] = '弹幕'
|
|
|
|
|
sheet['B1'] = '数量'
|
|
|
|
|
|
|
|
|
|
# 写入数据
|
|
|
|
|
for i, (danmu, count) in enumerate(top_8_count, start=2):
|
|
|
|
|
sheet[f'A{i}'] = danmu
|
|
|
|
|
sheet[f'B{i}'] = count
|
|
|
|
|
|
|
|
|
|
# 打印提示信息
|
|
|
|
|
print("弹幕已过滤")
|
|
|
|
|
|
|
|
|
|
# 保存Excel表
|
|
|
|
|
workbook.save('danmu_count.xlsx')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 2.3
|
|
|
|
|
# 数据可视化
|
|
|
|
|
|
|
|
|
|
# 读取Excel文件
|
|
|
|
|
df = pd.read_excel('danmu_count.xlsx', usecols=['弹幕'])
|
|
|
|
|
|
|
|
|
|
# 获取弹幕列表
|
|
|
|
|
text = ' '.join(df['弹幕'].astype(str).tolist()) # 提取弹幕内容并合并为一个长字符串
|
|
|
|
|
cut_text = jieba.cut(text) # 分词处理
|
|
|
|
|
word = ' '.join(cut_text) # 以空格分割文本
|
|
|
|
|
|
|
|
|
|
# 设置停用词
|
|
|
|
|
stopwords = set(["的", "了", "和", "是", "在", "我", "你", "他", "她"])
|
|
|
|
|
|
|
|
|
|
# 读取图片
|
|
|
|
|
pic = np.array(Image.open('1.png')) # 打开并加载图片文件
|
|
|
|
|
image_colors = ImageColorGenerator(pic) # 创建颜色生成器,用于从图片中提取颜色
|
|
|
|
|
|
|
|
|
|
# 配置并生成词云图
|
|
|
|
|
wd = wordcloud.WordCloud(
|
|
|
|
|
mask=pic, # 使用图片作为词云的形状
|
|
|
|
|
font_path='simhei.ttf', # 指定字体路径,以支持中文显示
|
|
|
|
|
background_color='white', # 设置背景颜色为白色
|
|
|
|
|
)
|
|
|
|
|
wd.generate(word) # 根据提供的文本生成词云
|
|
|
|
|
|
|
|
|
|
# 图片颜色渲染词云图的颜色,用color_func指定
|
|
|
|
|
plt.imshow(wd.recolor(color_func=image_colors), interpolation='bilinear') # 展示词云图
|
|
|
|
|
plt.axis('off') # 关闭显示x轴、y轴下标
|
|
|
|
|
plt.show() # 显示图像
|