ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用Python分析网络热词与弹幕传播:从爬取到情感分析

用Python分析网络热词与弹幕传播:从爬取到情感分析 最近在二次元社区刷到一条很有意思的文案“‘开往夏天的列车’即将到达站点请‘乘客们’做好准备”。后半句跟了一句“其实也可以当做是开往天堂的列车”再配上一句“这个家伙又开始想刀子了”。经常看番、逛同人圈的朋友应该秒懂这是在预告某个角色的剧情走向。这里的“刀子”是指悲剧剧情不是现实中任何伤害行为只是粉丝对“虐心情节”的调侃称呼。先说明一下这篇文章不打算讨论剧情本身也不展开“葱钻/钻葱”到底指哪对CP。我关注的不是文案里的二次元梗而是它背后可以做的技术拆解一条网络热词、一个弹幕高频句它的传播有没有规律参与讨论的人整体情绪是偏“期待”还是偏“悲伤”弹幕集中在视频的哪一段爆发这一批问题完全可以用 Python 从数据角度回答。所以本文提供一套可以照抄的“网络热词/弹幕传播分析”方案包含数据采集、文本清洗、分词、词频统计、情感分析、时间分布、可视化、接口封装和批量任务处理。整条链路不需要 GPU普通 CPU 电脑就能跑。对内容运营、短视频创作者、社区数据分析刚入门的同学来说可以直接照着做。1. 核心能力速览先把这套方案的关键信息列出来方便你判断值不值得往下读。能力项说明分析对象二次元社区、短视频平台中的弹幕、评论、热词文本主要功能公开数据采集、分词、关键词提取、情感分析、时间分布、可视化、API 输出、批量任务技术栈Python、requests、BeautifulSoup、jieba、SnowNLP、pandas、matplotlib、Flask硬件需求普通 CPU 电脑即可不需要 GPU不需要 CUDA系统平台Windows / Linux / macOS 均可数据来源平台公开接口、本地文本文件、CSV 导出文件启动方式命令行运行脚本 / Flask 接口服务是否支持 API支持返回 JSON 格式分析结果是否支持批量任务支持可多进程批量处理多个文件或多个视频弹幕适合人群内容运营、短视频创作者、社区数据分析入门者从材料看这套方案最核心的价值不是“模型有多强”而是所有步骤都开源、可复现、可落地。从采集到可视化每一步都是常见 Python 库不存在黑盒环节。2. 适用场景与使用边界这套分析方案适合解决“一个热词/热梗到底在传播什么、情绪如何、什么时候爆发”这类问题。举例来说复盘某条视频弹幕里高频出现的词判断观众关心什么。观察某对 CP、某个角色相关讨论的情感倾向。统计一条热梗在不同时间段被提及的次数找到爆发点。把分析结果封装成 API接入自己的内容运营看板或定时任务。它不适合做什么也要提前说清楚。首先它不适合去做精准用户画像因为弹幕和评论大多只有文本和时间信息没有完整用户行为数据。其次它不适合对非公开数据做采集私聊、私密群、付费内容都不在讨论范围内。再次SnowNLP 这类规则加统计的情感分析模型对二次元网络用语的敏感度有限只能作为快速基线不能当成绝对结论。在合规方面几个边界必须守住只能采集公开可访问的数据并且遵守平台接口条款控制请求频率不绕过风控。分析结果做展示时要对截图中的用户名、头像等个人信息做脱敏处理。同人创作内容涉及原作角色版权时要注意非商业使用、标注来源、尊重作者意愿。“刀子”“天堂”等词是剧情比喻不是真实伤害导向分析报告里也要避免过度联想。3. 环境准备与前置条件这套分析方案的依赖很少准备过程大约五到十分钟。操作系统建议使用 Windows 10/11、macOS 或主流 Linux 发行版。Python 版本建议 3.9 以上太老的版本对类型注解和 Flask 新接口支持不友好。磁盘方面整套虚拟环境和依赖库占用大概 200MB 左右如果还要存原始弹幕 CSV再预留几百 MB 足够。内存方面几万条弹幕文本的处理压力很小8GB 内存的电脑很宽裕如果一次性处理上百万条文本建议内存不低于 16GB。网络环境只需要能访问目标数据平台即可。如果在受控网络环境内无法直接访问外部网站可以改为使用本地 CSV 或文本文件作为输入后面所有分析流程不变。下面是通用检查清单Python 3.9 已安装能在命令行执行python --version。pip 可用能安装第三方依赖。目标平台接口或本地数据文件可用。输出目录有写权限。4. 安装部署与启动方式建议先创建一个独立的虚拟环境避免依赖冲突。这里以 Windows 命令和 Linux/macOS 命令分别说明。# Windows 创建虚拟环境 python -m venv venv venv\Scripts\activate # Linux / macOS 创建虚拟环境 python -m venv venv source venv/bin/activate激活虚拟环境后安装依赖库。可以将下面的内容保存为requirements.txt。requests2.31.0 beautifulsoup44.12.3 lxml5.2.1 jieba0.42.1 snownlp0.12.3 pandas2.2.2 matplotlib3.8.4 flask3.0.3 psutil5.9.8 threadpool1.1.0然后执行安装命令pip install -r requirements.txt如果安装速度慢可以临时使用国内镜像源pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple建议的项目目录结构如下hotword-analysis/ ├── data/ │ ├── raw/ # 原始弹幕/评论 CSV 或 txt │ └── output/ # 分析结果和图表 ├── scripts/ │ ├── fetch_danmaku.py # 采集层 │ ├── analyze.py # 分析层 │ └── server.py # API 服务层 ├── venv/ ├── requirements.txt └── README.md目录结构不是强制要求但建议一开始就按这种思路分离“数据、代码、输出”。后面做批量任务和 API 服务时会顺手很多。5. 功能测试与效果验证第一次跑通不要直接上大任务。先用一小段本地文本验证分词、词频、情感分析这几条核心链路。下面按功能模块给出测试方法和判断标准。5.1 验证分词与词频统计先创建一个本地文本文件data/raw/sample.txt内容可以模拟前文那段二次元文案开往夏天的列车即将到达站点 请乘客们做好准备 其实也可以当做是开往天堂的列车 这个家伙又开始想刀子了 我磕的是无差葱钻钻葱自行代入然后运行下面的脚本import jieba from collections import Counter from pathlib import Path text Path(data/raw/sample.txt).read_text(encodingutf-8) words [w for w in jieba.lcut(text) if len(w) 1] counter Counter(words) print(总词数, len(words)) print(Top 20 高频词) for word, count in counter.most_common(20): print(word, count)判断成功的标准是能正常输出“列车”“夏天”“乘客”“刀子”等有意义关键词不出现大量单字或乱码。如果发现“葱钻”这种自定义词被切碎了可以给 jieba 添加自定义词典。import jieba jieba.add_word(葱钻) jieba.add_word(钻葱)这一步是后面所有分析的基础。分词结果不准后面的词频、情感分析都会跟着偏。5.2 验证情感分析情感分析用 SnowNLP注意它输出的是 0 到 1 之间的值越接近 1 越积极越接近 0 越消极。from snownlp import SnowNLP texts [ 开往夏天的列车即将到达站点, 其实也可以当做是开往天堂的列车, 这个家伙又开始想刀子了, 好期待接下来的剧情, ] for t in texts: score SnowNLP(t).sentiments print(f文本{t}) print(f情感倾向{score:.4f}) print(- * 40)常见的判断标准是积极句子输出的分数应该在 0.7 以上消极句子在 0.3 以下。但 SnowNLP 默认训练语料偏向电商评价对“刀子”“刀死我了”这类二次元黑话不一定准确。如果你发现所有句子都输出 0.5 附近说明这个模型对当前文本不敏感这时候不要强行解读可以改用词典规则或更高级的模型。5.3 验证弹幕时间分布弹幕时间分布能反映观众在哪个场景集中发弹幕。这里提供一个从 B 站公开弹幕接口解析数据的示例。接口可能因平台调整而失效如果失效请将采集层替换为本地 CSV 数据。import requests from bs4 import BeautifulSoup import pandas as pd def fetch_danmaku(cid): 获取某个视频的公开弹幕。 cid 是视频分 P 的编号需要从视频页面请求中获取。 该接口为公开示例可能随平台调整而失效。 url fhttps://api.bilibili.com/x/v1/dm/list.so?oid{cid} headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)} resp requests.get(url, headersheaders, timeout10) resp.encoding utf-8 soup BeautifulSoup(resp.text, xml) rows [] for d in soup.find_all(d): p d.get(p, ) text d.get_text() parts p.split(,) appear_time float(parts[0]) if parts else 0 rows.append({time: appear_time, text: text}) return pd.DataFrame(rows) if __name__ __main__: cid 123456 # 替换成实际视频的 cid df fetch_danmaku(cid) print(弹幕数量, len(df)) print(df.head())判断标准是能正常获得弹幕数量且 DataFrame 包含time和text两列。如果返回空或 403优先检查 cid 是否有效、User-Agent 是否正确、接口是否有更新。这类公开接口在不同网络环境下表现不一样不要一上来就怀疑代码错误。得到time列之后就可以用 matplotlib 画弹幕时间分布图。import matplotlib matplotlib.rcParams[font.sans-serif] [SimHei, WenQuanYi Micro Hei, Noto Sans CJK SC] matplotlib.rcParams[axes.unicode_minus] False import matplotlib.pyplot as plt plt.figure(figsize(12, 4)) plt.hist(df[time], bins60, color#2ca02c, alpha0.8) plt.title(弹幕时间分布) plt.xlabel(视频播放时间秒) plt.ylabel(弹幕数量) plt.tight_layout() plt.savefig(data/output/danmaku_distribution.png, dpi150) print(图表已保存到 data/output/danmaku_distribution.png)如果弹幕集中在某几十秒区间说明那里大概率是名场面或情绪爆发点。5.4 验证接口 API分析逻辑跑通之后可以封装成 Flask API。先启动服务python scripts/server.py服务默认跑在127.0.0.1:5000。然后在另一个终端执行curl -X POST http://127.0.0.1:5000/analyze \ -H Content-Type: application/json \ -d {texts:[开往夏天的列车即将到达站点,这个家伙又开始想刀子了],top_k:10}预期返回 JSON 格式的关键词统计。{ code: 0, message: ok, top_keywords: [ [刀子, 1], [列车, 1], [夏天, 1] ] }如果返回正常说明分析服务可以被外部工具调用后面就可以接到自己的监控脚本或自动化流程里。6. 接口 API 与批量任务6.1 启动基础分析服务Flask 服务代码可以长这样。为了保证兼容性路由使用methods[POST]而不是 Python 3.10 之后的app.post简写。from flask import Flask, request, jsonify import jieba from collections import Counter app Flask(__name__) app.route(/analyze, methods[POST]) def analyze(): data request.get_json(forceTrue) texts data.get(texts, []) top_k int(data.get(top_k, 20)) words [] for text in texts: words [w for w in jieba.lcut(text) if len(w) 1] counter Counter(words) top_keywords counter.most_common(top_k) return jsonify({ code: 0, message: ok, total_words: len(words), top_keywords: top_keywords }) if __name__ __main__: app.run(host127.0.0.1, port5000)启动后所有 Python 脚本、HTTP 工具、持续集成任务都可以调用这个接口。6.2 Python 调用 API 示例import requests url http://127.0.0.1:5000/analyze payload { texts: [ 开往夏天的列车即将到达站点, 请乘客们做好准备, 这个家伙又开始想刀子了 ], top_k: 10 } resp requests.post(url, jsonpayload, timeout30) print(resp.status_code) print(resp.json())这种接口调用方式非常通用不需要关心内部实现只依赖 HTTP 协议。6.3 批量任务处理批量场景可以分成两类。第一类是多个 CSV 文件需要统一分析第二类是多个视频 cid 需要采集并分析。这里以多文件批量分析为例。import os import time from pathlib import Path from concurrent.futures import ProcessPoolExecutor import pandas as pd import jieba from collections import Counter RAW_DIR Path(data/raw) OUTPUT_DIR Path(data/output) def analyze_csv(path): df pd.read_csv(path, encodingutf-8) texts df[text].dropna().tolist() words [] for text in texts: words [w for w in jieba.lcut(text) if len(w) 1] counter Counter(words) top counter.most_common(20) return {file: path.name, rows: len(texts), top: top} if __name__ __main__: OUTPUT_DIR.mkdir(parentsTrue, exist_okTrue) csv_files list(RAW_DIR.glob(*.csv)) for csv_file in csv_files: try: result analyze_csv(csv_file) print(result) except Exception as exc: print(f{csv_file.name} 处理失败: {exc})如果文件很多可以用ProcessPoolExecutor多进程并行处理。import os from concurrent.futures import ProcessPoolExecutor def process_one(csv_file): return analyze_csv(csv_file) if __name__ __main__: csv_files list(RAW_DIR.glob(*.csv)) with ProcessPoolExecutor(max_workersos.cpu_count() or 2) as executor: results list(executor.map(process_one, csv_files)) for res in results: print(res)多进程能显著缩短耗时但要注意进程数不要无限加大建议控制在 CPU 核心数以内。否则内存占用会上升反而得不偿失。6.4 失败重试与日志批量任务最怕“跑一半被一条脏数据卡住”。基础做法是逐文件 try/except更稳的做法是加一个重试函数。import time def retry(func, max_tries3, delay1): for attempt in range(max_tries): try: return func() except Exception as exc: print(f第 {attempt 1} 次失败: {exc}) time.sleep(delay) raise RuntimeError(重试多次仍然失败)调用时把“采集弹幕”或“读取网络文件”这类不稳定的函数传进去即可。日志建议直接写到文件里方便排查import logging logging.basicConfig( filenamedata/output/batch.log, levellogging.INFO, format%(asctime)s %(levelname)s %(message)s )7. 资源占用与性能观察这套方案不涉及 GPU 和 CUDA资源占用主要是 CPU 和内存观察起来很简单。如果要量化脚本耗时和内存占用可以加一段计时监控import time import psutil start time.time() # 这里执行你的分析逻辑 elapsed time.time() - start memory_mb psutil.Process().memory_info().rss / 1024 / 1024 print(f耗时{elapsed:.2f} 秒) print(f内存{memory_mb:.2f} MB)几个影响性能的关键因素语料量几万条短文本在几秒内可以完成分词如果到几十万条耗时和内存都会明显上升。分词方式jieba.lcut是全模式、精确模式还是搜索引擎模式速度不一样。默认精确模式够用。进程数批量任务里进程数等于 CPU 核心数时通常提速最明显。再往上加内存翻倍速度反而不提升。情感分析SnowNLP 是逐条模型推理速度比分词慢。如果情感分析是瓶颈可以只对过滤后的关键词句做情感分析而不是全量文本。降低资源占用最直接的方法是“分批处理”。读取 CSV 时不要一次性read_csv整个超大文件可以按行分块chunk_iter pd.read_csv(data/raw/large.csv, chunksize5000, encodingutf-8) for chunk in chunk_iter: process(chunk)接口服务启动之后还要关注端口占用。如果 5000 端口被别的服务占了启动时会报Address already in use换端口即可python scripts/server.py --port 5001如果 Flask 代码里写死了端口也可以改成读取环境变量import os port int(os.environ.get(ANALYZE_PORT, 5000)) app.run(host127.0.0.1, portport)8. 常见问题与排查方法下面按实际开发中容易踩到的坑整理成排查表。问题现象可能原因排查方式解决方案pip 安装依赖很慢或超时默认源在国外网络延迟高查看 pip 输出日志使用国内镜像源中文乱码文件编码不是 UTF-8打印读取内容检查文件编码统一保存为 UTF-8或者encodinggbkjieba 分词结果碎片化自定义词不在词典打印分词结果使用jieba.add_word()添加自定义词弹幕接口返回空白或 403cid 无效或接口已调整检查 HTTP 状态码和响应内容换成本地 CSV 数据或改用平台最新公开接口情感分析结果集中在 0.5 附近SnowNLP 模型不匹配网络用语用几条明确积极/消极句子测试改用词典规则、购买标注数据或接入大模型分析Flask 启动报端口被占用之前有进程残留或其他服务占用端口netstat -anofindstr 5000 查看占用进程批量任务中途卡住单条数据异常或网络请求无响应检查日志定位到具体文件增加超时和重试逻辑内存不足一次性读取超大文件观察psutil内存曲线改为分块读取 CSV或增加并发进程遇到问题先看日志再缩小范围。不要直接大规模重跑先拿一条样本复现。9. 最佳实践与使用建议如果你要把这套方案真正用起来有几个建议值得留意。第一第一次先做最小验证。不要一上来就采集几十个视频的弹幕先用一个本地 sample 文件跑通分词、情感分析、可视化。链路通了再扩大规模。第二建立数据分层目录。raw放原始数据output放结果和图表脚本单独放。这样后续做回归、对比不同热词时非常方便。第三自定义词典和停用词是效果提升的关键。每次分析时把高频的无效词加入停用词表把切碎的人名、CP 名加入自定义词典。这比换模型还能更快提升结果质量。第四批量任务一定要有日志、超时和失败重试。数据采集阶段网络不确定因素很多一个请求卡住可能拖垮整个队列。第五API 服务只监听本机不加鉴权也能用如果开放到局域网或公网需要增加访问控制比如flask-talisman、token 校验或者放到内网反向代理后面。第六发布分析结果时要脱敏。不要直接贴出用户昵称、头像、用户 ID。标注样本量和采集时间会显得更专业。第七关于同人内容的版权和授权问题。粉丝创作、CP 讨论、剧情分析都是社区互动的一部分但发布前要确认素材来源合规不商用不抹黑角色和作者。10. 总结与下一步回到开头那条文案“开往夏天的列车”也好“刀子”也好对数据分析来说它们只是“文本信号”。真正有价值的不是某个词本身有多火而是这些词在什么时间、以什么情绪、和哪些词一起出现。这套 Python 分析流程把这些问题变成了可执行的脚本。最值得先试的功能是本地样本的分词和词频统计因为它最容易验证也决定了后续分析质量。最容易踩的坑是网络接口不稳定和 SnowNLP 对二次元黑话不敏感前者靠本地文件兜底后者靠自定义词典和人工抽样校验。后续可以扩展的方向不少接入更多数据源做对比、把分析结果定时写入看板、用大语言模型替代 SnowNLP 做更细粒度情绪判断或者把“热词传播周期”和发布时间、标题特征放在一起做归因。只要把采集层和分析层分开这套框架可以复用很久。建议你先把本地样本流程跑通再决定要不要接平台接口和批量任务。
返回列表