拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Python数据分析实战:泡泡玛特热搜评论的采集、分词与可视化

在 Python 数据分析的练习项目里把“公开评论采集”和“可视化报告输出”串成一条完整链路是目前最值得做的入门案例之一。它同时覆盖 requests 爬虫、pandas 清洗、jieba 分词、pyecharts 图表和报告整理几乎每个环节都会遇到真实工程问题也是简历项目和毕业设计里出现频率很高的选题。这篇文章围绕“泡泡玛特Pop Mart热搜评论数据分析可视化”这一主题从零搭建一个可选真实数据源、也可用本地样例数据跑通全流程的 Python3 项目。文章会给出完整目录结构、核心代码、运行验证方式和常见问题排查方法适合正在准备毕设、面试项目或希望系统掌握数据分析流程的 Python 学习者。1. 先想清楚热搜评论分析项目到底解决什么问题1.1 项目的业务目标和技术目标热搜评论数据的特点是文本短、口语化、情绪表达明显、包含大量网络新词。以泡泡玛特热搜评论为例用户评论里经常出现“盲盒”“隐藏款”“端盒”“雷款”“抽中”“二手溢价”等潮玩行业词汇。分析这些评论业务上可以回答三个问题用户对品牌的主要关注点是什么用户情绪偏向正面还是负面评论热度随时间如何变化。技术上的目标则更加明确用 Python 完成“采集 - 清洗 - 分析 - 可视化 - 报告输出”全流程。采集层负责拿到原始评论清洗层负责把脏数据处理成可分析的结构化数据分析层负责分词、统计、情感判断可视化层负责把统计结果转换成图表最后生成一个可以直接用浏览器打开的 HTML 报告。这个项目适合作为知识点综合练习因为你会在一个项目中同时使用 requests、pandas、jieba、pyecharts 四类不同定位的库。它们各自解决一个环节的问题组合起来就是一个完整的数据分析管道。1.2 技术选型说明为什么是 requests pandas jieba pyecharts整个项目主要依赖四个核心库每个库解决一个具体问题。库名作用不选其他方案的原因requests请求公开接口获取 JSON 评论数据轻量、学习成本低比 Scrapy 更适合作为入门课程pandas读取 CSV、去重、过滤、统计数据量在几千到几万条时完全够用生态成熟jieba中文分词、词频统计中文评论必须分词jieba 安装简单且支持自定义词典pyecharts生成交互式 HTML 图表图表类型丰富可以输出网页报告适合演示和答辩如果换成 Scrapy 可以支持大规模分布式爬取但如果只是做几万条评论的分析项目Scrapy 的调度器、中间件、管道反而会增加学习负担。使用 requests 逐页请求配合时间间隔足以完成教学和演示场景。还需要注意一点真实平台的接口地址和返回字段随时可能调整所以本项目会把“采集层”和“分析层”解耦。即使接口失效只要保留一份 CSV 或 JSON 样例数据后续清洗、分析、可视化流程依然可以完整跑通。2. 环境准备先把 Python 运行环境检查清楚2.1 版本选择和安装检查本项目基于 Python 3建议使用 3.8 及以上版本。Windows、macOS、Linux 都可以运行但要注意以下检查点。打开命令行工具执行以下命令确认 Python 和 pip 是否可用。python --version pip --version如果提示 python 不是内部或外部命令先检查是否安装 Python 并勾选了“Add Python to PATH”选项。macOS 和 Linux 用户如果系统自带 Python 3 版本较旧建议使用 Anaconda 或 pyenv 安装新版本避免后续依赖库出现版本兼容问题。推荐使用虚拟环境隔离项目依赖避免污染全局环境python -m venv venvWindows 下激活虚拟环境venv\Scripts\activatemacOS 和 Linux 下激活虚拟环境source venv/bin/activate激活后命令行前面会出现(venv)标识说明已经进入虚拟环境。2.2 安装依赖库在激活的虚拟环境中执行下面的安装命令pip install requests pandas jieba pyecharts如果网络速度较慢可以临时使用国内镜像源pip install requests pandas jieba pyecharts -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后可以通过一条命令验证所有核心库是否可用python -c import requests, pandas, jieba, pyecharts; print(all ready)如果看到all ready输出说明环境已经就绪。这里不要只验证导入还要确认版本之间没有明显冲突。在常见环境中requests 2.31、pandas 2.x、pyecharts 2.x 组合使用没有问题。如果使用 pandas 旧版本某些 API 行为会略有差异建议直接安装最新稳定版。2.3 推荐的项目目录结构项目虽然不大但目录结构提前规划好后面改代码和排查问题都会方便很多。推荐按下面的结构组织文件。popmart-analysis/ ├── venv/ # 虚拟环境 ├── data/ # 原始数据和中间数据 │ ├── comments.csv │ └── sample_comments.json ├── output/ # 图表和报告输出 ├── stopwords.txt # 停用词表 ├── fetch_data.py # 采集脚本 ├── clean_data.py # 清洗脚本 ├── analyze_visualize.py # 分析和可视化脚本 └── README.md # 项目说明数据统一放在 data 目录输出统一放在 output 目录脚本之间通过文件传递数据而不是把数据硬编码在代码里。这样做的原因是爬虫、清洗、可视化三个阶段如果放在一个文件里一旦中间环节报错前面的数据就全部丢失分开之后每一层都可以单独运行、单独调试。这也是实际项目里“数据管道”思想的简化版本。3. 数据采集拿到公开评论并保存为结构化文件3.1 先确认数据源和返回结构采集前最重要的一步不是写代码而是确认目标数据源提供什么结构的数据。以公开评论接口为例常见的返回格式是 JSON 对象里面包含评论列表、分页信息和用户相关信息。为了不影响真实平台这里使用一个通用的数据格式演示。实际项目中你需要先通过浏览器开发者工具的 Network 面板找到评论接口再确认字段名。{ data: { comments: [ { user_name: 用户A, content: 今天抽到了隐藏款真的开心, like_count: 128, created_at: 2024-03-12 20:15:00 }, { user_name: 用户B, content: 这个批次品控不行有点失望, like_count: 36, created_at: 2024-03-12 20:18:00 } ] }, page: 0, has_more: true }拿到真实接口的返回结构后把字段名记下来再进入代码编写环节。如果暂时找不到接口或者接口需要登录才能访问建议使用一份本地样例 JSON 数据来完成后续流程不要为了获取数据去做违规操作。下面的示例代码中会同时给出“请求接口”和“读取本地样例”两种方式。3.2 用 requests 实现基础采集采集脚本的核心逻辑是循环请求分页接口解析 JSON把需要的字段抽出来最后写入文件。import requests import pandas as pd import time import json HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120 Safari/537.36, Accept: application/json, text/plain, */*, } def fetch_comments(api_base, limit200): comments [] page 0 while len(comments) limit: url f{api_base}?page{page}page_size50 try: resp requests.get(url, headersHEADERS, timeout10) resp.raise_for_status() data resp.json() except Exception as exc: print(f第 {page} 页请求异常: {exc}) break items data.get(data, {}).get(comments, []) if not items: print(没有更多评论数据停止采集) break for item in items: comments.append({ user_name: item.get(user_name, ), content: item.get(content, ), like_count: item.get(like_count, 0), created_at: item.get(created_at, ), }) page 1 time.sleep(1) return comments if __name__ __main__: api https://example.com/api/comments result fetch_comments(api, limit200) df pd.DataFrame(result) df.to_csv(data/comments.csv, indexFalse, encodingutf-8-sig) print(f采集完成共保存 {len(df)} 条评论到 data/comments.csv)这里有几个关键点需要解释。请求头中的 User-Agent 是必须的很多服务端会拒绝没有 UA 或 UA 异常的请求设置成常见浏览器的 UA 可以降低被拒绝的概率。time.sleep(1)控制请求间隔避免短时间高频请求给目标服务造成压力这是公开数据采集的基本礼仪。encodingutf-8-sig是给 Windows Excel 用的带 BOM 的 UTF-8 编码可以让 Excel 直接打开 CSV 不乱码。如果接口不可用可以用本地 JSON 样例代替采集过程import pandas as pd with open(data/sample_comments.json, r, encodingutf-8) as f: sample_data json.load(f) df pd.DataFrame(sample_data) df.to_csv(data/comments.csv, indexFalse, encodingutf-8-sig)3.3 数据保存阶段的小坑保存 CSV 时不要使用默认的encodingutf-8。Windows 上的 Excel 打开纯 UTF-8 CSV 时会把中文显示成乱码而utf-8-sig编码会在文件头部写入 BOM 标识Excel 能自动识别。另外原始数据里可能包含换行符、逗号、引号。pandas 的to_csv会自动处理引号转义因此不要手动拼接字符串写文件。手动拼接不仅容易出错还会破坏 CSV 的字段结构。采集完成后用下面的命令简单看一下结果规模df pd.read_csv(data/comments.csv, encodingutf-8-sig) print(df.shape) print(df.head()) print(df[content].str.len().describe())确认行数、字段数量和评论长度分布符合预期再进入清洗阶段。如果行数明显偏少说明数据源可能已经变化需要回到接口检查阶段。4. 数据清洗和文本预处理统计结果准不准全看这步4.1 去重、去空、去广告原始评论数据通常包含重复评论、空内容、推广广告和纯表情内容。这些脏数据如果不处理词频统计会被严重干扰。import pandas as pd import re df pd.read_csv(data/comments.csv, encodingutf-8-sig) print(f清洗前数据量: {len(df)}) # 1. 去重 df df.drop_duplicates(subset[content]) print(f去重后数据量: {len(df)}) # 2. 去空 df df.dropna(subset[content]) df df[df[content].str.strip() ! ] # 3. 去除明显广告和无效文本 ad_keywords [加微信, 代购, 低价出, 联系我, 广告] def is_ad(text): for kw in ad_keywords: if kw in text: return True return False df df[~df[content].apply(is_ad)] print(f过滤广告后数据量: {len(df)})去重时选择content作为判断列而不是整行去重因为同一用户可能在多个时间点发布相同内容但点赞数不同。广告过滤用关键词集合判断这个集合需要根据实际数据不断补充。需要注意的是关键词过滤是简单规则可能误删正常评论因此过滤词表要谨慎维护不要放太宽泛的词。4.2 jieba 分词和停用词过滤中文评论不能按空格分单词必须用分词工具。jieba 的分词结果默认已经比较准确但对于潮流玩具相关词汇比如“隐藏款”“端盒”“盲盒”可以添加自定义词典避免被错误切分。import jieba from collections import Counter # 添加自定义词典保证专属词汇正确切分 for word in [泡泡玛特, 隐藏款, 端盒, 盲盒, 雷款, 热款, 潮玩]: jieba.add_word(word) # 读取停用词表 stopwords set() with open(stopwords.txt, r, encodingutf-8) as f: for line in f: w line.strip() if w: stopwords.add(w) stopwords.update({一个, 这个, 那个, 什么, 就是, 真的, 觉得, 没有, 还是, 可以, 一下}) def clean_text(text): text re.sub(r\w, , text) text re.sub(rhttp\S, , text) text re.sub(r回复, , text) text re.sub(r\s, , text) return text.strip() def seg_words(text): words jieba.lcut(text) result [] for w in words: w w.strip() if len(w) 2: continue if w.isdigit(): continue if w in stopwords: continue result.append(w) return result df[clean_content] df[content].apply(clean_text) df[words] df[clean_content].apply(seg_words) all_words [] for words in df[words]: all_words.extend(words) word_counter Counter(all_words) top_words word_counter.most_common(30) print(top_words)停用词表的作用是过滤“的、了、是、就、都”这类没有实际含义的高频词。如果不过滤它们会占据词频榜前几位干扰真正有价值的词。这里的过滤条件包括去掉单字词、数字和停用词。分词结果可以保留在 DataFrame 的新列里方便后续统计。4.3 评论情感倾向的简单判断情感分析是一个完整的 NLP 方向本项目不引入复杂模型使用词典法给出一个可解释的简化版本。维护一组正面词和负面词统计评论中出现的正面词数量和负面词数量按得分判断倾向。POSITIVE_WORDS { 好看, 喜欢, 可爱, 开心, 期待, 满意, 高级, 值得, 惊喜, 爱了, 种草, 回购, } NEGATIVE_WORDS { 失望, 难看, 后悔, 垃圾, 坑, 差评, 生气, 退款, 溢价, 涨价, 品控, 瑕疵, } def simple_sentiment(text): pos_count sum(1 for w in POSITIVE_WORDS if w in text) neg_count sum(1 for w in NEGATIVE_WORDS if w in text) if pos_count neg_count: return 正面 if neg_count pos_count: return 负面 return 中性 df[sentiment] df[clean_content].apply(simple_sentiment) print(df[sentiment].value_counts())这种词典法实现简单、运行快、结果可解释适合入门项目。它的局限也很明显否定词无法处理“不失望”会被识别成负面“喜欢”和“不喜欢”同时出现时无法正确抵消。如果后续想做更准确的情感分析可以升级为基于情感词典加否定词权重的方案或者使用预训练模型但这会显著增加项目复杂度。作为毕设和简历项目词典法配合明确的分析结论说明已经足够展示完整能力。5. 数据分析和可视化把统计结果变成可读图表5.1 词频 TOP20 柱状图词频分析回答“用户在聊什么”这个问题。把上面统计出的高频词绘制成柱状图可以直观展示用户的关注焦点。from pyecharts.charts import Bar from pyecharts import options as opts bar_data word_counter.most_common(20) x_axis [w for w, _ in bar_data] y_axis [c for _, c in bar_data] bar ( Bar() .add_xaxis(x_axis) .add_yaxis(出现次数, y_axis) .set_global_opts( title_optsopts.TitleOpts(title泡泡玛特热搜评论高频词汇 TOP20), xaxis_optsopts.AxisOpts(axislabel_optsopts.LabelOpts(rotate30)), yaxis_optsopts.AxisOpts(name次数), ) ) bar.render(output/bar_top20.html)x 轴文字旋转 30 度是为了防止词汇过长时互相重叠这是绘制中文柱状图时常见的问题。如果文字仍然重叠可以考虑把rotate调到 45 或 60。5.2 情感分布饼图情感分布回答“用户情绪是正面还是负面”这个问题。from pyecharts.charts import Pie sentiment_counts df[sentiment].value_counts() pie ( Pie() .add( 情感分布, [list(z) for z in zip(sentiment_counts.index, sentiment_counts.values)], radius[40%, 70%], ) .set_global_opts(title_optsopts.TitleOpts(title评论情感分布)) .set_series_opts(label_optsopts.LabelOpts(formatter{b}: {c} ({d}%))) ) pie.render(output/pie_sentiment.html)radius[40%, 70%]表示使用环形图中间留白可以让整体更清爽。formatter{b}: {c} ({d}%)同时显示标签、数量和百分比避免读者还要自己换算。5.3 时间趋势折线图时间趋势回答“评论热度在哪些时间段集中”这个问题。先把created_at解析成时间类型再按小时或按天聚合。import pandas as pd from pyecharts.charts import Line df[created_at] pd.to_datetime(df[created_at], errorscoerce) df df.dropna(subset[created_at]) df[hour] df[created_at].dt.hour hour_counts df[hour].value_counts().sort_index() line ( Line() .add_xaxis([f{h}时 for h in hour_counts.index]) .add_yaxis(评论数量, hour_counts.values.tolist()) .set_global_opts( title_optsopts.TitleOpts(title评论时间分布按小时), xaxis_optsopts.AxisOpts(name时间), yaxis_optsopts.AxisOpts(name评论数), ) ) line.render(output/line_time.html)errorscoerce的作用是把无法解析的时间转换成 NaT否则解析异常会直接抛错。聚合时按小时统计主要用来观察用户活跃时段。如果数据量太少按小时统计会出现大量空值绘图时折线会不连续这时可以改成按天统计。5.4 词云图和合并报告词云图适合作为报告首页的视觉焦点。pyecharts 的 WordCloud 组件会生成交互式 HTML比 matplotlib 生成的静态图片更适合在浏览器中展示。from pyecharts.charts import WordCloud word_cloud ( WordCloud() .add(, word_counter.most_common(100), shapediamond) .set_global_opts(title_optsopts.TitleOpts(title评论词云)) ) word_cloud.render(output/wordcloud.html)最后用 Tab 组件把多个图表整合到一个 HTML 页面方便答辩和演示。from pyecharts.charts import Tab tab Tab() tab.add(bar, 高频词) tab.add(pie, 情感分布) tab.add(line, 时间趋势) tab.add(word_cloud, 词云) tab.render(output/popmart_report.html) print(报告已生成: output/popmart_report.html)合并报告的好处是只有一个入口文件打开即可看到所有图表切换标签页查看不同维度。如果还需要 PDF 报告可以在 HTML 基础上使用浏览器的打印功能另存为 PDF或者再用 python-docx 生成 Word 版本的图文报告。6. 运行验证按顺序跑通并检查每个中间结果6.1 整个项目的运行顺序三个脚本应该按依赖顺序执行。如果采集脚本没有产出 CSV清洗脚本会直接报错如果清洗产出不通过分析结果也不可信。python fetch_data.py python clean_data.py python analyze_visualize.py如果使用本地样例数据可以跳过 fetch_data.py或者让 fetch_data.py 在接口不可用时自动读取样例文件。推荐在 fetch_data.py 中增加一个降级逻辑try: result fetch_comments(api, limit200) except Exception as exc: print(f接口采集失败改用本地样例数据: {exc}) with open(data/sample_comments.json, r, encodingutf-8) as f: result json.load(f)这样整体流程在任何环境都能跑通演示时不会因为接口失效而中断。6.2 验证指标和预期输出完成全流程后按下面的清单确认结果检查项预期结果检查方式comments.csv 存在文件可打开行数与采集日志一致pandas 读取并打印 shape清洗后数据量少于原始数据量重复和空值被移除打印各阶段行数分词结果无单字词、无停用词、无 URL抽查 5 到 10 条评论的 words 列情感分布正、负、中三类占比合计 100%value_counts(normalizeTrue)HTML 报告浏览器可正常打开图表无空白双击 output/popmart_report.html中文显示正常图表标题、坐标轴、词云均为中文肉眼检查6.3 数据量少时如何验证如果最终只采集到几十条评论图表会很难看词频分布也不稳定。此时不要直接下结论而是把数据量作为结论的一部分写出来。例如样本量为 52 条只能作为初步观察不能代表整体舆论。如果想获得更稳定的结论可以增加采集页数和时间范围。扩展到多个公开平台的数据做对比。先跑通全流程再投入更多时间扩大样本。数据量少不是项目失败而是筛选数据源和采集策略的信号。学习阶段最重要的是流程完整结论是否有统计意义则是后续迭代的问题。7. 常见问题与排查链路7.1 爬虫阶段的问题问题现象常见原因检查方式处理方法请求返回 403目标服务拒绝默认头或高频请求打印响应状态码和响应头设置完整 User-Agent降低请求频率优先使用本地样例数据返回 JSON 但解析到空列表接口字段名变化或需要登录参数打印原始 JSON 前 200 字符回到浏览器开发者工具确认字段名或使用样例数据中文乱码响应编码识别错误检查 resp.encoding使用resp.encoding resp.apparent_encoding或指定encodingutf-8CSV 在 Excel 打开乱码使用了纯 UTF-8 编码用记事本看 CSV 开头是否存在 BOM保存时使用encodingutf-8-sig需要特别强调的是如果请求出现 403 或者验证码说明目标平台有明确限制。此时正确的做法是停止继续尝试改用官方提供的公开数据接口或本地样例数据而不是研究绕过方案。学习爬虫的目的之一是理解协议和边界不是突破别人的防护。7.2 文本处理阶段的问题中文分词最常见的坑是专业词汇被切碎。比如“隐藏款”被切成“隐藏”和“款”“端盒”被切成“端”和“盒”。解决办法就是使用jieba.add_word添加自定义词典。另一个高频问题是停用词过多导致词频榜全是无意义词。建议先跑一次不过滤的词频统计看一眼原始高频词再把真正没有分析价值的词加入停用词表。情感判断不准确的问题也很常见原因是词典法无法处理否定表达。至少要在报告里说明方法的局限避免给读者造成结论可靠的错觉。7.3 可视化阶段的问题问题现象常见原因处理建议HTML 打开后图表空白浏览器没有加载 HTML 引用的 JavaScript 资源检查文件是否在本地路径不要用代码块文本直接打开图表中文显示为方框环境缺少中文字体系统安装中文字体或在图表配置中显式指定字体柱状图 x 轴文字重叠词汇过长且未旋转设置axislabel_optsopts.LabelOpts(rotate30 or 45)折线图出现断裂时间字段缺失或解析失败用pd.to_datetime(..., errorscoerce)并查看缺失值数量pyecharts 无法导入版本安装错误确认安装的是pyecharts不是旧版echarts7.4 排查顺序建议遇到问题时不要先怀疑框架。按下面的顺序排查输入数据是否存在路径是否正确。文件编码是否一致是否混用 utf-8 和 utf-8-sig。字段名是否和数据源一致打印前 3 行原始数据检查。依赖版本是否兼容重点检查 pandas 和 pyecharts 的版本。查看脚本运行时的异常堆栈定位到具体行。确认输出目录存在output目录不能不存在就调用 render。最后才考虑是否为框架限制。8. 最佳实践、合规边界和扩展方向8.1 学习环境与生产环境的差异学习环境下脚本顺序执行、数据落盘、图表输出到 HTML 就完成了。生产环境的数据分析项目还需要额外考虑以下几点配置外置化接口地址、请求间隔、关键词表不要硬编码在脚本里使用配置文件或环境变量。日志记录每个阶段记录采集数量、清洗率、失败原因方便回溯。异常重试请求失败时增加重试和退避机制但要保证重试频率合规。数据备份原始数据在清洗前先归档避免误删后无法恢复。监控告警真实业务的采集任务需要监控数据量为 0、异常率过高等指标。8.2 合规边界和采集礼仪任何采集项目都必须遵守三条基本底线只采集公开且允许访问的内容不采集个人隐私信息不以绕过平台限制为目标。学习项目建议控制采集频率设置合理的请求间隔数据只用于学习分析不用于商业目的或公开传播敏感结论。如果目标平台有开放 API优先使用官方接口没有开放接口时用少量样例数据完成流程演示是更稳妥的选择。8.3 可复用的项目扩展清单这个项目完成后可以按下面的方向继续扩展评论数据量提升到数万条加入增量采集能力定时任务每天新增数据。增加更细的维度和字段比如用户等级、评论地区、商品型号、点赞数分析不同品类用户关注点差异。将词频和情感分布做成自动更新的可视化大屏接入数据库持久化。用更完整的情感分析方案替换词典法对比简化版和进阶版的准确率差异。把采样、清洗、分析逻辑封装成函数编写单元测试形成一个可复用的数据分析模块。增加时间维度的对比分析比如新品发布前后评论情感变化这是很好的业务分析切入点。将报告输出扩展到 Word 和 PDF方便毕业设计论文引用。整个项目的核心价值不是“跑出一张词云”而是建立一套完整的数据分析工作流先确认数据源再采集落盘然后清洗分析最后用图表呈现。这个工作流可以迁移到任意文本评论场景比如电影评论、商品评论、App 应用评论。对于 Python 学习者来说把这个流程练熟比单独背 pandas API 或爬虫语法要实用得多。项目里最值得花时间的部分是清洗和分析阶段因为真实数据的脏程度远超预期而处理脏数据的能力恰恰是面试和工作中最容易体现差距的地方。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门