说实话,这个标题一开始是我在某个深夜刷B站时冒出来的念头。原神从2020年上线到现在,六年多了,我作为玩家和数据分析爱好者,一直在用Python做各种数据折腾。有一天突然想:原神在B站的热度到底是怎么变化的?璃月版本、稻妻版本、须弥版本……每次大版本更新之后,B站上的播放量、评论数、弹幕活跃度这些数字会有什么规律?于是就有了这个“风起璃月,数载回响”的数据复盘项目。
这篇文章就是完整记录我怎么用Python把原神在B站六年的热度数据抓下来、洗干净、算指标、画图表的过程,包括所有踩过的坑和绕过的弯路。如果你是Python初学者,能从这里看到requests、pandas、matplotlib这些库在真实场景里怎么配合;如果你已经在用Python做数据分析,可以重点看第三、四、五节的指标设计和反爬处理思路。不管怎样,这套流程换个游戏、换个UP主、甚至换个视频平台都能复用。
1. 项目整体设计与数据获取思路
1.1 为什么选B站作为数据源
原神的内容生态里,B站是一个绕不开的阵地。米哈游官方账号在B站首发PV、角色演示、版本预告,大量UP主做攻略、考据、二创和二倍速整活,玩家的情绪和讨论热度会直接反映在播放量、评论数、弹幕密度这些指标上。
选择B站还有一个现实原因:它的公开接口非常友好,有成熟的搜索API和视频信息API,不需要模拟浏览器,也不用处理复杂的JS渲染页面,用Python的requests库就能直接拿到结构化JSON数据。对比某音、某手这种把接口藏得很深的平台,B站对数据分析爱好者来说几乎是天堂。
1.2 数据获取方案的选型
摆在面前有两条路:一是用爬虫去抓网页HTML再解析,二是直接调用B站内部HTTP接口。我刚接触这个项目时也想过用Scrapy配BeautifulSoup去抓搜索页,试了两次果断放弃。原因很直接:
- 网页HTML结构经常变,上个月写的解析规则下个月就可能失效。
- B站搜索结果页是异步加载的,直接请求静态HTML拿不到完整数据。
- 接口返回JSON格式,字段结构稳定,用
requests.get()加params字典就能完成请求,代码量少一个量级。
还有一个更省事的选择是直接用第三方库bilibili_api,把搜索、视频详情、评论拉取都封装好了。不过我自己一般不用它做这种专项分析,因为接口字段经常更新,第三方库如果没跟上版本,报错会非常头疼。直接用requests调原生接口,麻烦一次,之后就一劳永逸。
1.3 项目技术栈与目录规划
这个项目的技术栈非常基础:
- requests:发HTTP请求,拉取JSON。
- pandas:数据清洗、透视、时间序列处理。
- matplotlib + pyecharts:画静态图和交互图。
- collections.Counter:统计词频,做基础文本分析。
我习惯把项目拆成模块,后续迭代只需要改参数,不用动主流程:
bash复制genshin_bilibili_analysis/
├── config.py # 请求头、Cookie、关键词、时间范围等配置
├── fetcher.py # 搜索接口与视频详情接口的请求封装
├── cleaner.py # 数据清洗、去重、类型转换
├── metrics.py # 热度指数计算、月度汇总
├── visualize.py # 可视化图表生成
└── main.py # 串联全流程
这样设计的好处是调试方便,比如只想重新画图时,直接跑visualize.py就行,不用重新抓几万条数据。后面我会详细介绍每个模块里放了什么逻辑。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据采集:从B站接口取数
2.1 搜索接口请求参数的调优
要统计“原神”相关内容,最直接的方式是使用B站搜索接口,按关键词搜索视频,拿搜索结果列表。核心接口是:
bash复制GET https://api.bilibili.com/x/web-interface/search/type
关键参数:
search_type=video:只搜视频。keyword=原神:搜索关键词。page:页码,从1开始。page_size:每页数量,最大能填50,我实测过填100会报错,老老实实50。order=click:按播放量排序,适合拿头部爆款。order=pubdate:按发布时间排序,适合拿新发布内容。
需要注意,如果不带Cookie,这个接口会频繁触发风控,甚至直接返回code: -412。我的做法是在config.py里配置一个自己的Cookie,并在每次请求之间加随机延迟,避免请求频率过快。网上很多教程不写这部分,初学者拿着代码一跑就报错,还以为是自己代码写错了,其实是频率问题。
2.2 视频详情与评论接口的字段说明
搜索接口返回的数据里已经包含播放量、评论数、收藏数、视频标题和发布时间,但信息不够全。比如我们想知道视频的点赞数、UP主信息、分区、时长,就得进一步请求视频详情接口:
bash复制GET https://api.bilibili.com/x/web-interface/view
params: bvid=BVxxxxxxxx
详情接口返回的stat对象里是一整套核心指标,对我们后续做热度分析非常有价值:
| 字段 | 含义 | 备注 |
|---|---|---|
view |
播放次数 | 核心热度指标之一 |
danmaku |
弹幕数 | 反映强烈互动意愿 |
reply |
评论数 | 讨论深度 |
favorite |
收藏数 | 内容实用价值 |
coin |
投币数 | 真金白银的支持 |
share |
分享数 | 内容传播能力 |
like |
点赞数 | 基础正向反馈 |
搜索接口里的pubdate是Unix时间戳,需要转成标准日期。duration字段是视频时长秒数,可以用来分析原神长视频和短视频的占比变化。
2.3 增量抓取与全量抓取的取舍
这个项目我做了两个版本。第一版是全量抓取:从头到尾翻几百页搜索接口,把六年所有结果全部存下来,再逐条请求详情接口补齐数据。优点是一次拿全,缺点是请求量大,容易触发反爬,而且很多老旧视频的详情数据从搜索接口就能拿到,再请求详情接口属于浪费配额。
第二版我改成了增量策略:
- 先按
order=pubdate和order=click各抓前几十页,覆盖时间范围和头部爆款。 - 记录当前已有的bvid到本地集合,每页取回后用集合过滤,只对新bvid请求详情接口。
- 请求详情接口时做限速,每两个请求间隔1.5到3秒随机。
这样抓下来的数据既包含时间维度的全貌,又保证了头部内容的详细指标。整个流程跑完大概需要两三个小时,我就在睡前挂着跑,第二天早上起来收数据。
3. 数据清洗与热度指标体系构建
3.1 用pandas处理缺失值和重复值
抓下来的原始数据大概有40多个字段,但很多字段我们根本用不上,所以清洗的第一步是筛选列。我最终只保留了title、bvid、author、pubdate、view、danmaku、reply、favorite、coin、share、like、duration、description这几列。
然后处理缺失值。搜索接口偶尔会漏掉某些视频的like字段返回0,问题不大。真正坑的是详情接口偶发超时,导致整条记录只有搜索接口的基础信息。我的处理策略是:如果某个视频详情请求失败三次就跳过,保留搜索接口数据里已有的字段,缺失指标直接填0,并在最后统计时单独标记data_source字段,方便后续排查。
去重逻辑看起来简单,实操有细节。bvid是唯一标识,直接用drop_duplicates(subset='bvid')就行。但要注意,B站有时会出现一个视频被下架后二次上传的情况,bv不同但内容高度重复。这种属于业务层面的重复,靠纯代码不好解决,我选择忽略。毕竟我们要分析的是B站生态热度,同一个内容的不同版本自身就代表了一种热度表达。
3.2 时间字段的标准化处理
B站返回的pubdate是Unix时间戳,我需要把它变成可聚合的年月字段:
python复制import pandas as pd
df['pubdate'] = pd.to_datetime(df['pubdate'], unit='s', utc=True)
df['pubdate_cst'] = df['pubdate'].dt.tz_convert('Asia/Shanghai')
df['year_month'] = df['pubdate_cst'].dt.to_period('M')
这里有个容易踩坑的点:utc=True如果不加,pandas会把它当作低时区时间处理,导致日期偏移8小时。对于白天发布的视频没影响,但如果某个视频是凌晨发布的,日期就会差一天,月度汇总时可能被归到错误的月份。
3.3 构建综合热度指数
播放量高不代表热度高,这个话题在数据分析圈老生常谈。2020年原神刚开服那阵,随便一个“原神PV”都能轻松破百万播放,但评论区可能只有几百条讨论。到了2023年以后,很多视频单日播放没那么高了,但弹幕、评论、收藏这些深度互动指标的密度反而上来了。
为了更客观地度量热度,我构造了一个加权热度指数:
python复制def compute_heat_score(row):
# 权重依据经验设定,实际项目里可以再做敏感度分析
return (row['view'] * 1.0 +
row['like'] * 2.0 +
row['favorite'] * 3.0 +
row['coin'] * 4.0 +
row['share'] * 5.0 +
row['reply'] * 6.0 +
row['danmaku'] * 8.0)
为什么弹幕权重最高?因为发弹幕的门槛比点赞高得多,用户需要暂停视频、打字、发送,这个动作包含的情绪浓度和信息密度远超一个双击。其次是分享,愿意把视频转到其他平台,说明用户认为这个内容有社交价值。评论权重排在第三,因为评论往往能引发互动讨论甚至二创,形成内容生态。
纯播放量驱动的指数会高估那些“标题党+封面党”内容的能量,加权指数更接近真实的社区热度感知。
3.4 去除无关内容的关键词过滤
搜“原神”时有一个麻烦:很多结果其实和游戏无关。比如关键词“原神”偶尔会匹配到一些名字里带“原神”但内容是其他游戏的视频,还有些是“原神哥”“原神启动”这种玩梗视频,也蹭了关键词。全看讨论度的话,玩梗视频本身也是原神热度的一部分,所以我不打算完全剔除,而是单独打标签。
我的过滤策略是:把视频标题和description拼接起来,如果包含“鸣潮”“星穹铁道”“绝区零”这些竞品词,同时完全不包含“原神”“璃月”“稻妻”“枫丹”等游戏内专有名词,就标记为is_relevant=False。这样在统计时既能保留全量数据看生态热度,又能单独筛出相关内容看核心玩家热度。
4. 关键趋势分析与核心发现
4.1 月度播放量与投稿量的双维度观察
当我完成数据清洗和指标构建后,第一时间按照年月汇总数据,看到一张六年的长表。用matplotlib画出来后,几个特征非常明显:
- 2020年9月开服,当月播放量冲到历史峰值,因为新发布的PV“浮浪的归人”等视频在B站病毒式扩散。
- 2021年上半年有个小幅回落,但紧接着稻妻版本更新又拉起来一波。
- 2022年到2023年是平稳期,播放量没有暴跌也没有暴涨,说明用户基本盘非常稳定。
- 2024年后单个头部视频的播放量较早期下降,但投稿数量显著增加,说明内容生态从集中产出转向分散供给。
注意一个反直觉现象:早期播放量大,并不代表当时的社区更活跃。2020年很多人是因为游戏新鲜感去看“原神下载安装”“原神怎么玩”这类视频,刷新完就划走了。2023年以后的观众更挑剔,愿意看的都是攻略、剧情考据、角色厨放类的深度内容,这种内容互动率天然更高。
4.2 版本更新与热度波动的对应关系
把热度指数按月份画出来后,我叠加了原神版本更新时间线,发现一个很稳定的规律:每次大版本前瞻直播的当月,热度指数会提前拉高;版本正式上线的当周达到峰值,然后在新地图探索期维持两周左右高位;到了版本中期(大约第4到6周),热度开始下行,直到下一个版本预告放出来。
璃月版本是典型案例。2021年春节档的“海灯节”版本,配合“明霄升海平”的剧情演出,在B站产生了大量二创和同人视频。我在2021年2月的月度数据里看到明显的弹幕数峰值,说明那个节点玩家情绪非常饱满,出圈效应也强。
须弥版本则体现了另一种热度模式。2022年8月上线的须弥篇,音乐、美术、剧情的质量都拉满,B站出现了大量“原神音乐现场”类长视频,播放量大但弹幕互动相对温和,因为观众在安静欣赏。这说明单看总播放量会错失内容属性差异,和指标设计密不可分。
4.3 头部UP主生态与内容结构变化
从采集的author字段里,我统计了历年播放量TOP20的UP主。结果不算意外:官方账号“原神”常年霸榜,但玩家二创账号在数量上占比越来越高。2020年榜单里官方视频和游戏资讯类占了一大半,2023年以后榜单里出现了更多角色考据、剧情梳理、boss攻略类的UP主。
有意思的是,我还发现早期爆款视频的duration普遍在5分钟以内,而2023年以后的头部视频时长明显拉长,接近15到20分钟。这里的原因很直观:早期观众对原神世界观还不了解,短视频适合快速传达核心信息;现在核心玩家需要的是深度解析,长视频提供的信息增量才能满足口味。内容结构和观众心智是同步演进的,这是六年来最明显的生态变化。
5. 可视化呈现:让数字真正“开口说话”
5.1 用matplotlib画热度走势与事件标注
数据本身不会说话,但图表可以。我用matplotlib画第一版趋势图时,踩过一个看得见的坑:直接对DataFrame里的year_month列做x轴,会出现刻度过密、标签重叠的问题。后来统一转换成字符串,只显示每年1月和7月作为刻度,图面才干净。
python复制import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
monthly = df.groupby('year_month')['heat_score'].sum().reset_index()
monthly['date'] = monthly['year_month'].dt.to_timestamp()
fig, ax = plt.subplots(figsize=(14, 6))
ax.plot(monthly['date'], monthly['heat_score'], linewidth=2, color='#2980b9')
ax.set_title('原神在B站的热度指数月度变化 (2020-2026)', fontsize=16)
# 只显示每年1月和7月,防止标签重叠
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=6))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
# 标注关键版本节点
key_dates = {
'2020-09-15': '公测开启',
'2021-01-01': '璃月海灯节',
'2022-08-01': '须弥版本',
'2023-08-01': '枫丹版本',
'2024-08-01': '纳塔版本',
}
for date_str, label in key_dates.items():
date_val = pd.to_datetime(date_str)
ax.axvline(date_val, linestyle='--', color='gray', alpha=0.6)
ax.text(date_val, ax.get_ylim()[1] * 0.9, label, rotation=45, fontsize=9)
plt.tight_layout()
plt.show()
画好后整个走势一眼就能看懂:六个大周期对应六个国家版本的更新节奏,热度峰值总在版本上线和春节档附近。这就是可视化的价值——不依赖任何文字描述,用户自己扫一眼就能得出相似结论。
5.2 用pyecharts做交互式时间线仪表盘
matplotlib适合静态报告,但如果我想把鼠标悬停上去直接显示每个月的数值、点击某个月份联动弹出当月热门视频,就得用pyecharts。它生成的HTML文件可以直接在浏览器打开,发给朋友或贴在公众号里都很方便。
我做的交互面板包含三块:热度指数总览、播放量Top10视频列表、弹幕数Top10视频列表。三者共用一个timeline组件,按月份切换。这样就能从“某个月整体热度”下钻到“这个月哪个视频最火”,非常直观。
操作上唯一要注意的是pyecharts对pandas的Period类型支持不好,画图前一定要先astype(str)转换,否则会报unsupported operand type(s)错误。这个坑我踩了十分钟才反应过来,提醒大家先转类型再传数据。
5.3 词云展示评论热词
除了数值指标,我还抓了一批“原神”搜索结果下热门视频的热门评论,用jieba分词后统计词频,用wordcloud画了一版词云。
词云结果非常有趣:早期(2020-2021年)热词集中在“抽卡”“氪金”“原石”“五星”,偏游戏机制和付费讨论;中期(2022-2023年)热词变成“剧情”“音乐”“地图”“感动”;后期(2024年往后)则出现大量角色名和地区名,比如“芙宁娜”“那维莱特”“纳塔”。
这个变化说明原神的核心讨论点在逐步从“这个游戏好不好玩”转向“这个游戏的内容值不值得回味”,社区的深度在肉眼可见地增加。做词云之前记得做一下停用词清洗,把“什么”“一个”“就是”这种无意义词汇过滤掉,否则画面会被语气词占据。
6. 实操中踩过的坑与解法纪录
6.1 请求频率过高触发B站风控
这个问题在项目初期差点让我放弃。第一版脚本用for循环请求搜索接口,每次间隔不到0.5秒,大概跑到200条请求时就返回了code: -412,所有后续请求全部失败。当时第一反应是账号被拉黑了,后来查了资料和社区讨论,才知道这是B站的临时风控,等一段时间会恢复。
解决方法是给每个请求加随机延时,并把重试机制写进代码:
python复制import time
import random
def safe_request(url, params, retries=3):
for attempt in range(retries):
resp = requests.get(url, params=params, headers=HEADERS, timeout=10)
if resp.status_code == 200 and resp.json().get('code') == 0:
return resp.json()
time.sleep(5 * (attempt + 1) + random.uniform(0, 2))
return None
另外,请求头里的User-Agent不要一直用同一个浏览器默认值,从几个常见UA里随机挑选也可以降低被识别为脚本的概率。实测把延迟从0.5秒调到2到4秒之后,抓几千条数据一路成功。
6.2 Cookie过期导致登录接口失效
搜索接口对Cookie的要求比较微妙。有时候不带Cookie也能正常返回数据,但偶尔会抽风,返回的搜索结果只有几条且没有author字段。我的解决方法是每次跑脚本前手动从浏览器复制最新Cookie到config.py,一旦发现返回数据异常就检查Cookie是否过期。
还有一个技巧:B站在请求头里识别Referer,如果某些请求被拒绝,可以尝试添加Referer: https://www.bilibili.com/。虽然官方接口文档没说必须带,但实测加上后成功率会提升一些。
6.3 时间序列对齐和缺失月的处理
数据清洗后我发现在某些月份(比如2025年上半年某个月)视频数量很少,导致月度汇总数据看起来断崖式下降。仔细排查后发现,这是因为搜索接口默认按综合排序返回,老视频在搜索结果里排名越来越靠后,我不翻够页数就漏掉了一部分历史视频。
补数的方式有两种:一是按order=click再抓一遍头部数据,和已有数据合并;二是专门挑那些断月,按order=pubdate翻页补齐。我用了第二种,每个月只补抓前3页就基本能覆盖那部分缺失数据,因为老视频的投稿数量本身就有限。
6.4 播放量的“时间累积效应”修正
分析跨度六年的数据时,很容易犯一个错误:直接拿2020年的播放量和2024年的播放量对比,然后下结论说2024年原神凉了。这不对。2020年的视频有四年多的时间累积播放量,2024年的视频可能上线才几个月,量级天然不占优。
所以我补充了一个“日均播放量”指标:
python复制df['days_since_publish'] = (analysis_date - df['pubdate_cst']).dt.days
df['daily_view'] = df['view'] / df['days_since_publish'].clip(lower=1)
按日均播放量重新排名后,很多2024年后发布的视频排到了前面。这说明只看总量容易误判热度趋势,分析长周期数据必须引入时间修正。这也是这个项目里我认为最有价值的一个处理细节。
7. 从数据中看到的原神六年生态变化
7.1 “内容生态”从官方驱动走向UGC驱动
这六年最直观的变化是B站原神内容生态的重心迁移。早期(2020-2021年)官方PV和角色演示占据绝对主导地位,播放量排行榜上几乎全是官方账号的内容。到了中期,攻略型UP主开始崛起,角色配队分析、周本打法、材料采集路线这类内容的播放量稳定上升。
后期阶段,二创、考据、剧情赏析类内容成为新的增长点。玩家不满足于“怎么玩”,更想理解“为什么这样设计”。这种转变在数据上体现为duration的持续拉长和favorite、coin在互动指标里的占比提高,因为长内容更值得收藏和投币表达感谢。
7.2 情绪热度的周期性波动规律
如果用日粒度数据观察,原神在B站的热度有一个非常稳定的“年度蝴蝶结”结构:每年1月到2月的海灯节/春节档是一波大峰值,6月到8月的周年庆和夏活是第二波峰值,然后12月的前瞻直播和年底活动会拉出第三个小峰值。
这种周期性其实反映了游戏内容更新节奏和玩家节点习惯之间的耦合。原神每年稳定四个版本,每个版本有前瞻、上线、探索、长草四个阶段,玩家在长草期刷B站的时间更多,但互动热情会集中在版本高潮期。官方在设计卡池和活动时,显然也在刻意配合这种传播节奏。
7.3 头部效应与长尾分布的演变
我还对每年播放量进行了基尼系数计算,发现一个有趣现象:早期头部视频占了全站原神播放量的很大比例,属于“少数爆款撑起热度”的结构;后几年中腰部UP主的内容播放量占比逐渐上升,头部集中度下降。
这个结论从另一个角度说明,原神在B站的内容生态并没有“凉”,只是在从“关注少数头部内容”向“更多元的长尾内容”演变。单个视频的播放量峰值可能不再像2020年那么夸张,但整体生态的健康度和多样性是显著提升的。
8. 扩展思考:这套方法还能用在哪些场景
这次分析做完,我把整套代码重构了一遍,把“关键词”“平台接口”“时间范围”全部参数化。现在换一个关键词(比如“鸣潮”“黑神话”)就能直接复跑全流程。这种通用性是我做项目时最看重的,代码写一次,后续能复用好几次才值得投入时间。
如果你想在这个项目基础上继续深入,有四个方向可以尝试:
第一,引入情感分析。把热门评论用大模型或BERT模型做正负面分类,计算情感分数,和播放量、弹幕数做相关性分析,看究竟是讨论度高的时候大家情绪偏正面,还是骂声多的时候弹幕更活跃。
第二,预测模型。用前几年各版本的时间节点、版本号、卡池角色等因素训练一个简单的XGBoost模型,预测下一个版本在B站的热度区间。虽然预测精度不可能很高,但趋势预判能为内容创作者提供选题参考。
第三,对比其他游戏IP的B站热度曲线,把原神和它的主要竞品放在同一套指标框架下对比,就能看出不同游戏的内容生态差异。
第四,做更细粒度的弹幕文本分析。弹幕比评论更口语化、碎片化,能捕捉到观看当下的即时情绪,比如在角色出场瞬间,弹幕里出现特定角色名的密度远高于平时。这种“实时情绪定位”对创作者把握观众爽点非常有帮助。
我个人实际操作中的体会是,这种数据项目的最大价值往往不在最终的分析结论,而在采集和清洗数据过程中培养出来的“数据敏感度”。一开始你觉得“原神B站热度很高”只是模糊印象,做完以后你能精确说出热度峰值的月份、主要贡献者、互动行为特征,这种从模糊到精确的转变,才是数据分析真正让人着迷的地方。最后再分享一个小技巧:抓下来的原始数据,不管多脏,都先存一份CSV备份,哪怕字段不全也别丢。后续分析思路变了想换指标,至少还有原始数据可以重新算,否则就要全部重抓,那种痛苦谁经历谁知道。
