Python+MySQL实战:从数据采集到可视化分析完整项目教程
学编程最怕的不是“不会某个语法”而是学了一堆东西却不知道自己能做什么。尤其是 Python 和 MySQL 这两个方向很多初学者都卡在同一个问题上语法看懂了增删改查也会写了但打开招聘网站一看还是不知道自己能做什么项目。如果你正处在这个阶段这篇文章就是给你准备的。我建议你跟着做一个完整的实战项目用 Python 采集泡泡玛特热门商品的用户评论把清洗后的结构化数据存进 MySQL再进行中文分词和可视化分析。这个项目的好处非常实在数据是真实业务场景链路贯穿“采集 - 存储 - 分析 - 展示”全流程能把 Python 基础、MySQL 操作、数据分析与可视化这些知识点全部串起来。做完之后你不只是“学过” Python而是“用 Python 解决过真实问题”。做成之后它完全可以作为简历里的项目经历去写而且面试官看到这种项目时通常不会只问“你用了哪些库”而是会问“数据量大了怎么处理”“脏数据怎么清洗”“为什么选 MySQL 不选文件存储”。这些问题下面我都会带你提前准备好答案。1. 这个项目到底值不值得做先说结论值得做但有一个前提。你不应该把它做成“爬虫 - 保存 - 画图”的流水账而应该把它做成一个体现数据工程思路的完整小系统。很多人自己练手时容易犯一个错辛辛苦苦爬了几百条评论保存在 Excel 或 CSV 里然后用 pyecharts 画两张图就结束了。这样的项目做完简历上只能写“熟悉 pyecharts”面试官一眼就能看出来技术含量有限。但这个项目如果加入 MySQL 持久化、数据清洗、中文分词、基于时间的趋势分析难度和价值就完全不同了。整个项目的核心链路是用 Python 从公开渠道获得商品热评数据。对评论做去重、过滤、字段整理。将清洗后的数据写入 MySQL 数据库。从 MySQL 读取数据做评分分布、评论时间趋势、评论主题关键词分析。用可视化图表把分析结果呈现出来形成一份“热评分析报告”。你可以看到这不是单一技能练习而是一个“小型数据系统”。它覆盖了数据采集、数据建模、数据清洗、数据分析和可视化五个环节。而这五个环节恰恰是数据分析岗位日常工作中每天都在做的事情。适合做这个项目的读者包括三类刚学完 Python 基础语法但是不知道下一步学什么的初学者正在准备数据分析或 Python 开发实习面试简历上缺少项目经历的同学想系统串联 MySQL 和 Python但一直找不到合适练手场景的自学者。如果是纯 Java 后端开发者这个项目同样可以参考它展示了 Python 生态在数据分析和可视化上的效率。你不需要成为爬虫专家也不需要成为数据分析师只需要完整走通一遍收获就足够大。2. 整体方案与技术选型很多教程一上来就安装各种软件很容易让初学者迷失方向。因此在动手之前先把整个项目的技术栈和为什么选它讲清楚。2.1 数据流程是什么样的数据从产生到变为图表通常会有这样一条路径数据源商品页面中的用户评论文本、评分、时间、点赞数等。采集层Python 脚本请求公开数据解析字段。清洗层去除重复评论、过滤表情符号、统一时间格式。存储层MySQL 表保存结构化评论数据。分析层pandas 读取 MySQL进行统计jieba 分词提取关键词。展示层pyecharts 生成词云、饼图、柱状图和折线图。这套流程就是很多企业级数据可视化项目的缩小版。理解了它以后无论换成什么业务数据你都能套用下去。2.2 为什么选 Python 而不是 JavaPython 在这个场景下的优势很明显数据处理生态成熟pandas 处理 DataFrame 很方便jieba 做中文分词只需要一行导入pyecharts 可以快速生成交互式 HTML 图表。如果用 Java 做实现同样效果需要更多的代码量尤其是中文分词和图表生成环节。Python 的 requests 库可以灵活处理 HTTP 请求非常适合中小型采集任务。配合 fake_useragent、time.sleep 等控制手段可以做到基本的访问频率控制。但要注意如果目标是采集数百万条数据的大规模系统那考虑用可分布式采集框架更合理这已经超出本篇范围了。2.3 为什么数据要存 MySQL而不是直接存 CSV这是面试中很可能会被追问的问题需要提前想明白。直接存 CSV 的缺点是无法做高效的复杂查询数据一多以后打开和过滤都很慢多条记录之间没有唯一约束重复数据靠脚本去重很麻烦并发读写时文件容易损坏历史数据难以增量管理多人协作时不同人本地各有一份文件产生了“数据副本”问题。MySQL 解决了这些问题。你可以给评论 ID 建唯一索引也可以按商品 ID 或评论时间做条件查询。更重要的是存储层和分析层分离之后后续如果需要做定时增量更新只需要把新评论写入 MySQL不需要改动分析逻辑。这是“文件存储方案”很难做到的。下面的表格可以让你更直观地理解技术选型模块选型理由编程语言Python数据处理生态完善上手快数据采集requests json轻量、便于学习请求与响应模型数据存储MySQL 8.x支持索引、约束便于增量管理数据清洗与分析pandas jieba表格化处理和中文分词的主流方案可视化pyecharts生成交互式 HTML免前端开发开发环境PyCharm 或 VS Code调试 Python 方便关于 MySQL 版本建议使用 8.0 及以上版本字符集直接使用 utf8mb4能完整支持中文和 Emoji 表情。如果你电脑上还没有安装 MySQL可以先去官网下载对应平台安装包安装过程中重点记住 root 密码和端口号。2.4 需要掌握哪些前置基础Python 基础变量、列表、字典、函数、循环、异常处理。MySQL 基础建库建表、INSERT、SELECT、WHERE、GROUP BY。pandas 基础read_sql、drop_duplicates、value_counts。如果你目前还不会上述知识建议先花一周补一补基本语法再回来做这个项目。但也不需要等到完全精通才动手很多细节都是在实战过程中理解的。3. 环境准备与前置条件为了避免“代码运行不起来然后开始怀疑人生”请先按步骤把环境准备好。3.1 安装 Python 环境从 Python 官网下载对应操作系统的 Python 3 安装包。如果你使用的是 Windows安装时务必勾选“Add Python to PATH”否则后续在命令行运行 python 会提示找不到命令。安装完成后打开命令行工具Windows 用 cmd 或 PowerShellmacOS 用终端运行下面命令验证python --version pip --version如果能正常输出版本号说明安装成功。如果提示“python 不是内部或外部命令”先重启命令行仍然不行的话就需要手动把 Python 安装目录添加到系统环境变量 PATH 中。3.2 安装 MySQL 并创建测试库MySQL 属于数据库服务安装过程比普通软件稍复杂。Windows 用户可以选择 MySQL Installer安装路径中请牢记设置的 root 密码macOS 用户可以用 Homebrew 安装也可以使用官方 dmg 包。完成安装后使用 MySQL 命令行或 Navicat 等客户端连接 MySQL然后创建项目数据库CREATE DATABASE IF NOT EXISTS popmart_comment DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci; USE popmart_comment;这里我们指定 utf8mb4 字符集是为了支持中文和表情符号避免热评里常见的“哈哈哈”出现乱码。实际使用 MySQL 客户端时会提示输入密码。本项目的所有代码都假设数据库用户为 root密码部分你需要改成自己的设置。建议不要直接在代码里写死真实数据库密码至少放到脚本文件头部常量中方便统一修改。3.3 创建 Python 虚拟环境并安装依赖强烈建议为项目创建独立的虚拟环境避免不同项目之间互相污染依赖版本。Windows 下创建与激活虚拟环境的命令是python -m venv venv venv\Scripts\activatemacOS / Linux 下python -m venv venv source venv/bin/activate命令行前面出现(venv)之后继续安装项目依赖pip install requests pandas mysql-connector-python jieba pyecharts各库的作用如下库名主要用途requests请求公开接口获取评论 JSON 数据pandas数据清洗、统计分析mysql-connector-pythonPython 连接 MySQL 的官方驱动jieba中文分词提取评论关键词pyecharts生成可视化图表安装完成之后可以运行一个检查脚本确保所有库都能正常导入# 文件路径check_env.py import requests import pandas as pd import mysql.connector import jieba import pyecharts print(Python 环境检查通过) print(pandas 版本, pd.__version__) print(jieba 版本, jieba.__version__)如果运行没有报错说明基础环境已经就绪。4. 数据采集模块设计热身环境准备完后进入项目的第一个业务模块。首先想清楚我们到底要采集什么字段阅读泡泡玛特商品页面的热评有价值的字段通常包括评论内容、评分星级、评论时间、点赞数、用户昵称、商品名称和商品 SKU 信息。其中“评分”用于做满意度分布分析“评论时间”用于观察近期的口碑变化“评论内容”用于分词和词云“点赞数”用于找出高赞热评。实际采集时评论数据一般不在页面 HTML 里而是通过前端异步请求获取 JSON 数据。你可以通过浏览器开发者工具在 Network 面板中找到返回评论的接口观察接口地址和参数字段。真实的接口地址和字段会随时间变化不同网站也有不同的防护策略所以这里提供一个合法且稳定的练习角度为了保证代码能够在任何环境下运行我们用“模拟评论数据生成模块”作为采集层入口再提供接入真实 JSON 数据的占位方法。这样处理的另一个原因是训练数据链路、清洗逻辑、入库逻辑和可视化能力并不依赖真实接口。用模拟数据跑通后再接入真实数据会从容很多。下面是一个完整的模拟采集与数据生成模块# 文件路径collect_demo.py # 说明这是一个模拟热评采集模块用于学习数据处理链路。 # 真实场景中你应该遵守平台规则只采集你有权访问的公开数据 # 并将下方“模拟数据”替换为实际请求返回的 JSON 内容。 import random import time REVIEW_TEXTS [ 设计太可爱了抽到隐藏款开心一整天, 做工比想象中好细节很精致就是发货有点慢, 盲盒真的太看运气了手感一般, 包装很好送朋友的她很喜欢泡泡玛特, 这个系列配色很温柔摆在桌面上非常治愈, 手感有点轻觉得是普通款没想到开出来还不错, 品控可以再提升一下有一个小瑕疵, 物流速度快第二天就到了很满意, 款式多到选择困难每一个都想要, 收藏价值很高已经回购好几次了, 盒子有点压扁了希望以后可以加强包装, 想抽隐藏款结果又抽到了重复款难过, 手感偏重大概率是热门款果然没错, 客服态度很好处理问题很及时, 作为礼物送给女朋友她非常喜欢这个牌子, ] def generate_demo_review(goods_name, goods_id, idx): 生成一条模拟评论数据用于跑通项目链路 rating random.choices([5, 4, 3, 2, 1], weights[60, 25, 10, 3, 2])[0] like_count random.randint(0, 200) hour random.randint(9, 22) comment_time f2025-06-{random.randint(1, 20):02d} {hour:02d}:{random.randint(0, 59):02d} return { goods_id: goods_id, goods_name: goods_name, user_name: f用户_{random.randint(1000, 9999)}, rating: rating, content: random.choice(REVIEW_TEXTS), comment_time: comment_time, like_count: like_count, } def fetch_hot_comments(goods_nameSKULLPANDA 温度系列, goods_id1001, page_num3, page_size10): 模拟分页获取热评。 真实项目如果已经通过浏览器开发者工具找到公开 JSON 接口 可以用 requests.get 获得到 response再解析为同样的列表字典格式。 all_reviews [] for page in range(1, page_num 1): for idx in range(page_size): all_reviews.append(generate_demo_review(goods_name, goods_id, idx)) # 模拟真实请求的间隔避免给目标站点造成压力 time.sleep(0.1) print(f采集完成共获取 {len(all_reviews)} 条评论) return all_reviews if __name__ __main__: data fetch_hot_comments() for item in data[:5]: print(item)运行方式python collect_demo.py预期会输出“采集完成共获取 30 条评论”并打印前 5 条模拟数据。这里需要提醒一句本项目目的是学习数据分析和可视化技术示例中使用模拟数据完全合法且可复现。如果你想换成真实平台热评请务必先阅读平台 robots 协议和使用条款控制请求频率不破坏网站服务不将数据用于商业用途。这是每一位开发者都应该养成的数据合规习惯。5. MySQL 表设计与数据入库数据有了接下来要解决“如何存放”。5.1 设计评论表评论数据表需要包含业务字段和工程字段。业务字段包括商品名称、用户昵称、评分、评论内容、评论时间、点赞数工程字段包括自增主键、入库时间。建表 SQL 如下USE popmart_comment; DROP TABLE IF EXISTS comment_info; CREATE TABLE comment_info ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT 主键ID, goods_id INT NOT NULL COMMENT 商品ID, goods_name VARCHAR(100) NOT NULL COMMENT 商品名称, user_name VARCHAR(64) COMMENT 用户昵称, rating TINYINT COMMENT 评分1-5星, content TEXT COMMENT 评论内容, comment_time DATETIME COMMENT 评论时间, like_count INT DEFAULT 0 COMMENT 点赞数, created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 入库时间, KEY idx_goods_id (goods_id), KEY idx_rating (rating), KEY idx_comment_time (comment_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci COMMENT商品热评数据表;几个设计的细节rating 字段用 TINYINT足够容纳 1 到 5 的评分节省空间。content 字段用 TEXT因为评论内容长短不一不适合定长 VARCHAR。comment_time 使用 DATETIME后续按时间分组统计时更方便。为 goods_id 和 comment_time 建立索引是因为后续最常见的查询条件就是“查看某个商品某段时间的评论”。5.2 MySQL 连接配置写一个 db.py 文件统一管理数据库连接。把数据库地址、用户名、密码放在文件顶部常量中实际开发时建议改成从环境变量读取。# 文件路径db.py import mysql.connector DB_CONFIG { host: 127.0.0.1, port: 3306, user: root, password: 这里改成你自己的MySQL密码, database: popmart_comment, charset: utf8mb4, use_unicode: True, } def get_connection(): 获取一个新的数据库连接 conn mysql.connector.connect(**DB_CONFIG) return connmysql.connector.connect 每次调用都会创建新连接。在本项目的低并发场景下这样的写法简单直观、足够使用。如果未来数据量大可以考虑使用连接池技术例如 SQLAlchemy 的 pool 功能。5.3 批量写入库采集到的评论数据需要写入 MySQL。一条一条地执行 INSERT 效率很低推荐使用 executemany 批量插入。# 文件路径save_to_db.py from collect_demo import fetch_hot_comments from db import get_connection def save_reviews_to_db(reviews): 将评论列表写入 MySQL if not reviews: print(没有可写入的数据) return 0 conn get_connection() cursor conn.cursor() sql INSERT INTO comment_info (goods_id, goods_name, user_name, rating, content, comment_time, like_count) VALUES (%s, %s, %s, %s, %s, %s, %s) data [ ( item[goods_id], item[goods_name], item[user_name], item[rating], item[content], item[comment_time], item[like_count], ) for item in reviews ] try: cursor.executemany(sql, data) conn.commit() print(f成功写入 {cursor.rowcount} 条评论) return cursor.rowcount except Exception as e: conn.rollback() print(f写入失败已回滚{e}) return 0 finally: cursor.close() conn.close() if __name__ __main__: reviews fetch_hot_comments(page_num3, page_size10) save_reviews_to_db(reviews)保存后运行python save_to_db.py执行后可以在 MySQL 客户端中查询SELECT COUNT(*) FROM comment_info; SELECT goods_name, rating, content, like_count FROM comment_info LIMIT 10;能够看到刚写入的数据说明从采集到入库的链路已经跑通。这里必须强调事务和回滚数据库写入操作涉及数据一致性如果某一条数据非法导致整体失败直接执行 INSERT 而没有事务保护可能会留下一半脏数据。上面代码中使用 commit 和 rollback 保证要么全部成功要么失败后回滚。这种习惯在真实项目中非常重要。6. 数据清洗与中文分词分析数据入库后下一个环节是从数据库中读取数据并进行分析前的清洗。6.1 什么是数据清洗为什么需要它真实场景中的原始评论并不干净一般会有以下问题同一条评论被采集脚本重复写入评论内容带有大量空格、换行或表情符号评分为空或超出 1 到 5 的范围评论时间格式不一致商品名称中混杂前后缀导致无法统一统计。如果不处理就直接可视化图表里的数字会误导人。比如重复评论可能会导致词云中某个词频率虚高让运营人员以为用户都在聊某个话题实际却是数据重复造成的假象。6.2 用 pandas 清洗评论数据pandas 是 Python 数据分析的核心库它可以把 MySQL 查询结果直接转换成 DataFrame然后用一行代码完成去重。# 文件路径clean_and_analyze.py import pandas as pd from db import get_connection def load_comments_from_db(): 从 MySQL 读取评论数据到 DataFrame conn get_connection() sql SELECT goods_id, goods_name, rating, content, comment_time, like_count FROM comment_info df pd.read_sql(sql, conn) conn.close() return df def clean_comments(df): 清洗评论数据 df df.drop_duplicates(subset[goods_id, user_name, content, comment_time]) df df.dropna(subset[content, rating]) df df[(df[rating] 1) (df[rating] 5)] df[content] df[content].astype(str).str.strip() df[content] df[content].str.replace(\n, , regexFalse).str.replace(\r, , regexFalse) df[comment_time] pd.to_datetime(df[comment_time], errorscoerce) df df.dropna(subset[comment_time]) return df def rating_distribution(df): 评分分布统计 dist df[rating].value_counts().sort_index() print(评分分布) print(dist) return dist if __name__ __main__: df load_comments_from_db() df clean_comments(df) print(清洗后数据量, len(df)) rating_distribution(df)6.3 使用 jieba 进行中文分词词云图并不是直接把评论画上去而是要先对评论内容做分词再把高频词展示出来。jieba 是目前使用率很高的中文分词库。基本用法如下import jieba text 设计太可爱了抽到隐藏款开心一整天 words jieba.lcut(text) print(words) # 输出[设计, 太, 可爱, 了, , 抽到, 隐藏, 款, , 开心, 一整天]分词后噪音词比较多比如“了”“太”“”。需要过滤停用词。停用词来自很多场景你可以自己维护一个列表比如STOP_WORDS set([ 的, 了, 是, 我, 你, 他, 她, 它, 我们, 你们, 这个, 那个, 一个, 非常, 真的, 觉得, 就是, 还是, 可以, 没有, , 。, , , , \n, 哈哈哈, ])然后在分析时只要 word 存在于停用词集合中或者 word 的长度小于 2就直接丢弃。同时可以进一步筛选自定义词表只保留对分析有价值的名词、形容词和品牌词。6.4 统计高频词与高赞热评把分词后的词语按频率排序即可知道用户讨论的热点。而“热评”的定义通常有两种一是点赞数高、内容质量高的评论二是被重复提及的关键词。我们都可以统计出来。# 文件路径analyze_text.py import jieba import pandas as pd from collections import Counter STOP_WORDS set([ 的, 了, 是, 我, 你, 他, 她, 它, 我们, 你们, 这个, 那个, 一个, 非常, 真的, 觉得, 就是, 还是, 可以, 没有, , 。, , , , \n, ]) def load_all_content(df): return .join(df[content].tolist()) def extract_hot_words(df, top_n30): 提取评论中的高频关键词 all_words [] for content in df[content]: words jieba.lcut(content) for w in words: w w.strip() if len(w) 2 and w not in STOP_WORDS and not w.isdigit(): all_words.append(w) counter Counter(all_words) return counter.most_common(top_n) def top_by_likes(df, n10): 点赞数最高的热评 Top N top_df df.sort_values(like_count, ascendingFalse).head(n) return top_df[[goods_name, user_name, rating, like_count, content, comment_time]] if __name__ __main__: from clean_and_analyze import load_comments_from_db, clean_comments df load_comments_from_db() df clean_comments(df) hot_words extract_hot_words(df) print(高频关键词 Top 20) for word, count in hot_words[:20]: print(f{word}: {count}) top_comments top_by_likes(df, 5) print(\n高赞热评 Top 5) print(top_comments.to_string(indexFalse))执行后你会看到类似“隐藏款”“设计”“包装”“盲盒”“手感”这样的关键词出现在前列。这说明在模拟数据里用户最关注的维度其实集中在“款式”“外观”“品控”“购买体验”几个方向。真实数据量变大后这种统计会更有业务指导意义。7. 可视化展示把分析结果变成看得懂的图分析终归要通过可视化呈现。使用 pyecharts 的好处是不用写前端代码就可以生成带交互效果悬浮提示、数据缩放的 HTML 文件。7.1 评分分布饼图评分分布适合展示整体满意度。用清晰的饼图可以快速看出好评、中评、差评的比例。# 文件路径visual_report.py from pyecharts.charts import Pie, Bar, WordCloud, Line from pyecharts import options as opts from clean_and_analyze import load_comments_from_db, clean_comments df load_comments_from_db() df clean_comments(df) # 评分分布数据 rating_counts df[rating].value_counts().sort_index() data_pair [(f{star}星, int(count)) for star, count in rating_counts.items()] pie ( Pie() .add(, data_pair, radius[40%, 70%]) .set_global_opts(title_optsopts.TitleOpts(title热评评分分布)) .set_series_opts(label_optsopts.LabelOpts(formatter{b}: {c} ({d}%))) ) pie.render(rating_pie.html) print(已生成评分分布图rating_pie.html)运行后项目目录下会出现 rating_pie.html用浏览器打开就能看到饼图。7.2 高频关键词词云词云非常适合展示“大家在聊什么”。pyecharts 的 WordCloud 可以直接接收词和权重。# 文件路径visual_report.py追加 from analyze_text import extract_hot_words hot_words extract_hot_words(df, top_n50) wc_data [(word, count) for word, count in hot_words] wordcloud ( WordCloud() .add( , wc_data, word_size_range[20, 100], textstyle_optsopts.TextStyleOpts(font_familySimHei), ) .set_global_opts(title_optsopts.TitleOpts(title商品热评关键词词云)) ) wordcloud.render(comment_wordcloud.html) print(已生成词云图comment_wordcloud.html)如果你使用 macOS 系统SimHei 字体可能不存在可以改成 PingFang SC 或 Arial Unicode MS。如果词云图中的中文乱码多半是字体没有设置成中文字体的原因这是最常见的问题。7.3 评论时间趋势折线图将评论时间按月或按日聚合可以看出这个商品的口碑热度是否有周期性。由于演示数据只模拟了 6 月的数据用“按日”分组会更合适。# 文件路径visual_report.py追加 daily_count df.groupby(df[comment_time].dt.date).size().reset_index(namecount) daily_count[comment_time] daily_count[comment_time].astype(str) line ( Line() .add_xaxis(daily_count[comment_time].tolist()) .add_yaxis(评论数量, daily_count[count].tolist(), is_smoothTrue) .set_global_opts( title_optsopts.TitleOpts(title评论数量时间趋势), xaxis_optsopts.AxisOpts(name日期), yaxis_optsopts.AxisOpts(name评论数), ) ) line.render(comment_time_trend.html) print(已生成时间趋势图comment_time_trend.html)折线图的价值在于可以看出某个时间点评论暴涨。如果真实数据里某天突然出现大量负面评论那么大概率是出现了品控问题或热门事件这种发现只有把数据按时间轴看才够直观。7.4 评分与点赞数对比柱状图另一个有价值的分析维度是不同评分的评论获得了多少点赞。如果 5 星评论点赞数整体不如 3 星评论多说明用户对于“中评”内容有更高共鸣这也能反映问题。# 文件路径visual_report.py追加 grouped df.groupby(rating)[like_count].mean().round(1) bar ( Bar() .add_xaxis([f{star}星 for star in grouped.index.tolist()]) .add_yaxis(平均点赞数, grouped.tolist()) .set_global_opts( title_optsopts.TitleOpts(title不同评分评论的平均点赞数), xaxis_optsopts.AxisOpts(name评分), yaxis_optsopts.AxisOpts(name平均点赞数), ) ) bar.render(rating_like_bar.html) print(已生成柱状图rating_like_bar.html)你可以将所有可视化代码写在同一个脚本里一次性运行生成 4 个 HTML 文件也可以拆开逐张运行方便调试。项目阶段建议合并成一个 visual_report.py然后统一查看输出。8. 运行效果验证与问题排查整个项目的执行顺序是初始化数据库和表。运行 collect_demo.py 生成模拟评论数据。运行 save_to_db.py 将数据写入 MySQL。运行 clean_and_analyze.py 做清洗和分词。运行 visual_report.py 生成可视化 HTML 文件。如果你把代码复制到本地并执行成功预期效果如下终端显示采集完成成功写入 30 条以上的评论MySQL 中能查询到结构化数据项目目录下出现 4 个 HTML 文件浏览器打开 rating_pie.html 可以看到 1 星到 5 星的占比浏览器打开 comment_wordcloud.html 可以看到“设计”“盲盒”“隐藏款”等词。如果某一步运行失败优先从下面几个角度排查。问题现象可能原因排查方式解决方案导入模块时提示 ModuleNotFoundError忘记安装依赖包或没有激活虚拟环境检查命令行前是否有 (venv)执行 pip list按 3.3 节执行 pip installmysql.connector 连接失败密码错误、端口错误、或 MySQL 服务未启动检查 DB_CONFIG 配置用客户端测试连接运行 netstat 查看 3306 端口修改密码或启动 MySQL 服务写入数据库失败提示 DataErrorcontent 字段长度超过 TEXT 上限或日期格式不合法打印具体数据检查字段值清洗阶段做类型转换和裁剪执行 SQL 时报 Duplicate entry重复写入相同数据主键或唯一索引冲突查询已有数据 COUNT避免重复执行或写入前查询去重中文乱码数据库字符集不是 utf8mb4或连接字符集不对查看数据库 CHARACTER_SET建表使用 utf8mb4DB_CONFIG 中增加 charsetpyecharts 图表无法打开环境缺少浏览器或 HTML 路径问题确认运行时当前目录用绝对路径或直接双击 HTML词云不显示中文图形库或浏览器未取到中文字体检查词云文字样式指定支持中文的字体如果出现 Unknown database 错误说明数据库还没有创建需要先执行第 3.2 节的 CREATE DATABASE 语句。这是初学者最容易忽略的一步。以上排查过程本身就是项目经验的一部分。将来你在简历里写“熟悉 Python MySQL 开发”面试官最想听的往往不是功能怎么做出来的而是你遇到过哪些问题、用什么方法定位并解决。9. 从练习到简历工程化与最佳实践练习完成只是第一步。如果你想把它作为简历项目或者在学习过程中养成更好的工程习惯下面这些建议很值得参考。9.1 把代码按功能模块拆分不要把所有代码写在一个大文件里。推荐按职责拆分popmart-analysis/ ├── venv/ # 虚拟环境不需要提交到 Git ├── db.py # 数据库连接配置 ├── collect_demo.py # 采集/模拟数据模块 ├── save_to_db.py # 入库模块 ├── clean_and_analyze.py # 数据清洗 评分统计 ├── analyze_text.py # 文本分词 关键词统计 ├── visual_report.py # 可视化模块 ├── requirements.txt # 依赖清单 └── README.md # 项目说明文档在 requirements.txt 中固定依赖版本方便其他环境复现requests2.31.0 pandas2.1.4 mysql-connector-python8.2.0 jieba0.42.1 pyecharts2.0.5注意以上版本号只是示例请以你本地实际安装为准。真实项目里建议用 pip freeze 生成当前环境的依赖版本保证可复现。9.2 不要泄露数据库密码很多初学者会把数据库密码直接写在代码里然后提交到 GitHub这是一个非常危险的习惯。真实项目中更推荐使用环境变量管理敏感信息import os DB_PASSWORD os.getenv(DB_PASSWORD, ) DB_CONFIG { user: os.getenv(DB_USER, root), password: DB_PASSWORD, ... }在本地开发时可以在命令行中设置临时环境变量。发布到服务器时则通过部署平台的密钥管理服务注入。掌握这个习惯会让别人觉得你有一定生产经验。9.3 入库逻辑要保证幂等重复运行采集脚本是常态不应因为重复运行而产生大量重复数据。最稳妥的方案是建立唯一索引例如 (goods_id, user_name, comment_time, content) 太长不太适合直接建索引但可以先生成一列 content_hash 作为去重标识import hashlib def make_content_hash(row): raw f{row[goods_id]}|{row[user_name]}|{row[comment_time]}|{row[content]} return hashlib.md5(raw.encode(utf-8)).hexdigest()清洗后的 DataFrame 可以增加 content_hash 列写库时让 MySQL 对该列建立唯一索引。如果重复执行入库新写入的重复记录会被数据库拒绝而不是变成双份数据。这种方法在生产环境非常常见。9.4 用日志代替 print练习时使用 print 输出没问题但以后项目规模变大print 无法持久化输出也没法区分信息等级。建议使用 Python 自带的 logging 模块import logging logging.basicConfig( levellogging.INFO, format%(asctime)s %(levelname)s %(message)s ) logger logging.getLogger(__name__) logger.info(成功写入 %s 条评论, count)在面试时提到“使用 logging 记录数据入库和清洗结果”会比“我用 print 打了很多日志”显得更规范。9.5 简历上的项目描述如果写成简历项目可以按时间倒序放在“项目经历”里采用 STAR 原则描述项目名称泡泡玛特热评可视化分析系统个人项目技术栈Python、MySQL、pandas、jieba、pyecharts项目内容基于 Python requests 采集公开商品评论数据完成字段解析、数据校验与异常重试使用 pandas 对评论进行去重、空值处理、时间格式统一并使用 jieba 完成中文分词与高频词统计使用 MySQL 设计评论信息表建立商品、评分、评论时间索引通过 executemany 完成批量写入使用 pyecharts 生成评分分布饼图、关键词词云、评论时间趋势折线图为运营分析用户关注点提供数据支撑通过 logging 记录数据清洗与入库结果使用环境变量管理数据库账号保证本地开发安全。项目成果描述时不建议编造过大的数据量。如果你跑了 50 条演示数据不要写成“处理百万级数据”。可以换个角度写“沉淀了一套可复用的评论数据采集、清洗、入库、分析流程”。把流程能力和数据质量意识体现出来面试官反而更认可。10. 总结与下一步可以做什么这个项目的价值不在于用了多少新技术而在于它强迫你完整地走通了“数据是怎么从业务中产生最终变成决策依据”的全流程。你亲手处理了中文乱码、时间格式不统一、重复数据、字段为空、可视化字体缺失等实际问题这些问题是任何教科书都无法完整教会你的。做完基础版本之后还可以沿着以下几个方向继续升级第一增加定时调度能力。可以把采集脚本包装成 Python 函数通过系统自带的 cron 或 Windows 任务计划程序定时执行让评论数据每天自动增量更新。第二把 HTML 图表升级成动态看板。使用 Flask 搭建一个简单的 Web 服务调用 MySQL 数据接口再用 ECharts 在前端渲染完成后端到前端的数据可视化大屏效果。这是不少企业招聘中提到的“可视化大屏”能力的入门路径。第三加入情感分析。基于评论内容判断正面、中性和负面再结合词云找到被集中吐槽的方面。可以对训练好的情感模型做进一步优化也可以在评论数据上直接使用公开情感词典。第四优化 SQL 查询。当数据量增长到几十万条以后查询是否走索引、分组聚合是否高效都会影响体验。这个时候再回头去学 MySQL 的执行计划EXPLAIN和索引优化理解会深刻很多。数据总是在真实场景里才最有说服力。如果只是跟着教程在本地造数据学到的是 API 的用法只有把一个具体场景的数据从采集到可视化完整打通你才会理解为什么 Python 和 MySQL 至今仍是数据分析与后端开发里的黄金组合。希望这篇教程能帮你把这两个技术真正“串”起来在你简历上留下一个看得见、讲得清、经得起追问的项目。