ARTICLE DETAIL

资讯详情

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

Python+MySQL评论数据分析:从数据清洗到可视化完整链路

Python+MySQL评论数据分析:从数据清洗到可视化完整链路 前阵子有个准备转行的同学发来一个课程链接标题很直接写着“基于 PythonMySQL 的泡泡玛特热搜评论数据分析项目练完写进简历一周拿到 Offer”。他问我这东西靠谱吗练完真的能写进简历吗我的判断是项目本身不唬人但标题暗示的路径有问题。它把 Python、MySQL、数据分析串在了一起还给了“热搜评论”这个足够具体的业务场景这对练习者来说其实是很好的素材。真正决定你能不能靠它拿到面试机会的不是“练完”而是你能不能向面试官讲清楚你处理的是什么数据表结构为什么这样设计清洗时去掉了什么SQL 按什么逻辑在做聚合最后分析结论是怎么从图表里长出来的。所以这篇文章不打算顺着标题再吹一遍“一周拿 Offer”。我想把项目拆成一条可以迁移到任何评论类、舆情类、商品反馈类场景的完整链路数据准备、表设计、清洗入库、SQL 分析、可视化解读、简历表达。你能跑通这一条比“再做五个同款项目”有用得多。1. 先拆穿“一周拿 Offer”这个项目练的其实是完整的数据分析闭环1.1 项目表面是“热搜评论分析”实质是文本数据全流程如果只看项目名你会误以为重点在“热搜”。但一个热搜词本身没有太大分析价值真正有分析空间的是两条数据线评论数据用户发布了什么内容、在哪个平台、什么时候发布、获得了多少点赞。热搜词数据哪个关键词在什么时间进入了热搜榜单、热度是多少、是否持续上涨。把这两条数据结合起来你才能看到一个更完整的问题某个话题在热搜上火了之后用户评论里到底在讨论什么是高高兴兴晒单还是反复追问补货信息或者有一些共性的失望和疑惑。所以这个项目并不是“爬虫项目”也不是“SQL 题目”而是一个典型的小型文本数据分析任务。它的核心价值在于把数据的生命周期完整走了一遍数据获取或导入格式探查和清洗存储与建模查询与指标计算可视化和结论产出很多人在初学阶段会把注意力放在写代码上觉得能跑出一个词云就是成功。但面试官真正想听的是你在第 3 步到第 5 步之间做了什么判断。这部分才是可迁移的能力。1.2 招聘方看的不是项目名而是项目里的决策点为什么不能只用一句话描述项目因为只有一句话等于没有信息量。面试官听到“泡泡玛特热搜评论数据分析”时他脑中立刻会出现几个问题你的评论数据是从哪里来的这个数据的采集边界是什么你为什么要建两张表表结构里有哪些字段为什么主键这样设置清洗做了哪几步有没有做过去重你做小时级趋势分析时MySQL 的索引是怎么设计的数据量到 10 万条会慢吗评论是文本你如何判断情感倾向你的判断依据是词典还是模型最后给出的建议是拍脑袋得出的还是从数据里推导出来的如果这些问题你都回答得比较清楚这个项目才能真正成为简历里的加分项。否则项目就只是一个“跟着教程跑通的网页”。这也是这类标题充满诱惑力和欺骗性的地方它让你以为最困难的是“开始”其实最困难的永远是“过程中的决策”和“收尾时的解释”。在这个项目里我的建议是先按一个小型舆情分析系统的思路来做而不是按一个爬虫脚本的思路来做。你不需要做成企业级平台但至少要有一条清晰的数据链路。2. 环境与数据源先把地基搭好再讨论爬虫和接口2.1 Python 和 MySQL 环境怎么准备先确认版本少走弯路这个项目的最基本依赖是 Python 和 MySQL。很多人会卡在第一步不是因为操作复杂而是因为版本和连接方式不匹配。如果你一开始接触的是 Python 3.12、MySQL 8.0那就围绕这套版本去配置不要去看太旧的教程。推荐先安装好Python 3.10 或更高版本MySQL 8.0一个 MySQL 图形化客户端比如 Navicat、DataGrip、MySQL Workbench一个虚拟环境专门给这个项目使用创建虚拟环境后把基础依赖装好python -m venv .venv source .venv/bin/activate # Windows 下使用 .venv\Scripts\activate pip install pandas pymysql sqlalchemy cryptography openpyxl matplotlib jieba这里有几个容易踩的细节pymysql是 Python 连 MySQL 的驱动。如果 MySQL 是 8.x默认认证插件是caching_sha2_password。pymysql要正常工作通常需要先装cryptography。如果你一上来就把 MySQL 的认证插件改成老版本反而会给以后埋坑。sqlalchemy用来给pandas.read_sql提供稳定的连接通道。对于这类型项目直接用pymysql.connect也可以但我更推荐用 SQLAlchemy 的create_engine因为后面从 MySQL 读表做可视化时会方便很多。openpyxl是 pandas 读写 Excel 时常用的底层引擎。如果数据文件是 CSV可以不装但很多时候你会拿到 xlsx 格式的评论数据。jieba是做中文分词用的。后面要跑词频或词云它比直接按空格分词靠谱得多。2.2 数据来源的合规边界不是所有数据都能爬这是很多人会忽略但非常重要的一步。做数据分析项目时数据来源必须干净、合规。一个常见误解是只要我用 Python 写了一个爬虫把某个平台的热搜评论抓下来了这个项目就更有含金量。但在真实工作和面试里数据采集的合规性要远远优先于技术实现的炫酷程度。对于学习项目比较稳妥的数据来源有这样几种公开数据集有些开源社区会存放匿名的电商评论或社交媒体评论数据你可以下载后用于学习分析。官方提供的开放接口如果平台提供公开 API并且允许你做数据分析用途可以按文档调用。自建演示数据完全模拟生成一批评论和热搜数据。虽然它不等于真实数据但足够用来练习清洗、入库、SQL 和可视化全流程。合规爬取的数据需要遵守平台的 robots 协议、服务条款控制请求频率并且只采集公开且非隐私的信息。千万不要采集账号隐私、私信、未公开联系方式等字段。我的建议是如果你只是第一次做这个项目先别把时间花在爬虫上。你完全可以先构造 1 万条左右的模拟数据把链路跑通之后再考虑替换成真实授权数据。把数据获取和数据处理分开练效率更高。2.3 没有真实数据时构造一个“最小可用数据集”构造数据并不是编故事而是为了让你掌握数据处理的逻辑。你可以先做一个只有 100 条的 CSV 文件用来验证链路。如果表结构设计有问题100 条数据就能让你发现如果没问题再扩展成 1 万条也不迟。假设comment.csv的结构如下comment_idplatformtopic_keywordcontentcomment_timelike_countC0001微博手感感觉这次的手感有点不一样但还是很喜欢2025-04-01 10:21:0012C0002微博补货门店到底什么时候补货等了好几天2025-04-01 10:35:003C0003小红书隐藏款拆到隐藏款了开心到爆炸2025-04-01 11:02:0078再假设hot_search.csv的结构如下keywordhot_valueevent_time泡泡玛特新品8500002025-04-01 08:00:00补货3200002025-04-01 10:00:00这样一个最小数据集能帮你跑通后面所有流程。最重要的不是数据真实与否而是你先有一个稳定的“输入边界”。3. 从 CSV 到 MySQL清洗思路和批量入库的工程细节3.1 数据建模把评论和热搜话题分开设计很多新手会在建表阶段犯一个错误把所有字段都塞进一张表。看起来省事但后期分析会遇到很多麻烦。这里我建议采用最简单的两张表设计comments保存每条评论的明细。hot_search保存热搜关键词在不同时间点的热度。这两张表通过topic_keyword字段建立弱关联。因为评论不一定要知道热搜的完整热度曲线热搜表也不应该重复存储评论内容。comments表的字段可以这样设计CREATE TABLE IF NOT EXISTS comments ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, comment_id VARCHAR(64) NOT NULL COMMENT 评论唯一ID, platform VARCHAR(32) NOT NULL DEFAULT COMMENT 来源平台, topic_keyword VARCHAR(64) NOT NULL COMMENT 关联话题词, content TEXT COMMENT 评论正文, comment_time DATETIME NOT NULL COMMENT 评论发布时间, like_count INT NOT NULL DEFAULT 0 COMMENT 点赞数, sentiment_score DECIMAL(3, 2) DEFAULT NULL COMMENT 情感倾向分, UNIQUE KEY uk_comment_id (comment_id), KEY idx_time (comment_time), KEY idx_keyword (topic_keyword) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;hot_search表可以设计成CREATE TABLE IF NOT EXISTS hot_search ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, keyword VARCHAR(64) NOT NULL, hot_value BIGINT NOT NULL DEFAULT 0, event_time DATETIME NOT NULL, KEY idx_keyword_time (keyword, event_time) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;这里面的几个设计选择面试时可以主动讲comment_id要加唯一索引因为评论区经常有重复数据入库时去重更安全。正文一定要用utf8mb4因为 MySQL 的老版utf8并不完整支持所有中文和 emoji。评论数据里经常有 emoji如果字符集不对入库时要么报错要么变成乱码。content使用TEXT足够但如果你要存很长的文本比如几千字的评论那要改成MEDIUMTEXT。sentiment_score不是必填字段。你可以在 Python 侧先算好也可以后面再回填。3.2 清洗顺序比清洗技巧更值得关注拿到原始评论 CSV 后不要直接写入 MySQL。清洗的顺序比某个具体清洗操作更重要。通常我会按这样几步来做去空白和去空值删除content为空、comment_time为空的行。时间标准化把各种格式的字符串时间统一转成datetime类型。去重基于comment_id去掉重复评论。格式规范把文本首尾空格去掉把全角数字转成半角把多余换行符压缩。敏感信息处理如果数据里有非匿名的用户 ID、手机号、地址等字段一律删除或做脱敏处理。情感分计算如果需要后续做情感分析可以在这一步先算好一个粗粒度分数。这里不需要一上来就想做一个非常完美的清洗流程。先跑通最小样本再逐步增加规则。注意清洗的第一步应该是“确认数据规模和数据字段”而不是“开始写清洗函数”。先用df.head()和df.info()把数据看明白再动手。参考代码如下import pandas as pd df pd.read_csv(comment.csv, encodingutf-8) print(df.head()) print(df.info()) df df.dropna(subset[content, comment_time]) df[content] df[content].astype(str).str.strip() df[comment_time] pd.to_datetime(df[comment_time], errorscoerce) df df.dropna(subset[comment_time]) df df.drop_duplicates(subset[comment_id], keepfirst)其中errorscoerce的意思是转换不了的时间统一变成NaT后面再一起删掉。这样可以避免某一条脏数据让整个入库脚本崩溃。情感分如果要用简单规则来做可以这样positive_words [喜欢, 快乐, 惊喜, 好看, 值得, 开心, 好拆, 满意] negative_words [失望, 缺货, 异味, 难拆, 退款, 差评, 不喜欢] def simple_sentiment(text): pos sum(1 for w in positive_words if w in text) neg sum(1 for w in negative_words if w in text) score (pos - neg) / (pos neg 1e-6) return round(score, 2) df[sentiment_score] df[content].apply(simple_sentiment)这个方法的精度并不高但作为项目的第一版已经足够。你需要明白它的局限规则词典一旦碰上否定表达“不是不喜欢”这种句子就会被误判。如果你想在面试里展示边界感提到这一点反而是加分项。3.3 四步入库建库、连接、批量写入、验证入库看起来是写代码其实是工程问题。你可以分四步来看第一步建库。from sqlalchemy import create_engine engine create_engine(mysqlpymysql://root:你的密码localhost:3306/popmart_analysis?charsetutf8mb4)如果 MySQL 尚未创建popmart_analysis数据库可以先通过 pymysql 单独建库再继续用 SQLAlchemy。也可以直接到 MySQL 客户端里执行CREATE DATABASE IF NOT EXISTS popmart_analysis DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;第二步读取连接配置。不要把数据库密码硬编码写在代码里比较适合新手的做法是把账号密码写在.env文件或本地配置区代码里用os.getenv读取。这个习惯会在你做团队项目时省很多事。第三步批量写入。一次只插入一条是新手最常见的问题。如果数据量只有 100 条还好但到了 1 万条以上逐条 insert 会非常慢。更好的方式是把数据拼成 list然后使用executemany一次批量写入import pymysql conn pymysql.connect( hostlocalhost, userroot, password你的密码, databasepopmart_analysis, charsetutf8mb4 ) sql INSERT IGNORE INTO comments (comment_id, platform, topic_keyword, content, comment_time, like_count, sentiment_score) VALUES (%s, %s, %s, %s, %s, %s, %s) data [ ( row[comment_id], row[platform], row[topic_keyword], row[content], row[comment_time], row[like_count], row[sentiment_score] ) for _, row in df.iterrows() ] with conn.cursor() as cursor: cursor.executemany(sql, data) conn.commit()这里有一个很实用的细节SQL 里的INSERT IGNORE配合comment_id唯一索引可以在遇到重复 ID 时直接跳过而不是让整个批量任务失败。如果你没有唯一索引那INSERT IGNORE的“去重”效果就名存实亡。第四步验证。入库之后先在 MySQL 客户端里执行几条查询验证SELECT COUNT(*) FROM comments; SELECT * FROM comments LIMIT 10;注意不要一上来就把全量数据写入。先用df.head(100)生成小样本等表结构和字段类型都确认无误后再跑全量入库。这个习惯能帮你区分“数据问题”和“代码问题”。4. SQL 分析先定义指标再写查询不要看到表就 select *4.1 指标定义先回答要分析什么很多人在 SQL 阶段会陷入一种状态打开表先SELECT *然后漫无目的地看几条数据最后不知道下一步该算什么。想避免这个问题可以在写 SQL 前先想清楚四类指标声量指标评论总量、搜索热度总量、按日/小时分布。互动指标总点赞数、平均点赞数、哪些评论互动量高。结构性指标不同平台评论占比、不同话题的评论占比、不同话题的热度峰值。情感指标平均情感分、正负向评论比例、负面情绪集中发生在哪个话题上。以评论数据为例当你问“哪个关键词的讨论热度最高”时不要直接看hot_search表里的最大热度值而要对比“热搜出现频率”和“评论区实际讨论量”。这两个指标可能不一致。热搜词热度高可能只是因为平台算法推荐但评论区真实讨论量大说明用户有表达欲望。把它们放在一起看才是“热搜评论分析”。4.2 核心 SQL 示例下面几个 SQL 是这个项目里比较常见的分析维度。按小时统计评论量看用户活跃时段SELECT HOUR(comment_time) AS hour_part, COUNT(*) AS comment_cnt FROM comments GROUP BY hour_part ORDER BY hour_part;按话题关键词统计评论量和平均点赞数SELECT topic_keyword, COUNT(*) AS comment_cnt, AVG(like_count) AS avg_like, ROUND(AVG(sentiment_score), 2) AS avg_sentiment FROM comments GROUP BY topic_keyword ORDER BY comment_cnt DESC LIMIT 20;关联热搜表和评论表看某个关键词的热度变化与评论量的关系SELECT h.keyword, h.hot_value, COUNT(c.comment_id) AS comment_cnt FROM hot_search h LEFT JOIN comments c ON h.keyword c.topic_keyword WHERE h.event_time 2025-04-01 00:00:00 AND h.event_time 2025-04-02 00:00:00 GROUP BY h.keyword, h.hot_value ORDER BY h.hot_value DESC;这里你会遇到一个需要甄别的点MySQL 在执行LEFT JOIN时如果comments表的数据量很大并且topic_keyword上没有索引它可能会做全表扫描查询就会变慢。所以在数据量上了 10 万条之后给topic_keyword和comment_time建索引是必要的。4.3 SQL 出问题时怎么排查如果你执行 SQL 后发现结果明显不对不要急着怀疑 SQL 语法先按排查链路走一遍确认基础数据规模执行SELECT COUNT(*) FROM comments看是不是全量数据都进去了。确认时间范围看comment_time字段的存储值是否有异常比如“2025-04-01”被存成了“2025-04-01 00:00:00”还是完整时间。确认分组逻辑如果按HOUR(comment_time)分组得到 0 点到 23 点的完整分布是正常的如果只出现几条记录大概率是时间格式或入库阶段出了问题。确认字符编码如果筛选条件里带中文但查不到结果先查SHOW VARIABLES LIKE character_set%还要看连接字符串里有没有声明charsetutf8mb4。确认聚合粒度一个话题如果在hot_search表里出现多次GROUP BY keyword后必须用AVG、MAX、SUM等聚合函数处理热度值不能直接查hot_value。否则 MySQL 5.7 之后的ONLY_FULL_GROUP_BY会直接报错即使不报错取到的那条也不一定是你要的。SQL 只是工具真正决定分析质量的是你脑子里的分析问题。先问“我想比较什么”再写查询。5. Python 可视化和业务结论让分析结果能用于面试表达5.1 用 pandas 重新读取 MySQL做二次分析数据入库后还要回到 Python 做可视化。你可以用 SQLAlchemy 建立连接再用pandas.read_sql将查询结果读成 DataFrame。import pandas as pd from sqlalchemy import create_engine import matplotlib.pyplot as plt engine create_engine(mysqlpymysql://root:你的密码localhost:3306/popmart_analysis?charsetutf8mb4) df pd.read_sql( SELECT id, platform, topic_keyword, content, comment_time, like_count, sentiment_score FROM comments , engine) df[date] pd.to_datetime(df[comment_time]).dt.date daily_data df.groupby(date).size().reset_index(namecomment_count) plt.figure(figsize(12, 5)) plt.plot(pd.to_datetime(daily_data[date]), daily_data[comment_count]) plt.title(评论量日趋势) plt.xlabel(日期) plt.ylabel(评论数) plt.grid(alpha0.3) plt.tight_layout() plt.savefig(daily_trend.png, dpi150)中文乱码是常见问题。Windows 上可以尝试plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] FalsemacOS 上可以改成Arial Unicode MSLinux 上通常是Noto Sans CJK SC。如果没有中文字体先到系统里安装对应字体再重启环境。不要一上来就改 matplotlib 源码这属于环境问题不是代码问题。如果有时间还可以继续做一张词频图或者条形图。比如统计出现次数较高的主题词import jieba from collections import Counter stop_words {我们, 今天, 这个, 一个, 什么, 还是, 可以, 真的, 感觉} words [] for text in df[content].dropna(): for word in jieba.cut(text): word word.strip() if len(word) 2: continue if word in stop_words: continue words.append(word) counter Counter(words) top_words counter.most_common(20) print(top_words)词云可做可不做。对面试来说条形图比词云更容易讲清楚。5.2 图表只是中间产物关键是“结论、证据和建议”图表做出来后最困难的一步是把它翻译成业务结论。这里我非常推荐用“结论—证据—建议”三段式来组织表达。不要只说“我发现评论量在 1 号最高”这只是在描述图表。更好的表达是结论用户对“新品上市”“手感讨论”的关注度明显高于“价格优惠”。证据在清洗后的 1 万条评论里“手感”相关话题占比约 18%其中“惊喜”“喜欢”等内容情感分偏高而涉及“缺货”“补货”的评论情绪分偏低但占比只有约 6%。建议如果这是一个营销分析任务下一步可以重点观察新品发售前后的评论峰值尤其是“补货”话题是否会在库存不足时快速上升从而影响口碑。当然这里需要特别说明如果你用的是模拟数据或公开数据集不要把结论包装成对某个品牌的真实判断。面试时你可以说“我用一套模拟数据验证了分析方法实际换到真实数据时流程可以直接复用”。这才是诚实的表达方式。5.3 如何向别人讲述这个项目我在面试场景里常听到两种表达。一种是这样“我用 Python 爬了评论存到 MySQL然后写了 SQL做了可视化最后得出了结论。”这种表达的问题在于它把所有环节压成了一条流水线面试官听不出任何个人判断。另一种是这样“我拿到数据后先发现原始 CSV 里存在重复 comment_id于是设计了唯一索引入库时用 INSERT IGNORE 跳过重复数据。统计日趋势时我发现评论高峰和热搜高峰不完全同步。后来在 hot_search 和 comments 之间用 topic_keyword 关联后发现有两类话题一类是自发讨论型一类是热搜带动型于是我把分析重点放在了情感分明显偏低的那类话题上。”第二种表达明显更有信息量因为它包含了问题、方案、验证和解释。不要担心它听起来不够高深面试官更愿意听真实的思考过程。6. 容易翻车的地方以及项目如何真正写进简历6.1 这套项目最容易翻车的五个点做这类项目时会出现一些看起来不起眼但特别消耗时间的问题。我按出现频率整理了五个点第一字符集不一致。MySQL 库表要设置成utf8mb4Python 连接字符串也要带charsetutf8mb4CSV 文件的读取编码也要确认。如果原始文件是 UTF-8 带 BOM用encodingutf-8读取也可能会在中文列名上出现问题这时可以尝试encodingutf-8-sig。第二日期字段类型混乱。有的是2025-04-01有的是2025/04/01 10:00:00有的是时间戳。不要靠肉眼判断直接用pd.to_datetime统一转换再用errorscoerce把非法值变成空值。第三分组聚合后字段不一致。如果 SQL 里用了GROUP BY topic_keyword那么SELECT的非聚合字段必须也在GROUP BY里或者用聚合函数处理掉。MySQL 8.0 默认启用了ONLY_FULL_GROUP_BY很多不严谨的查询会直接报错。第四中文可视化乱码。这个问题不是 Python 逻辑错误而是缺少中文字体或字体配置不对。先确认系统是否安装了中文字体再配置plt.rcParams。第五情绪判断过于自信。如果用规则词典或者通用中文情感模型来打分必须知道它只能作为粗粒度参考。真实评论里包含大量反讽、否定、网络梗和语境信息模型精度天然有限。面试时主动说出这部分边界比答辩时被问住要好得多。6.2 简历写法把过程描述改成结果描述简历上的项目描述通常只有三到五行每句话都应该承载信息。不要这样写泡泡玛特热搜评论数据分析项目 - 使用 Python 爬取评论数据 - 使用 MySQL 保存数据 - 使用 pandas 做清洗和分析 - 使用 matplotlib 做可视化每一个“使用”都没有提供判断依据。更好的写法是热搜评论数据分析项目Python MySQL - 搭建评论表和热搜话题表通过唯一索引和 utf8mb4 字符集完成 1 万条评论数据的入库与去重 - 设计“评论量日趋势”“话题热度与评论量关联”“情感分统计”三类分析维度定位出用户讨论度与热搜热度不同步的话题 - 使用 pandas 完成清洗使用 MySQL 做聚合使用 matplotlib 输出图表并形成结论、证据、建议的结构化分析结果 - 该流程可复用于电商评论、游戏评价、品牌舆情等文本数据场景关键原则是尽量让每句话都回答“你做了什么决策”而不是“你碰了什么工具”。特别提醒如果项目使用的是模拟数据或课程示例数据不要在简历里偷偷写成“百万级真实评论”。面试官追问数据来源时一旦发现表述不实项目可信度会迅速归零。写“示例数据集”不丢人造假才丢人。6.3 让你之后能复用的一个框架这类项目最大的价值不是“泡泡玛特”而是那套可以迁移到很多业务场景里的执行框架。我把它总结成四个步骤第一步先确认输入资产。你有哪些字段数据量大不大是否合规有没有重复或缺失这决定了你后面能做哪些分析。第二步设计表结构和指标。不要拿到数据就建表。先想清楚要回答什么问题再决定建几张表、建哪些字段、加什么索引。第三步用最小样本跑通链路。先取 100 条数据完成清洗、入库、查询、可视化再处理全量数据。小样本跑通后再解决性能问题这是最高效的顺序。第四步把输出整理成结论。图表不是终点。每张图都要回答一句话它说明了什么证据在哪里下一步建议做什么如果没有这句话图就只是装饰。如果你能把这几步做熟以后接到的任务无论是外卖评论、手机评价、游戏用户反馈还是品牌舆情基本都是同一套逻辑。换的只是数据字段和业务问题。这也是为什么我在开头说这类项目的价值不在标题里的“热搜”也不在某个具体品牌而在于它帮你建立了一条从原始文本到业务回答的完整路径。这道路径如果想走得扎实一周时间通常不够但它值得你花三到四周慢慢走完。
返回列表