尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

黑神话悟空评论数据分析系统:从采集清洗到情感主题建模全流程实战

黑神话悟空评论数据分析系统:从采集清洗到情感主题建模全流程实战 《黑神话悟空》发售之后玩家评论几乎成了一种“全民评测”。有人讨论画面表现有人争论难度曲线有人考据剧情和原著关系也有人纯粹在评论区玩梗。对于普通玩家这些只是刷过去的信息流但对于做数据分析的人来说这是一批极其难得的真实中文文本数据。如果一个毕业设计选择做“黑悟空评论数据分析系统”它真正要挑战的并不是机器学习算法有多深而是能否把“评论采集、数据清洗、中文分词、情感分析、主题建模、可视化展示”这一整条链路完整跑通并且最终得出能说服导师和评委的结论。很多人把这类项目想成“爬虫项目”或者“画图项目”实际做下来会发现最花时间的反而是文本预处理和分析结果的解释。这也是本文想重点拆解的地方。从项目编号 0180 的演示定位来看这个题目的核心价值是“全流程可演示”。也就是说它既要展示技术能力也要让非技术背景的人一眼看懂分析结果。文章会按真实项目落地顺序来写先从业务角度说明为什么选这个题目然后给出系统架构和技术选型再依次拆解数据采集、数据清洗、情感分析、主题建模和可视化看板的实现方式。每一步都会有可直接复用的代码片段最后还会整理一份常见问题排查表和答辩时容易被追问的工程细节。1. 项目背景与选题价值1.1 为什么“黑悟空评论”适合做数据分析项目先回答一个最直接的问题市面上可分析的数据这么多为什么偏偏选《黑神话悟空》的评论第一数据量大且获取渠道集中。游戏发售后的热度集中在几个核心平台比如B站视频评论区、微博话题、知乎问答和贴吧讨论。对毕设来说不需要到处找数据源只要围绕两三个平台就能拿到足够支撑分析的样本。第二评论内容天然适合做文本挖掘。玩家评论涵盖了画面、剧情、战斗、音乐、文化表达、优化性能等多个维度而且情感倾向非常鲜明。好评和差评的表述方式差异明显容易做情感分类也容易通过主题模型发现大家真正关注的子话题。第三话题本身有大众认知度。答辩的时候评委可能不了解你的算法细节但一定知道这款游戏。当你说“系统把玩家对画面讨论的比例从 30% 降到 8%”时评委能快速理解你在分析什么这比分析一个冷门学术数据集要好讲得多。1.2 毕业设计做这类系统的真实难点这类系统看起来是“爬虫 词云 情感分析”三板斧但真正把它做成一个能演示、能回答业务问题的系统难点在三个地方。第一个难点是数据质量问题。评论里大量内容是表情符号、网络梗、楼主回复引用、“镇楼图”等非有效文本如果不过滤后续分词的准确率会很难看。第二个难点是中文文本的领域适配。“黑猴”“杨戬”“天命人”“空气墙”“定身术”这些词通用分词器并不认识需要建自定义词典。如果不做这一步主题模型的结果可能是一堆没有信息量的词。第三个难点是分析结论的可解释性。很多毕设项目停在“我画了一张情感分布饼图”这一步但图和结论之间缺少桥接。评委更想看到的是“好评集中在哪些主题差评集中在哪些主题为什么会出现这种分布”。本文后面的分析流程就是围绕这条主线设计的。2. 系统架构与技术选型2.1 系统分层架构从工程角度这个系统可以分成五层。这里不用复杂架构图用最容易理解的方式描述每一层的职责。数据接入层负责从各平台获取评论数据包括爬虫采集和离线 JSON 文件导入两种方式。离线导入是给演示和答辩准备的兜底方案避免在演示现场因为网络或登录问题翻车。数据存储层负责把原始评论、清洗后的结构化数据和分析结果保存下来。大作业和毕设场景推荐 SQLite轻量且无需安装服务如果项目规模更大可以换 MySQL。数据预处理层负责去重、去噪、中文分词、停用词过滤、自定义词典扩展。这一层直接决定后续分析质量。分析引擎层负责情感打分、词频统计、主题建模和时间趋势分析。用到的核心库是 SnowNLP、Jieba 和 Gensim。可视化与展示层负责把分析结果变成词云、饼图、折线图、柱状图以及一个内嵌的可交互页面。推荐 Pyecharts 配合 Streamlit 或 Flask 搭建轻量演示前端。2.2 技术选型与选型理由模块技术选型说明开发语言Python 3.8数据分析生态最成熟适合快速迭代数据处理Pandas、NumPy清洗、去重、聚合、转换中文分词Jieba支持自定义词典安装简单情感分析SnowNLP离线可用适合中文电商和评论场景主题建模Gensim LDA适用于短文本主题发现可视化Pyecharts生成 HTML 图表演示效果好Web 展示Streamlit 或 FlaskStreamlit 更省代码Flask 更灵活数据库SQLite / MySQL毕设优先 SQLite生产可切 MySQL这套技术栈没有使用大模型 API 或 Spark 这类重型组件原因很明确毕业设计演示环境不稳定离线可用、单机可跑、结果可复现才是第一优先级。后面如果学有余力再换成大模型情感分析或 Spark 分布式处理也不迟。3. 环境准备与项目初始化3.1 环境要求建议使用 Python 3.8 或更高版本。操作系统不限Windows、macOS、Linux 都可以。为了不污染系统环境强烈建议创建虚拟环境。创建虚拟环境的命令如下Windows 和 Linux 下的激活方式略有不同。python -m venv venv # Windows 激活方式 venv\Scripts\activate # macOS / Linux 激活方式 source venv/bin/activate激活成功后命令行提示符会出现(venv)前缀。接下来安装项目依赖。pip install pandas numpy jieba snownlp gensim pyecharts streamlit requests beautifulsoup4 openpyxl安装完成后可以用下面的命令确认核心库是否正常加载。import pandas as pd import jieba import snownlp import gensim print(pandas version:, pd.__version__) print(jieba installed:, jieba.__version__) print(gensim installed:, gensim.__version__)版本号以实际安装为准。如果这里没有报错说明环境已经满足要求可以进入项目初始化阶段。3.2 项目目录结构一个清晰的项目结构对毕设答辩非常加分。这里给出一份推荐目录既不会过度设计也能体现工程规范。black_myth_comment_analysis/ ├── data/ │ ├── raw/ # 原始评论 JSON / CSV │ ├── cleaned/ # 清洗后的数据 │ └── result/ # 分析结果输出 ├── dicts/ │ └── black_myth_dict.txt # 自定义词典 ├── src/ │ ├── collector.py # 数据采集 │ ├── cleaner.py # 数据清洗 │ ├── analyzer.py # 情感分析与主题建模 │ ├── visualizer.py # 可视化图表 │ └── app.py # Streamlit 展示入口 ├── requirements.txt └── README.md如果数据量不大可以暂时不用数据库直接用 CSV 和 JSON 文件组织数据。需要做查询和统计时用 Pandas 读取即可。等到需要存储多批次爬取结果时再考虑 SQLite。4. 评论数据获取爬虫与数据落地4.1 数据源选择与合规提醒评论数据主要可以从 B站视频评论区、微博话题、知乎问答、NGA 论坛等公开页面获取。这里必须强调只能采集公开可见的数据并且只用于学习研究和技术演示不得用于商业用途。同时要遵守目标平台的 robots 协议控制请求频率不要对平台服务器造成压力。毕设演示时最稳妥的做法是先用小规模数据跑通流程导出为 JSON 或 CSV 文件并把这份离线数据作为演示时的默认数据源。这样即使现场网络断开系统依然可以正常演示。4.2 通用评论采集示例不同平台的接口千差万别这里不针对某个平台写死代码而是给出一段通用的请求与解析思路。实际使用时需要根据目标页面结构调整解析逻辑。# 文件路径src/collector.py import json import time import requests import pandas as pd from bs4 import BeautifulSoup HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Referer: https://www.bilibili.com/, } def fetch_comments(url, limit100): 通用评论采集函数仅用于学习演示。 不同平台的页面结构和接口差异较大实际使用时需要按目标平台调整。 comments [] response requests.get(url, headersHEADERS, timeout10) response.encoding utf-8 soup BeautifulSoup(response.text, html.parser) # 这里只是示例实际选择器需要根据页面结构调整 for item in soup.select(.comment-item): content item.get_text(stripTrue) if content: comments.append({content: content}) if len(comments) limit: break time.sleep(0.5) # 控制频率避免对目标站点造成压力 return comments def save_json(data, filepath): with open(filepath, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2) print(fsaved {len(data)} comments to {filepath}) if __name__ __main__: demo_comments [ {content: 黑神话的画面表现太震撼了特别喜欢黄风岭的设计}, {content: 难度有点高第二章我打了三个小时才过}, {content: 剧情太碎片化了很多人看完还是一头雾水}, {content: 国产游戏做到这个水平真的值得鼓励}, ] save_json(demo_comments, data/raw/black_myth_demo.json)这段代码里做了一件很关键的事用demo_comments作为内置演示数据。真实爬虫通常无法在所有环境下稳定运行所以先用离线数据把流程打通再逐步替换成真实评论数据。4.3 从离线 JSON 导入数据实际项目中建议统一通过一个加载函数读取原始数据这样后面所有模块都不用关心数据来自爬虫还是本地文件。# 文件路径src/collector.py 中新增函数 def load_raw_data(filepathdata/raw/black_myth_demo.json): import json with open(filepath, r, encodingutf-8) as f: data json.load(f) df pd.DataFrame(data) df[content] df[content].astype(str) return df if __name__ __main__: df load_raw_data() print(df.head()) print(总评论数:, len(df))运行后如果正常打印出 DataFrame 和总评论数说明数据已经成功加载。后续的所有清洗、分析和可视化步骤都从这个入口开始。5. 数据清洗与中文预处理数据清洗是中文文本分析最容易被低估的环节。很多刚接触数据分析的人会直接把原始评论丢进 Jieba 分词结果发现词云的顶部全是“我们”“什么”“一个”这种无意义词。原因很简单没有去掉停用词也没有过滤无效字符。5.1 清洗规则设计针对《黑神话悟空》评论数据清洗规则至少应该覆盖以下四类问题。第一类是重复内容。同一个梗可能在评论区被反复复制去重可以避免高频词被无意义放大。第二类是无效字符。表情符号、URL、用户、#话题# 标签等需要归一化或直接删除。第三类是超短文本。长度小于 2 个字的内容通常信息量极低。第四类是通用停用词和领域停用词。前者如“的”“了”“和”后者如“哈哈哈”“666”“支持”。# 文件路径src/cleaner.py import re import pandas as pd def clean_text(text): text re.sub(r[^], , text) text re.sub(r\w, , text) text re.sub(rhttps?://\S, , text) text re.sub(r#\w#, , text) text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9。、「」《》], , text) text text.strip() return text def deduplicate(df, keycontent): df df.drop_duplicates(subset[key], keepfirst) return df def filter_short_text(df, min_len2, keycontent): df df[df[key].str.len() min_len] return df def load_stopwords(filepathdicts/stopwords.txt): with open(filepath, r, encodingutf-8) as f: return set([line.strip() for line in f if line.strip()]) def preprocess(df, keycontent): df df.copy() df[clean_content] df[key].apply(clean_text) df deduplicate(df, keyclean_content) df filter_short_text(df, keyclean_content) return df if __name__ __main__: from collector import load_raw_data raw_df load_raw_data() clean_df preprocess(raw_df) print(清洗前:, len(raw_df), 清洗后:, len(clean_df)) print(clean_df[[content, clean_content]].head())运行这段代码后你会看到原始文本和清洗后文本的对比。如果清洗后的评论数量明显减少这是正常的说明去重和无效文本过滤起到了作用。5.2 自定义词典与分词Jieba 默认词典对《黑神话悟空》的专有名词支持不足。“天命人”“杨戬”“筋斗云”“四妹”“黄风岭”等词会被切碎成多个字严重影响词频统计和主题模型效果。解决方法是在项目里维护一个自定义词典。# 文件路径dicts/black_myth_dict.txt 黑神话 10 n 天命人 10 n 杨戬 10 nr 黄风岭 10 ns 四妹 10 n 空气墙 10 n 定身术 10 n 广智 10 nr 幽魂 10 n 大圣 10 n每一行的格式为“词语 词频 词性”词频建议设置得比默认词频高具体数值可以按效果调整。自定义词典写好之后在分词前加载。import jieba jieba.load_userdict(dicts/black_myth_dict.txt) def tokenize(text): return [w for w in jieba.lcut(text) if w.strip()] # 测试示例 sample 空气墙太多了打杨戬的时候老是绕不过去 print(tokenize(sample))如果输出结果是“空气墙 / 太多 / 了 / 打 / 杨戬 / 的 / 时候 / 老是 / 绕不过去”说明自定义词典生效了。6. 情感分析与主题挖掘6.1 情感分析从评论文本到情感得分中文评论情感分析有两种常见路线。一种是基于标注数据训练分类模型效果更好但成本较高另一种是使用现成的情感分析工具比如 SnowNLP。SnowNLP 的sentiments属性会返回一个 0 到 1 之间的值越接近 1 表示情感越积极越接近 0 表示越消极。SnowNLP 本身是基于电商评论语料训练的对游戏评论的适配并不完美。所以实际项目中不建议直接认定“得分大于 0.6 就是好评”而应该先抽一批样本做人工核对再决定阈值。这里给出一个可调的区间映射方案。# 文件路径src/analyzer.py from snownlp import SnowNLP def sentiment_score(text): try: return SnowNLP(text).sentiments except Exception: return 0.5 def map_sentiment(score, pos_th0.6, neg_th0.4): if score pos_th: return 正面 elif score neg_th: return 负面 else: return 中性 def add_sentiment_column(df, content_colclean_content): df df.copy() df[sentiment_score] df[content_col].apply(sentiment_score) df[sentiment_label] df[sentiment_score].apply(map_sentiment) return df这里把情感映射逻辑独立成函数后续调整阈值时不需要改动主流程。情绪分布可以按“正面 / 中性 / 负面”三档统计也可以按 0.1 的步长分成十档看整体分布形态。6.2 基于词频的关键话题发现情感分析回答的是“大家是夸还是骂”词频统计则回答“大家到底在讨论什么”。把清洗后的文本按自定义词典分词过滤停用词后统计 Top N 关键词这一步可以为后续 LDA 主题模型提供直观参考。from collections import Counter def get_top_keywords(df, content_colclean_content, top_n30): words [] for text in df[content_col].dropna(): words.extend(tokenize(text)) words [w for w in words if w not in load_stopwords()] counter Counter(words) return counter.most_common(top_n) top_words get_top_keywords(clean_df, top_n30) for word, count in top_words: print(word, count)不同主题会在 Top 词上形成明显区分。比如画面相关的评论会高频出现“画质”“光影”“场景”“震撼”战斗相关的评论会高频出现“难度”“BOSS”“闪避”“招式”剧情相关的评论会出现“剧情”“结局”“原著”“改编”。这些词本身就是分析结论的重要论据。6.3 LDA 主题建模把评论聚成几个可解释的话题词频只能告诉用户“哪些词出现得多”但没法直接说明“这些评论可以被分成几个话题”。LDA 主题模型可以做到这一点。它的基本思想是每一条评论是由若干个主题混合生成的每个主题又是由一组词构成的概率分布。训练完成后我们可以观察每个主题的高概率词给主题起一个人类能读懂的名字。# 文件路径src/analyzer.py 中新增函数 import gensim import gensim.corpora as corpora from pprint import pprint def train_lda(df, content_colclean_content, num_topics5): texts [] for text in df[content_col].dropna(): words [w for w in tokenize(text) if w not in load_stopwords()] if words: texts.append(words) dictionary corpora.Dictionary(texts) corpus [dictionary.doc2bow(text) for text in texts] lda_model gensim.models.LdaModel( corpuscorpus, id2worddictionary, num_topicsnum_topics, random_state42, passes10, ) return lda_model, dictionary, corpus lda_model, dictionary, corpus train_lda(clean_df, num_topics5) pprint(lda_model.print_topics(num_words8))LDA 的训练结果很大程度上取决于超参数num_topics的取值。5 个主题不一定合适建议分别尝试 3、5、7 三个值然后对比主题词的区分度。如果几个主题的高概率词高度重叠说明主题数量设置偏少如果某个主题的词完全没有业务含义则说明评论本身太短或停止词过滤不彻底。这里有一个容易被忽视的问题评论属于短文本单条评论只有几十个字直接跑 LDA 的效果通常一般。更稳妥的做法是先把所有评论按用户 ID 聚合如果数据没有用户 ID就按时间段聚合把一段时间内的所有评论拼成一条长文本再输入 LDA。聚合后的文本质量会明显提升。7. 可视化看板与毕设演示流程7.1 核心图表设计可视化不是把所有能画的图都堆上去而是围绕分析故事线来安排图表。建议一个演示看板只包含四类图。第一张是词云图直观展示高频关键词第二张是情感分布饼图或柱状图展示正面、中性、负面评论的占比第三张是时间趋势折线图展示不同日期的评论量和情感均值变化用于回答“口碑有没有随时间变化”的问题第四张是主题权重图展示 LDA 模型发现的几个主题占比。Pyecharts 生成图表的方式比较直观。以词云为例可以直接从 Top 词列表生成 HTML 文件。# 文件路径src/visualizer.py from pyecharts.charts import WordCloud from pyecharts import options as opts def draw_wordcloud(top_words, output_pathdata/result/wordcloud.html): words [(word, count) for word, count in top_words] chart WordCloud() chart.add(, words, word_size_range[20, 100]) chart.set_global_opts(title_optsopts.TitleOpts(title黑悟空评论关键词词云)) chart.render(output_path) print(wordcloud saved to, output_path)情感分布图可以用饼图也可以用横向柱状图。如果情感倾向集中在正面和负面两个极端饼图更有冲击力如果想对比不同时间段的情感变化则折线图更合适。from pyecharts.charts import Pie, Line def draw_sentiment_pie(df, output_pathdata/result/sentiment_pie.html): label_counts df[sentiment_label].value_counts() data [(label, int(count)) for label, count in label_counts.items()] chart Pie() chart.add(, data, radius[40%, 75%]) chart.set_global_opts(title_optsopts.TitleOpts(title评论情感分布)) chart.render(output_path) print(sentiment pie saved to, output_path)7.2 用 Streamlit 搭建演示前端如果不想写复杂的前端页面Streamlit 是最快的方案。全部代码可以放在一个文件里展示逻辑和图表逻辑直接复用前面的分析函数。# 文件路径src/app.py import streamlit as st from collector import load_raw_data from cleaner import preprocess from analyzer import add_sentiment_column, get_top_keywords from visualizer import draw_wordcloud, draw_sentiment_pie st.set_page_config(page_title黑悟空评论数据分析系统, layoutwide) st.title(黑悟空评论数据分析系统) st.subheader(1. 数据概览) raw_df load_raw_data() clean_df preprocess(raw_df) st.write(f原始评论数{len(raw_df)} 条) st.write(f清洗后评论数{len(clean_df)} 条) st.dataframe(clean_df[[clean_content]].head(10)) st.subheader(2. 情感分析) emotion_df add_sentiment_column(clean_df) st.bar_chart(emotion_df[sentiment_label].value_counts()) st.subheader(3. 高频关键词) top_words get_top_keywords(clean_df, top_n30) st.write(top_words) draw_wordcloud(top_words, data/result/wordcloud.html) draw_sentiment_pie(emotion_df, data/result/sentiment_pie.html)运行命令很简单streamlit run src/app.py启动后浏览器会自动打开一个本地页面你可以看到数据概览、情感分析结果和词云图。这个演示流程足够支撑毕业设计答辩时的现场演示而且不依赖外部网络非常稳。8. 常见问题与排查思路问题现象可能原因排查方式解决方案中文显示为乱码文件编码不是 UTF-8检查文件头用 Python 打开时确认 encoding 参数保存文件统一使用 UTF-8 编码爬虫返回 403缺少请求头或频率过高打印响应状态码和响应头补充 User-Agent、Referer降低请求频率分词结果不包含领域词自定义词典未加载或词语不规范打印jieba.lcut的结果在分词前调用load_userdict检查词典格式情感分析结果集中在 0.5 附近评论文本过短或 SnowNLP 训练语料不匹配抽样 50 条人工标注对比调整情感阈值或考虑用大模型 API 做二次分析LDA 主题词高度重叠主题数量设置不合适或文本太短对比不同主题数的困惑度检查词干增加num_topics或按用户/时间段聚合文本Streamlit 页面无图表图表输出路径错误或模块未成功渲染查看终端日志确认 HTML 文件是否生成检查 Pyecharts 渲染路径改用 st.plotly_chart 或 st.image 展示清洗后数据量过少过滤规则太激进查看被删除样本统计停用词命中情况放宽短文本阈值或保留部分表情符号作为特征9. 毕业设计答辩与工程化最佳实践9.1 答辩演示清单毕业设计演示最忌讳的是“现场写代码”或“现场爬数据”。更稳妥的演示节奏是先展示系统首页和数据总览再展示情感分布接着展示高频关键词和主题模型最后用一句话总结项目结论。演示前需要准备三样东西。第一离线数据集确保断网时系统能正常运行。第二一份分析结论摘要比如“画面和美术是本游戏最受好评的维度而难度设计和优化问题主要集中在负面评论中”。第三录制一份 5 分钟左右的完整演示视频防止现场环境出现意外。9.2 从毕设到工程项目的三个建议第一个建议是做好数据处理过程留痕。答辩时评委非常关心“数据从哪来、清洗规则是什么、为什么这样做”。建议在项目 README 中写入原始数据规模、清洗后数据规模、使用的词典版本、情感阈值设置依据。这些内容看似琐碎但能体现工程严谨性。第二个建议是先把单机流程跑通再考虑技术升级。不要一开始就引入 Spark 或 Flink 这类大数据框架。评论数据量通常只有几万到几十万条单机 Python 完全能处理。先保证分析结果可复现再谈性能优化。第三个建议是给系统留一个“扩展接口”。可以在分析模块中预留一个model_provider参数后续想从 SnowNLP 切换到大模型 API 时只需要替换模型调用实现不需要改动清洗和可视化代码。这种接口设计对面试表达也有加分。9.3 数据安全与合规评论区数据属于平台公开数据但任何采集行为都必须以“公开、合法、非商业用途”为前提。项目代码中要加上数据来源说明并且不要公开发布带有用户 ID 和个人信息的原始数据。如果使用别人的公开数据集要注意其许可协议。从《黑神话悟空》评论这个具体场景出发你已经掌握了一套完整的“采集 → 清洗 → 分析 → 可视化”中文文本分析流水线。这套流程不局限于游戏评论换个数据源就能复用到商品评论、影评、新闻评论等场景。下一步建议找一份自己感兴趣的评论数据集把 pipeline 完整跑一遍。真正理解了每个环节为什么这么设计才算是把这个项目从“演示代码”变成了自己的“项目经验”。
返回列表