这次我们来看一个很典型的毕业设计题目:黑悟空评论数据分析系统(项目编号 0180)。它并不是一个纯 AI 生成项目,而是一套完整的数据分析工程:把《黑神话:悟空》在公开平台上的玩家评论采集下来,经过清洗、分词、情感分析、评分分布统计之后,用可视化图表展示成一套可交互的数据看板。
这类题目能覆盖的知识点非常全:网络爬虫、数据存储、Pandas 数据处理、中文分词、情感分析、Flask Web 服务、ECharts 可视化。对计算机、大数据、电子商务、数字媒体专业的学生来说,答辩时能讲的内容足够多,也容易演示。而且它不像深度学习项目那样依赖 GPU,普通笔记本就能跑完整个流程。
这篇文章不会把某个现成项目的代码逐行贴出来,而是把评论数据分析系统的完整实现路线拆开讲:系统怎么设计、数据从哪来、清洗和分析怎么做、可视化看板怎么搭、API 接口怎么暴露、最容易踩的坑有哪些。如果你正在做同类毕业设计,或者想拿一份真实评论数据练手数据分析,这个思路可以直接落地。
1. 项目核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 数据采集 + 数据分析 + 可视化展示系统 |
| 数据源 | 《黑神话:悟空》公开玩家评论、公开评论接口或自建样本数据 |
| 核心功能 | 评论采集、数据清洗、情感分析、词频统计、评分分布、可视化看板 |
| 技术栈 | Python、Flask、Pandas、jieba、SnowNLP、pyecharts/ECharts、SQLite/MySQL |
| 运行环境 | Windows / Linux / macOS 均可,普通笔记本即可,无需 GPU |
| 启动方式 | 命令行启动 Web 服务,浏览器访问看板页面 |
| API 支持 | 提供 JSON 格式接口,支持前端动态加载和批量导出 |
| 批量任务 | 支持批量评论数据导入、定时增量采集、批量情感分析 |
| 适合场景 | 毕业设计演示、数据分析课程设计、评论舆情分析学习 |
从项目定位来看,这个系统的核心亮点不是某个算法有多先进,而是把数据分析的完整链路串起来了。用户从浏览器打开看板,能看到评论总量、情感占比、评分分布、高频词云、时间趋势,这些内容对非技术背景的演示对象非常直观。
2. 系统整体架构与功能模块
评论数据分析系统的架构通常可以分为四层:
采集层:负责从公开平台获取评论数据。常见的输入形式有三种:直接调用平台公开接口、解析公开页面、读取已经导出的 CSV/Excel 文件。对于毕业设计来说,第三种方式最稳妥,第二种方式最容易演示。
存储层:把采集到的评论写入数据库。SQLite 适合演示场景,零配置、单文件、随拷随走;MySQL 适合更正式的项目结构,便于展示数据库设计能力。
分析层:对评论做清洗、去重、分词、停用词过滤、情感打分、词频统计,这一步是整个系统的核心。
展示层:用 Flask 提供 Web 服务和 JSON API,前端页面通过 ECharts / pyecharts 渲染图表,也可以直接生成静态 HTML 报告。
这种分层设计的优点是:每一层都可以单独测试和替换。比如爬虫被平台限制时,可以直接用文件导入代替;情感分析模型不满意时,可以换词典法实现,不需要动其他模块。
3. 适用场景与合规边界
这类项目适合以下人群:
- 正在做毕业设计或课程设计,需要一套完整可演示的数据分析系统的学生;
- 想学习 Python 数据分析全流程的开发者;
- 需要对游戏评论、商品评论做舆情分析的运营或产品人员。
要注意的是,评论数据属于用户生成内容,使用时有几条边界必须守住:
- 优先使用公开接口或公开数据集。如果接口没有开放或者使用条款不允许批量下载,就不要强行抓取。
- 采集频率必须克制。无论从哪个平台获取数据,都要避免高并发请求对源站造成压力。可以在代码里加请求间隔和失败重试。
- 仅用于学习研究和毕业设计演示,数据不能用于商业用途,也不能二次传播原始用户隐私信息。
- 展示时对用户名等敏感信息做脱敏。如果看板会公开展示,最好只保留评论内容和情感标签。
- 涉及模型、图片、美术素材等内容时,注意版权声明,不要直接提取游戏内素材作为商业作品素材。
这些合规要求不只是写在文档里,也建议在系统界面上加一句“演示数据仅供学习研究使用”。
4. 开发环境与依赖准备
这个项目的环境要求不高,核心条件就三个:Python 3.8 以上、pip 可用、网络能访问 PyPI。
推荐使用虚拟环境隔离依赖:
python -m venv venv # Windows venv\Scripts\activate # Linux / macOS source venv/bin/activate安装依赖:
pip install flask pandas sqlalchemy pymysql pyecharts jieba snownlp requests beautifulsoup4 openpyxl依赖说明:
| 依赖库 | 用途 |
|---|---|
| flask | 提供 Web 服务和 JSON API |
| pandas | 数据清洗与统计分析 |
| sqlalchemy | 数据库 ORM,方便切换 SQLite/MySQL |
| pycharts | 生成可视化 HTML 图表 |
| jieba | 中文分词 |
| snownlp | 中文情感分析(也可用规则词典替换) |
| requests / beautifulsoup4 | 请求公开接口、解析页面 |
| openpyxl | 读取和导出 Excel 数据 |
硬件方面,普通办公笔记本即可。评论数据通常几十万条以内,Pandas 完全能处理;如果数据量到百万级别,建议用 SQL 聚合替代 Pandas 全表加载,或者换 MySQL 存储。
5. 数据准备与存储设计
5.1 数据来源选择
《黑神话:悟空》这类热门游戏的评论数据有很多公开渠道。常见做法有三种:
- 公开评论接口:部分平台提供 JSON 评论接口,按游戏 ID 和时间分页拉取。这种方式适合演示“爬虫采集”能力,但必须确认接口允许访问、控制请求频率。
- 公开数据集:GitHub、Gitee、Kaggle 上有人整理过热门游戏评论数据集,下载后作为 CSV 导入系统即可。
- 手工整理:从公开页面复制部分评论,整理成 Excel 用于功能演示。这种方式数据量小,但足够跑通整个流程。
无论用哪种方式,建议在项目目录下保留一份原始数据备份,这样即使接口失效,演示也不会中断。
5.2 评论表结构设计
下面是通用的评论表结构,可以作为存储层设计参考:
CREATE TABLE IF NOT EXISTS comments ( id INTEGER PRIMARY KEY AUTOINCREMENT, platform VARCHAR(32) COMMENT '来源平台', user_name VARCHAR(64) COMMENT '用户昵称(展示时脱敏)', score VARCHAR(16) COMMENT '推荐/不推荐或数值评分', content TEXT COMMENT '评论内容', comment_time DATETIME COMMENT '评论时间', sentiment VARCHAR(16) COMMENT '正向/中性/负向', sentiment_score DECIMAL(5, 4) COMMENT '情感得分', created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '入库时间' );如果你的毕设要求使用 MySQL,可以把AUTOINCREMENT换成AUTO_INCREMENT,并在config.py里配置连接串。SQLite 的优势是零配置文件、方便演示,但不利于展示“数据库设计”能力;正式一点的项目可以用 MySQL。
6. 数据采集模块实现
数据采集模块的核心是稳定性和可控性。不要一上来就写大规模并发爬虫,先把单页请求跑通,再加分页和去重。
以 Steam 公开评论接口为例(store.steampowered.com/appreviews/{appid}),代码思路如下:
import requests import pandas as pd import time # Steam 公开评论接口示例 # 实际项目需要结合目标平台接口和授权情况调整,采集前务必确认平台允许访问 url = "https://store.steampowered.com/appreviews/1245620" params = { "json": 1, "language": "schinese", "num_per_page": 20, "cursor": "*", } headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } resp = requests.get(url, params=params, headers=headers, timeout=30) data = resp.json() if data.get("success") == 1: reviews = data.get("reviews", []) rows = [] for r in reviews: rows.append({ "platform": "steam", "user_name": r.get("author", {}).get("steamid", ""), "score": "推荐" if r.get("voted_up") else "不推荐", "content": r.get("review", "").replace("\n", " "), "comment_time": r.get("timestamp_created", 0), }) df = pd.DataFrame(rows) print(df.head()) else: print("请求失败,请检查参数或接口可用性")采集时注意几个细节:
- 每次请求之间加
time.sleep(2)左右,降低触发频率限制的概率; - 分页游标从响应中读取,不要用固定页数硬爬;
- 失败请求要记录日志,方便断点续采;
- 原始响应保存一份 JSON 或行式文本,避免后续清洗失败后还要重新拉取。
如果不想依赖外部接口,也可以在系统里加一个“CSV 导入”入口,用户可以上传预先整理好的评论文件,系统解析后写入数据库。这种方式更适合现场演示,因为它不依赖网络环境。
7. 评论清洗与情感分析
7.1 数据清洗
原始评论数据通常有很多噪声,比如 HTML 标签、emoji、连续空白、无意义短评。清洗规则要控制得克制一些,不要影响正常评论表达。
import re import jieba STOPWORDS = {"的", "了", "是", "我", "你", "他", "这", "那", "就", "都", "也"} def clean_comment(text: str) -> str: # 去掉 HTML 标签 text = re.sub(r"<[^>]+>", "", text) # 去掉多余空白 text = re.sub(r"\s+", " ", text).strip() return text def filter_useless(text: str) -> bool: # 过滤过短评论 if len(text) < 2: return False # 过滤纯数字、纯标点、无意义灌水 if re.fullmatch(r"[\W\d_]+", text): return False return True def tokenize(text: str) -> list: words = jieba.lcut(text) return [ w for w in words if w.strip() and w not in STOPWORDS and not re.fullmatch(r"[\W\d_]+", w) ]清洗完成后,建议输出一份清洗前后的统计对照:原始评论数、清洗后有效评论数、按平台分布、按时间分布。这组数字在答辩时非常有用,能直观说明数据处理流程的有效性。
7.2 情感分析
中文评论情感分析有两个常用方案:
方案一:SnowNLP 模型
from snownlp import SnowNLP def analyze_sentiment(text: str): try: score = SnowNLP(text).sentiments except Exception: score = 0.5 if score >= 0.6: return "正向", round(score, 4) if score <= 0.4: return "负向", round(score, 4) return "中性", round(score, 4)SnowNLP 的优势是开箱即用,缺点是对游戏领域评论不一定准确,比如“这游戏真肝”会被打成正向。如果效果不好,可以换成情感词典规则法:维护一个积极词表和一个消极词表,计算评论中两类词的出现次数,再结合否定词和程度副词做调整。
对于毕设演示,建议先跑 100 条评论做人工核对,如果准确率能到 70% 以上就可以用;如果明显偏低,就换词典法或考虑用已开源的中文评论情感模型。
7.3 词频统计
词频统计直接喂给词云图:
from collections import Counter def word_freq_from_texts(texts: list): counter = Counter() for t in texts: counter.update(tokenize(t)) return counter.most_common(100)高频词可以结合情感标签做交叉分析,比如“美术”“剧情”“优化”在正向和负向评论中的排名差异,这种分析比单独一个词云有深度得多。
8. 统计分析与可视化看板
8.1 分析维度
建议从五个维度设计可视化看板:
| 维度 | 图表类型 | 说明 |
|---|---|---|
| 评论总量与情感占比 | 数字卡片 + 饼图 | 一眼看出整体口碑 |
| 评分分布 | 柱状图 | “推荐/不推荐”或 1-5 星分布 |
| 评论时间趋势 | 折线图 | 按天/周统计评论数量,观察发售和更新节点 |
| 高频词 | 词云 | 展示玩家讨论最多的话题 |
| 情感与关键词交叉分析 | 横向柱状图 | 正向高频词 vs 负向高频词 |
pyecharts 可以直接生成 HTML 文件,适合静态报告;也可以通过 Flask 渲染模板,把图表嵌入到动态页面。推荐后者,因为可以配合接口动态切换时间范围、情感类型。
8.2 生成词云
pyecharts 的WordCloud组件可以直接接收词频列表:
from pyecharts.charts import WordCloud from pyecharts import options as opts def render_wordcloud(word_items, output_path="output/wordcloud.html"): c = ( WordCloud() .add("", word_items, word_size_range=[12, 80], shape="circle") .set_global_opts(title_opts=opts.TitleOpts(title="评论高频词")) ) c.render(output_path)输出文件放在output/目录下,Flask 里可以做静态文件映射,让浏览器直接访问。这里要注意中文显示问题,词云组件默认字体可能不支持中文,需要在系统里指定中文字体路径,否则图表里的中文会变成方块。
9. Web 服务与接口 API
9.1 Flask 服务骨架
from flask import Flask, jsonify, request import sqlite3 app = Flask(__name__) DB_PATH = "data/blackmyth.db" def query_db(sql, args=(), one=False): conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row cur = conn.execute(sql, args) rows = cur.fetchall() conn.close() return (rows[0] if rows else None) if one else rows @app.route("/api/overview", methods=["GET"]) def overview(): total = query_db("SELECT COUNT(*) AS cnt FROM comments", one=True)["cnt"] positive = query_db("SELECT COUNT(*) AS cnt FROM comments WHERE sentiment='正向'", one=True)["cnt"] negative = query_db("SELECT COUNT(*) AS cnt FROM comments WHERE sentiment='负向'", one=True)["cnt"] return jsonify({ "total": total, "positive": positive, "negative": negative, "neutral": total - positive - negative }) @app.route("/api/comments", methods=["GET"]) def comment_list(): page = int(request.args.get("page", 1)) size = int(request.args.get("size", 20)) offset = (page - 1) * size rows = query_db("SELECT id, platform, score, content, sentiment FROM comments LIMIT ? OFFSET ?", (size, offset)) return jsonify({"items": [dict(r) for r in rows]}) if __name__ == "__main__": app.run(host="127.0.0.1", port=8000, debug=False)启动服务:
python app.py浏览器访问:
http://127.0.0.1:8000/api/overview如果页面能返回 JSON 数据,说明服务已经跑通。
9.2 接口验证
curl "http://127.0.0.1:8000/api/overview"返回示例:
{"neutral": 3, "negative": 12, "positive": 130, "total": 145}接口设计建议遵循一个原则:查询条件全部用 query 参数控制,比如start_time、end_time、sentiment、platform、page、size。这样前端可以做筛选器,后端不需要为每个筛选条件单独写接口。
10. 批量任务与定时增量采集
毕设演示里最常见的要求是“系统能自动更新数据”。这里可以用一个简单的定时任务思路来实现:
import time import logging def run_incremental_task(interval_minutes=60): while True: try: collect_recent_comments() rebuild_analysis_cache() logging.info("增量采集和分析完成") except Exception as e: logging.error(f"任务执行失败: {e}") time.sleep(interval_minutes * 60)在这个任务里,collect_recent_comments()负责拉取新增评论,rebuild_analysis_cache()负责重新计算情感占比和词频。为了避免每次刷新看板都重新全量计算,可以建立一张缓存表,把统计结果预计算好,前端接口只读缓存,这样响应速度会快很多。
批量导入功能也建议做成独立函数,支持 CSV 和 Excel:
import pandas as pd def import_comments_from_file(file_path, platform="csv"): if file_path.endswith(".csv"): df = pd.read_csv(file_path) else: df = pd.read_excel(file_path) df = df.rename(columns={ "评论内容": "content", "评分": "score", "时间": "comment_time", }) # 写入数据库,这里只打印示意 print(f"准备导入 {len(df)} 条评论")批量任务最需要关注的是失败重试和日志。不要只打印一行error,至少记录时间、任务阶段、失败条数和异常堆栈,方便后续排查。
11. 性能观察与优化建议
评论数据分析系统的性能瓶颈通常不在算法,而在数据处理方式和页面加载速度。
数据量小时:几千到几万条评论,Pandas 直接读取、直接聚合,响应基本在毫秒级。
数据量增大后:几十万条评论,全表加载到 Pandas 会占用大量内存。优化方向有三个:
- 用 SQL 聚合代替 Pandas 全表加载,例如
SELECT sentiment, COUNT(*) FROM comments GROUP BY sentiment。 - 增加统计缓存表,定时刷新,避免每次请求都重新计算。
- 前端图表数据做分页或抽样,不在一个请求里传输全量数据。
耗时最长的任务通常是情感分析。如果几万条评论逐条调用模型打分,可能耗时几分钟。建议给情感分析增加一个“进度条 + 分批处理”能力,先在后台把结果写入数据库,前端通过接口查询处理进度。
观察性能的方法很简单:在关键函数前后记录时间戳,输出到日志:
import time start = time.time() analyze_all_comments() print(f"情感分析耗时: {time.time() - start:.2f}s")这个日志在答辩演示时也可以直接展示,说明你做过性能评估。
12. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 评论接口请求失败 | 网络代理、接口参数错误、频率限制 | 查看响应状态码和错误信息 | 加请求间隔、切换备用数据源、改用本地 CSV 导入 |
| 数据库表不存在 | 未执行建表 SQL 或连接了错误数据库文件 | 检查DB_PATH和启动日志 | 在启动入口自动执行建表脚本 |
| 中文图表显示为方块 | 图表组件缺少中文字体 | 检查系统字体和 pyecharts 字体配置 | 指定中文字体路径,如C:/Windows/Fonts/simhei.ttf |
| 情感分析结果偏正向或偏负向 | SnowNLP 领域适配性差 | 抽 100 条人工核对 | 换情感词典法,或收集领域语料微调 |
| 页面打开很慢 | 接口实时全量计算 | 看接口响应时间日志 | 增加统计缓存表、使用 SQL 聚合 |
| 接口返回 500 | 查询 SQL 语法错误、字段不存在 | 查看 Flask 异常日志 | 用独立测试脚本直接执行 SQL,确认字段名 |
| 批量导入重复数据 | 没有去重逻辑 | 检查数据库主键和导入日志 | 以用户 ID + 评论时间 + 内容哈希做唯一约束 |
| 端口 8000 被占用 | 上一个服务进程未退出 | `netstat -ano | findstr 8000` 查看占用 |
排查问题有一个通用思路:先看日志、再单测数据、最后替换组件。不要一上来就怀疑算法有问题,先确认数据管道通了再说。
13. 最佳实践与项目扩展方向
做这类毕业设计项目,建议从一开始就养成这些习惯:
- 目录结构清晰。数据文件、代码、输出报告、文档分目录管理,不要全部堆在根目录。
blackmyth-comment-analysis/ ├── app.py # Flask 入口 ├── config.py # 配置文件 ├── collector/ # 数据采集 ├── analyzer/ # 清洗与情感分析 ├── web/ # 前端模板与静态资源 ├── data/ # 数据库文件 ├── output/ # 导出图表和报告 └── requirements.txt第一次先小参数测试。先用 100 条评论跑通全流程,再扩展到全量数据。不要一开始就爬几万条,排查成本会很高。
保留一套最小可运行配置。把“CSV 导入 + SQLite + 静态图表”作为保底方案,即使外部接口失效,系统依然可以演示。
模型文件、输入素材、输出结果分目录管理。项目里不要出现“最终版 v2 最终版”这种命名。
接口服务限制访问范围。本地演示时监听
127.0.0.1就够了,不要监听0.0.0.0,避免同网络其他设备访问。涉及公开数据的项目要保留数据来源说明。在项目 README 里写明评论来源、采集时间和使用限制,这是负责任的做法。
后续还可以扩展的方向包括:接入 StarRocks 或 ClickHouse 做大数据量下的即时分析、用 ECharts 做大屏展示、加入基于大模型的评论摘要生成、做不同平台评论对比分析。如果时间充裕,把“单一游戏评论分析”扩展成“多游戏评论对比系统”,答辩亮点会更强。
这套系统最值得做的原因在于,它把 Python 数据分析的完整流程走了一遍:从获取数据、清洗数据、分析数据到展示数据,每一步都能看到可量化结果。最先验证的功能应该是“CSV 导入 + 情感分析 + 看板展示”这条主链路;最容易踩的坑则是中文图表乱码和接口请求失败。先把这两件事搞定,整个项目就稳了。