Python爬虫+Flask+ECharts:泡泡玛特热搜评论数据分析实战
发布时间:2026/8/31 1:22:53来源:尧图网络
1. 项目背景与功能拆解1.1 为什么选择泡泡玛特热搜评论作为分析对象很多做 Python 毕设或求职项目的同学都会选择“爬虫 数据分析 可视化”这个组合。因为这个链路短、效果直观既能展示爬虫采集能力又能体现数据分析思维还能通过图表让结果一目了然。但问题在于大部分教程都停留在爬取天气、爬取豆瓣电影这种老套案例写进简历里毫无区分度。这次我选择泡泡玛特POP MART这个潮玩品牌作为分析对象。泡泡玛特的热搜评论具有三个非常适合做数据分析的特点评论量集中。热门 IP 上新、联名发售时微博、小红书等平台的评论短时间内会大量聚集数据密度高分析价值明显。情绪表达强烈。“抢到了”“端盒”“隐藏款”“雷款”“退坑”等词汇频繁出现通过简单的文本分类就能看出用户对产品的态度。带有时间趋势。每次新品发售前后评论热度和关键词分布会发生变化适合做时间序列分析。把这套流程落地为一个可以直接运行、演示、甚至写进简历的 Flask ECharts 项目就是本文的目标。1.2 技术栈选型技术选型遵循“够用、易上手、展示效果好”的原则Python 3爬虫和数据分析的首选语言生态完善。requests BeautifulSoup4网页请求与 HTML 解析适合中小型爬虫项目。pandas数据清洗、去重、分词统计。Flask轻量级 Web 框架适合快速构建后台数据接口。ECharts百度开源的可视化库通过简单的 JS 配置就能完成饼图、柱状图、折线图、词云等图表。整套技术栈不需要重型组件一台普通电脑就能运行非常适合毕业设计、课程项目和简历中的个人项目展示。1.3 功能模块拆解整个项目划分为三大模块这也是本文后续章节的组织方式模块主要功能涉及工具数据采集模块抓取热搜评论数据保存为 CSV 文件requests、BeautifulSoup4、pandas数据分析模块清洗数据、统计关键词、计算评论情感倾向pandas、jieba可选可视化展示模块提供数据接口和前端图表展示Flask、ECharts、HTML/CSS/JavaScript为了让项目结构清晰建议代码分层编写不要把爬虫逻辑和 Flask 接口混在一起。后续会给出完整的项目目录。2. 环境准备2.1 Python 版本本文示例以 Python 3 为基础开发推荐使用 Python 3.8 及以上版本。如果你使用的是 Python 3.12 或更新版本请留意 pandas 和 jieba 是否有适配包。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。检查本地 Python 版本python --version如果你的电脑同时安装了 Python 2 和 Python 3可能需要使用python3命令。2.2 安装依赖进入项目目录后创建虚拟环境推荐python -m venv venv激活虚拟环境Windowsvenv\Scripts\activatemacOS / Linuxsource venv/bin/activate安装依赖pip install flask requests beautifulsoup4 pandas jieba各依赖库的作用flask构建 Web 服务。requests发送 HTTP 请求获取网页内容。beautifulsoup4解析 HTML提取评论等结构化数据。pandas对 CSV 或 JSON 格式的评论数据进行清洗与统计。jieba中文分词用于提取高频关键词如果只想用 ECharts 做基础图表可以不安装。如果下载速度慢可以临时换用国内镜像源pip install flask requests beautifulsoup4 pandas jieba -i https://pypi.tuna.tsinghua.edu.cn/simple2.3 项目结构建议按照下面的目录组织代码popmart-analysis/ ├── app.py # Flask 主程序 ├── crawler.py # 爬虫模块 ├── analysis.py # 数据分析模块 ├── requirements.txt # 依赖清单 ├── templates/ │ └── index.html # 前端展示页面 ├── static/ │ ├── css/ │ │ └── style.css │ └── js/ │ └── echarts.min.js # ECharts 本地文件也可使用 CDN ├── data/ │ └── comments.csv # 爬取后保存的评论数据 └── output/ └── analysis_result.json # 统计后的图表数据之所以把爬虫、分析和 Flask 主程序拆开是为了方便单独调试。你可以先跑爬虫生成 CSV再单独运行分析脚本最后再启动 Flask。这样即使某一环节出错也不影响其他模块。3. 爬虫模块实现3.1 数据源分析与合规说明先说明一个非常重要的前提爬虫只能爬取允许访问的公开数据。在编写爬虫前必须查看目标网站是否提供 API 或开放性接口。比如微博有开放平台接口虽然个人开发者申请门槛较高但相对正规。如果你申请到了接口权限可以直接按接口文档请求 JSON 数据比解析 HTML 更稳定、更合规。如果只是个人学习最稳妥的方式是使用公开测试数据或者仅抓取少量内容用作功能演示。本文的爬虫代码以通用逻辑为例你需要根据实际数据源调整选择器和接口地址。合规红线遵守目标网站的 robots.txt。控制请求频率不要并发爆破。只爬取公开可见内容不绕过登录和验证码。数据仅用于个人学习和项目演示不进行商业传播。3.2 requests 发送请求评论数据通常有两种获取方式一种是从网页 HTML 中直接解析另一种是请求后端 JSON 接口。以通用场景为例假设目标数据源提供一个返回 JSON 的评论接口我们的爬虫可以这样写# crawler.py import requests import json def fetch_comments(page): 模拟请求评论接口返回 JSON 数据 # 请注意这里需要替换为你实际可用的接口地址 url https://example.com/api/comments params { page: page, page_size: 50 } 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://example.com/ } try: resp requests.get(url, paramsparams, headersheaders, timeout10) resp.raise_for_status() return resp.json() except requests.RequestException as e: print(f请求失败{e}) return None关键点params 参数用来传递翻页和数量。headers 中必须携带 User-Agent否则很多服务器会拒绝请求。timeout 设置超时时间避免程序卡死。每次请求之间建议加上 time.sleep()降低对目标服务器的压力import time for page in range(1, 5): data fetch_comments(page) if data: # 处理数据 pass time.sleep(2) # 控制爬取频率3.3 BeautifulSoup 解析 HTML如果目标数据源是静态 HTML 页面那就需要使用 BeautifulSoup 提取评论信息。下面是一个通用的解析逻辑示例。假设网页结构中有评论列表每条评论包含用户昵称和评论内容# crawler.py from bs4 import BeautifulSoup def parse_html(html_text): 解析 HTML提取评论列表 soup BeautifulSoup(html_text, html.parser) comments [] # 需要根据实际网页结构调整选择器 comment_nodes soup.select(.comment-item) for node in comment_nodes: nickname_node node.select_one(.nickname) content_node node.select_one(.content) if not nickname_node or not content_node: continue comments.append({ nickname: nickname_node.get_text(stripTrue), content: content_node.get_text(stripTrue) }) return comments这里我用.comment-item、.nickname、.content表示占位选择器实际开发时需要通过浏览器的 F12 开发者工具确认目标网页的 HTML 结构再替换成真实选择器。3.4 pandas 数据清洗与保存爬取到的评论往往包含空值、重复内容、短评噪声等。清洗逻辑可以统一放在分析模块中爬虫只负责把原始数据落盘。# analysis.py import pandas as pd def load_comments(csv_pathdata/comments.csv): 读取评论数据 return pd.read_csv(csv_path) def clean_comments(df): 清洗评论数据 # 去掉空值 df df.dropna(subset[content]) # 去除重复评论 df df.drop_duplicates(subset[content]) # 过滤过短评论少于 2 个字符 df df[df[content].str.len() 2] # 重置索引 df df.reset_index(dropTrue) return df将爬取的数据保存为 CSV# crawler.py import csv def save_to_csv(comments, csv_pathdata/comments.csv): 将评论列表保存为 CSV 文件 with open(csv_path, w, encodingutf-8-sig, newline) as f: writer csv.DictWriter(f, fieldnames[nickname, content]) writer.writeheader() writer.writerows(comments) print(f已保存 {len(comments)} 条评论到 {csv_path})使用utf-8-sig编码是为了让 Excel 直接打开 CSV 时不出现中文乱码。4. Flask 后端接口开发4.1 创建 Flask 主程序Flask 部分的核心职责是读取分析结果通过接口返回 JSON 给前端 ECharts 使用。先写一个最简版本的app.py# app.py from flask import Flask, jsonify, render_template import json app Flask(__name__) def load_analysis_result(): 读取统计结果 JSON 文件 with open(output/analysis_result.json, r, encodingutf-8) as f: return json.load(f) app.route(/) def index(): 前端页面 return render_template(index.html) app.route(/api/summary) def api_summary(): 返回评论总览数据 data load_analysis_result() return jsonify(data[summary]) app.route(/api/sentiment) def api_sentiment(): 返回情感分布数据 data load_analysis_result() return jsonify(data[sentiment]) app.route(/api/hot_words) def api_hot_words(): 返回热词数据 data load_analysis_result() return jsonify(data[hot_words]) if __name__ __main__: app.run(host0.0.0.0, port5000, debugTrue)路由设计说明/返回前端 HTML 页面。/api/summary返回评论总量、平均长度等总览数据。/api/sentiment返回情感饼图数据。/api/hot_words返回高频关键词数据供柱状图或词云使用。这样设计的好处是前后端分离。即使你还不熟悉 ECharts也可以先用浏览器访问这些 JSON 接口确认数据是否正常返回。如果你希望 Flask 启动时自动爬取并分析数据可以增加一个初始化函数# app.py from crawler import run_crawler from analysis import run_analysis def init_data(): run_crawler() run_analysis() if __name__ __main__: init_data() app.run(host0.0.0.0, port5000, debugTrue)但更推荐的做法是分开执行因为爬虫失败时不应影响 Web 服务的启动。4.2 数据分析与结果生成在analysis.py中我们需要生成output/analysis_result.json。这个文件是 Flask 接口的数据源结构应该与接口对应。# analysis.py import json import pandas as pd from collections import Counter def analyze_keywords(df, top_n20): 统计高频关键词 # 这里可以接入 jieba 分词 # 为了演示简单按空格和常见符号切分 all_words [] for content in df[content]: # 简易分词实际应用建议使用 jieba.lcut words content.replace(, ).replace(。, ).split() all_words.extend(words) counter Counter(all_words) return counter.most_common(top_n) def analyze_sentiment(df): 简单情感统计 positive_words [好看, 喜欢, 可爱, 抢到, 满意, 绝绝子] negative_words [失望, 难看, 退货, 翻车, 投诉, 退坑] positive_count 0 negative_count 0 neutral_count 0 for content in df[content]: if any(word in content for word in positive_words): positive_count 1 elif any(word in content for word in negative_words): negative_count 1 else: neutral_count 1 return [ {name: 正面, value: positive_count}, {name: 负面, value: negative_count}, {name: 中性, value: neutral_count} ] def run_analysis(): 执行完整分析流程生成结果 JSON df load_comments() df clean_comments(df) hot_words analyze_keywords(df) sentiment analyze_sentiment(df) result { summary: { total_comments: len(df), unique_users: df[nickname].nunique() }, sentiment: sentiment, hot_words: [{name: word, value: count} for word, count in hot_words] } with open(output/analysis_result.json, w, encodingutf-8) as f: json.dump(result, f, ensure_asciiFalse, indent2) print(分析完成结果已保存到 output/analysis_result.json)这段代码里情感分析用的是最简单的词典匹配法。它的优点是容易理解、适合教学演示缺点是准确率有限。如果追求更高的准确率可以引入 SnowNLP 或基于机器学习的情感分类模型但项目复杂度会相应增加。5. ECharts 可视化页面开发5.1 HTML 页面骨架ECharts 使用方式很简单在 HTML 中引入echarts.min.js然后准备一个带宽度和高度的 DOM 容器。以 CDN 方式引入为例!-- templates/index.html -- !DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title泡泡玛特热搜评论数据分析/title script srchttps://cdn.jsdelivr.net/npm/echarts5.4.3/dist/echarts.min.js/script style body { font-family: Microsoft YaHei, sans-serif; background: #f7f7f9; margin: 0; padding: 20px; } .container { max-width: 1200px; margin: 0 auto; } h1 { text-align: center; color: #333; } .summary-cards { display: flex; gap: 20px; margin-bottom: 30px; justify-content: center; } .card { background: #fff; border-radius: 10px; padding: 20px 30px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); text-align: center; min-width: 150px; } .card h3 { margin: 0 0 10px; font-size: 16px; color: #666; } .card p { margin: 0; font-size: 32px; font-weight: bold; color: #333; } .chart-row { display: flex; flex-wrap: wrap; gap: 20px; } .chart-box { background: #fff; border-radius: 10px; padding: 20px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); flex: 1; min-width: 400px; height: 450px; } .chart-box.wide { flex-basis: 100%; } /style /head body div classcontainer h1泡泡玛特热搜评论数据分析/h1 div classsummary-cards div classcard h3评论总数/h3 p idtotalComments-/p /div div classcard h3评论用户数/h3 p idtotalUsers-/p /div /div div classchart-row div idsentimentChart classchart-box/div div idhotWordsChart classchart-box/div /div /div script // 在这里编写 ECharts 图表初始化代码 /script /body /html如果你不想依赖 CDN也可以把echarts.min.js下载后放到static/js/目录然后通过url_for(static, filenamejs/echarts.min.js)引用。这里为了保持示例简洁正文使用 CDN 方式演示等部署到正式环境时建议改为本地文件避免因外部网络问题导致图表加载失败。5.2 饼图展示评论情感分布先获取/api/sentiment的数据然后初始化饼图。ECharts 的饼图非常适合展示占比关系这里用它来展示正面、负面、中性评论的比例。// 在 script 标签中补充 async function renderSentimentChart() { // 初始化图表实例 const chart echarts.init(document.getElementById(sentimentChart)); // 获取数据 const response await fetch(/api/sentiment); const data await response.json(); // 配置项 const option { title: { text: 评论情感分布, left: center }, tooltip: { trigger: item, formatter: {a} br/{b}: {c} ({d}%) }, legend: { top: 30px }, series: [ { name: 情感占比, type: pie, radius: [40%, 70%], avoidLabelOverlap: false, itemStyle: { borderRadius: 6, borderColor: #fff, borderWidth: 2 }, data: data, emphasis: { label: { show: true, fontSize: 20, fontWeight: bold } }, label: { show: true, formatter: {b}: {d}%, fontSize: 14 } } ] }; chart.setOption(option); // 页面尺寸变化时自动缩放 window.addEventListener(resize, () chart.resize()); } renderSentimentChart();这段代码中需要注意radius: [40%, 70%]表示环形饼图。formatter中的{b}表示名称{c}表示数值{d}表示百分比。resize事件用于页面窗口变化时保持图表自适应。5.3 柱状图展示热词排行热词数据来自/api/hot_words。柱状图适合展示排名关系配合滚动条可以展示更多关键词。async function renderHotWordsChart() { const chart echarts.init(document.getElementById(hotWordsChart)); const response await fetch(/api/hot_words); const data await response.json(); // ECharts 柱状图需要 x 轴数据和 y 轴数据 const names data.map(item item.name); const values data.map(item item.value); const option { title: { text: 评论热词 TOP20, left: center }, tooltip: { trigger: axis }, grid: { left: 3%, right: 4%, bottom: 8%, containLabel: true }, xAxis: { type: category, data: names, axisLabel: { interval: 0, rotate: 40 } }, yAxis: { type: value, name: 出现次数 }, series: [ { name: 关键词热度, type: bar, data: values, itemStyle: { color: #ff6b8a } } ] }; chart.setOption(option); window.addEventListener(resize, () chart.resize()); } renderHotWordsChart();这里默认展示 20 个关键词因为词太多会导致 x 轴标签拥挤。如果希望进一步优化视觉效果可以给柱状图增加 dataZoom 缩放组件或者使用词云图展示需要额外引入echarts-wordcloud插件。6. 完整运行与效果验证6.1 准备依赖清单在项目根目录生成requirements.txt方便导出环境pip freeze requirements.txt如果你只想保留核心依赖手工创建也可以flask2.0 requests2.31.0 beautifulsoup44.12.0 pandas2.0.0 jieba0.42.16.2 运行爬虫建议先单独执行爬虫确认数据能够正常抓取再继续后续操作。在项目目录下创建一个run.py把流程串起来# run.py from crawler import save_to_csv, fetch_comments, parse_html import time if __name__ __main__: all_comments [] for page in range(1, 3): print(f正在爬取第 {page} 页...) data fetch_comments(page) if data: # 如果 data 是 JSON需要按真实结构解析 # 这里假设 data[comments] 是评论列表 comments data.get(comments, []) for item in comments: all_comments.append({ nickname: item.get(user, {}).get(nickname, ), content: item.get(text, ) }) time.sleep(2) save_to_csv(all_comments)执行python run.py预期输出正在爬取第 1 页... 正在爬取第 2 页... 已保存 76 条评论到 data/comments.csv如果保存条数为 0说明数据源结构或选择器需要调整。可以先用 print 打印返回的 JSON 或 HTML 片段检查字段名称。6.3 运行分析与启动 Flask执行分析python -c from analysis import run_analysis; run_analysis()预期输出分析完成结果已保存到 output/analysis_result.json启动 Flaskpython app.py浏览器访问http://127.0.0.1:5000你应该能看到顶部两个统计卡片评论总数、评论用户数。左侧饼图展示情感分布。右侧柱状图展示热词排行。同时访问http://127.0.0.1:5000/api/sentiment会直接返回 JSON 数据[ {name: 正面, value: 23}, {name: 负面, value: 11}, {name: 中性, value: 42} ]这说明后端的接口链路已经打通。7. 常见问题与排查思路7.1 爬虫请求返回 403问题现象常见原因解决思路请求返回 403服务器检测到非浏览器请求检查 User-Agent补全浏览器请求头请求返回 403IP 被限制降低请求频率加 time.sleep不要并发爬取请求返回 403需要 Cookie使用浏览器登录后复制 Cookie放入 headers排查步骤先用浏览器访问目标页面看是否正常打开。用 requests 打印响应状态码和响应头。对比浏览器请求头补齐缺失字段。7.2 Flask 页面能打开但图表不显示问题现象常见原因解决思路页面空白无图表ECharts 没有加载成功检查 CDN 是否可访问或改为本地文件页面出现但图表区域很小容器没有设置高度给 chart-box 加 height 样式数据接口返回错误JSON 文件不存在或路径错误确认 output/analysis_result.json 已生成7.3 中文乱码乱码通常出现在 CSV 文件和 JSON 接口两个地方。CSV 写入时使用encodingutf-8-sig可以解决 Excel 乱码。JSON 输出时json.dump加上ensure_asciiFalse可以避免中文变成\uXXXX形式。如果 Flask 接口返回乱码检查app.py中是否有app.config[JSON_AS_ASCII] False。Flask 2.3 及以后版本默认不再转义 Unicode老版本可能需要注意。7.4 DataFrame 读取为空如果data/comments.csv存在但load_comments()读取为空优先检查文件路径是否写对。CSV 中是否有表头。CSV 编码是否为 utf-8 或 utf-8-sig。可以在命令行中先打印前几行python -c import pandas as pd; df pd.read_csv(data/comments.csv); print(df.head())7.5 jieba 分词结果不理想默认分词对网络热词比如“绝绝子”“端盒”可能切分不稳定。可以通过增加自定义词典来解决。创建userdict.txt绝绝子 5 n 端盒 5 n 隐藏款 5 n加载方式import jieba jieba.load_userdict(userdict.txt)8. 最佳实践与工程建议8.1 爬虫部分爬虫是项目中合规风险最高的模块也是面试时最容易被追问的部分。建议做到以下几点请求频率必须控制。即使目标网站没有明确限制也建议单线程 延时爬取避免给对方服务器造成压力。遵循 robots.txt。很多网站会明确哪些路径不允许爬取作为学习者也应该遵守。数据只用于学习演示。展示项目时不要强调“爬取了多少条商业数据”而是强调数据如何清洗、分析、可视化。做好异常处理。对超时、连接失败、返回非 200 等情况要有兜底逻辑。8.2 数据处理部分每次做统计分析前先备份原始 CSV。清洗后的数据不要直接覆盖原文件。定义统一的字段名比如nickname、content、created_at避免后续维护时混乱。情感分析不要盲目追求复杂度。在教学项目中词典匹配足够说明问题如果要用于更严谨的场景再引入分类模型并准备标注数据验证准确率。8.3 Flask 应用部分debugTrue 只适合开发环境。如果项目要部署到公网必须关闭 debug。数据接口要做容错。如果analysis_result.json不存在建议返回一个默认空结构而不是直接报 500。生产环境可使用 gunicorn 或 waitress 代替 Flask 内置服务器pip install gunicorn gunicorn -w 2 -b 0.0.0.0:5000 app:appWindows 下可使用 waitresspip install waitress waitress-serve --listen0.0.0.0:5000 app:app8.4 可视化部分ECharts 图表的可读性很重要。建议饼图不要超过 6 个类别否则图例会堆挤。柱状图的关键词数量控制在 20 个以内必要时使用滚动条。颜色选择尽量统一不要大红大绿。每个图表都加上标题和数据说明让非技术人员也能看懂。8.5 简历与面试呈现如果你的目的是开学或找工作不要只贴一句“使用 Python 爬取 XX 数据并用 Flask ECharts 展示”。建议这样描述用 requests 和 BeautifulSoup 完成多平台公开评论数据采集编写异常处理与限流机制。使用 pandas 完成去重、清洗、关键词抽取输出结构化分析结果。基于 Flask 提供 REST API前端使用 ECharts 完成情感环形图和热词柱状图展示。项目支持本地一键运行代码分层清晰。面试官大概率会追问这三个问题如果目标网站有反爬限制你怎么办情感分析的准确率如何评估Flask 接口能承受多大并发这些问题没有标准答案但你需要提前准备。第一问可以从请求头模拟、限速、代理池、OCR 识别验证码等维度回答第二问强调召回率和准确率需要标注数据验证并且给出“当前演示项目用词典匹配生产场景应使用分类模型”的说明第三问要承认 Flask 内置服务器能力有限生产环境会换成 gunicorn 并配合 Nginx。9. 总结与后续扩展整个项目跑通之后你其实已经完成了一个完整的“数据采集 → 数据清洗 → 数据分析 → Web 可视化”链路。步骤可以拆成四个关键阶段爬虫阶段通过 requests 获取原始数据解析后落盘 CSV。清洗阶段用 pandas 去除空值和重复内容。分析阶段统计情感分布和关键词热度。展示阶段Flask 提供 JSON 接口ECharts 渲染饼图和柱状图。接下来如果你想让这个项目更有竞争力可以考虑以下扩展方向将情感分析从词典匹配升级为 SnowNLP 或预训练模型并对比不同方案的准确率。加入时间维度用折线图展示评论数量随产品发布周期的变化趋势。接入定时任务每天定时爬取增量数据形成持续更新的数据看板。将 CSV 存储替换为 MySQL 或 SQLite体验完整的“爬虫 → 入库 → 查询 → 可视化”工程链路。为 Flask 接口编写单元测试展示你的工程化意识。如果你在做毕业设计建议把重点放在“数据如何支撑一个真实业务问题”上。比如“通过分析泡泡玛特热搜评论研究不同产品线的口碑差异”就是一个可以扩展成论文的选题。单纯做爬虫演示只是工具能围绕一个业务问题展开分析才是面试时比代码本身更值钱的地方。
网站建设高端定制企业官网