十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Python数据分析可视化实战:爬虫+Flask+ECharts构建评论大屏

Python数据分析可视化实战:爬虫+Flask+ECharts构建评论大屏 有不少同学在准备毕业设计、求职简历项目时都会遇到同一个问题数据从哪来怎么展示怎么把一个普通的数据分析项目包装成能写进简历的完整实战案例我最近在整理一套 Python3 数据分析可视化案例选择“泡泡玛特热门产品评论”作为分析对象基于 Flask 提供后端服务使用 ECharts 完成可视化大屏展示。整套项目从数据采集、清洗、分析到可视化展示闭环完整。这篇文章就把完整思路、代码、关键配置和排错经验都整理出来纯手把手教学新手也能一步步跑起来。如果你是正在准备毕设、想在简历里放一个有数据量的练手项目或者刚开始学 Python 爬虫 Flask ECharts这篇内容会比较适合你。文章较长建议先收藏然后跟着文章把环境搭好再逐段运行代码。1. 项目背景与功能拆解1.1 为什么选择“评论数据”做可视化购物评论是电商和消费品牌最重要的数据资产之一。它包含用户评分、评论文本、发布时间、点赞数、购买评价等多个维度非常适合做数据分析教学。选择热门潮玩品牌的评论数据主要有三个原因数据话题性强用户关注度高分析结果更容易产生“看得懂”的结论。评论数据天然适合做词频分析、情感分析、评分分布、时间趋势等多维度展示。数据格式相对规整适合爬虫采集和后续清洗。这个项目的核心目标不是预测股价、不是训练复杂模型而是搭建一条“数据采集 → 数据清洗 → 数据存储 → 后端接口 → 前端图表”的完整链路。1.2 项目功能模块拆解整个项目可以分为四个模块模块作用技术点数据采集获取评论原始数据requests、CSV数据清洗与分析对评论进行清洗、统计Pandas、Jieba后端接口为前端提供 JSON 数据Flask前端可视化图表展示分析结果HTML、ECharts、Ajax这四个模块串联起来后访问网页就能看到整套数据分析结果。每个模块都可以单独拆出来讲非常适合面试时展示项目思路。2. 环境准备与项目初始化2.1 需要准备的环境本文示例以常见环境为例版本需根据你的实际系统调整重点是演示整体配置思路。需要安装的软件和库如下Python 3.8 及以上版本Flaskpandasjiebarequests浏览器推荐 Chrome如果你的电脑还没有安装 Python可以到 Python 官网下载安装包安装时记得勾选“Add Python to PATH”。2.2 创建虚拟环境并安装依赖建议在项目目录下创建虚拟环境避免依赖冲突。Windows 下打开命令提示符Linux/Mac 打开终端执行以下命令mkdir popmart-analysis cd popmart-analysis python -m venv venv激活虚拟环境Windows 下执行venv\Scripts\activateLinux/Mac 下执行source venv/bin/activate创建requirements.txt文件内容如下flask3.0.0 pandas2.1.4 jieba0.42.1 requests2.31.0然后执行安装命令pip install -r requirements.txt2.3 项目目录结构建议按照下面的结构组织项目popmart-analysis/ ├── venv/ # 虚拟环境 ├── data/ │ └── comments.csv # 评论数据 ├── scraper/ │ └── spider.py # 爬虫脚本 ├── analysis/ │ └── data_analysis.py # 数据分析脚本 ├── app.py # Flask 后端入口 ├── templates/ │ └── index.html # 可视化页面 ├── static/ │ ├── css/ │ │ └── style.css │ └── js/ │ └── echarts.min.js # ECharts 库文件 └── requirements.txttemplates和static是 Flask 的固定目录结构前者存放 HTML 模板后者存放静态资源。ECharts 的echarts.min.js可以从 ECharts 官网下载也可以使用 CDN 链接后面代码中我会给出 CDN 方式。3. 评论数据采集模块3.1 爬虫设计思路与合规说明先强调一个重要前提爬虫技术只应用于学习研究、公开数据采集并且需要遵守目标网站的robots.txt协议和相关法律法规。本项目以技术演示为主不会针对具体网站做绕过反爬、破解验证码等操作。评论数据采集的基本思路是找到评论数据对应的 HTTP 请求接口。使用requests模拟浏览器发送请求获取 JSON 数据。解析 JSON提取评论的评分、内容、时间、点赞数等字段。保存为 CSV 文件供后续分析使用。很多网站的评论接口是动态加载的直接解析 HTML 页面拿不到数据。这里需要打开浏览器的开发者工具F12在 Network 面板查看 XHR 请求找到真正的数据接口。3.2 使用 requests 获取评论数据下面是一个通用型评论采集脚本核心思路已经写好。实际使用中只需要根据目标接口的返回格式调整字段名和参数即可。文件路径scraper/spider.pyimport csv import time import requests # 请求头模拟浏览器访问避免部分服务器拒绝请求 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, Accept: application/json, text/plain, */* } # 示例接口地址实际使用请替换为目标网站可访问的公开数据接口 COMMENT_API https://example.com/api/comments # CSV 表头 CSV_HEADER [comment_id, user_name, rating, comment_time, comment_text, like_count] def fetch_comments(page: int, page_size: int 20) - list: 请求评论接口返回评论列表。 实际使用时需要根据接口文档调整参数和解析逻辑。 params { page: page, pageSize: page_size, } try: response requests.get(COMMENT_API, headersHEADERS, paramsparams, timeout10) response.raise_for_status() data response.json() # 这里是示例解析逻辑实际以接口返回结构为准 return data.get(data, {}).get(list, []) except requests.RequestException as e: print(f第 {page} 页请求失败{e}) return [] def parse_comment(item: dict) - list: 将接口返回的单条评论数据解析为 CSV 行。 return [ item.get(comment_id, ), item.get(user_name, ), item.get(rating, 0), item.get(create_time, ), item.get(content, ), item.get(like_count, 0) ] def save_to_csv(rows: list, file_path: str ../data/comments.csv): 将评论数据追加写入 CSV 文件。 使用 utf-8-sig 编码避免 Excel 打开乱码。 with open(file_path, modea, newline, encodingutf-8-sig) as f: writer csv.writer(f) if f.tell() 0: writer.writerow(CSV_HEADER) writer.writerows(rows) def main(): # 创建 CSV 并写入表头 with open(../data/comments.csv, modew, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow(CSV_HEADER) # 爬取前 5 页示例数据 for page in range(1, 6): print(f正在采集第 {page} 页...) comments fetch_comments(page) rows [parse_comment(item) for item in comments] save_to_csv(rows) time.sleep(1) # 礼貌爬取控制请求频率 print(采集完成数据已保存到 data/comments.csv) if __name__ __main__: main()在这个脚本里需要注意几个关键点COMMENT_API是示例地址实际使用时要替换成目标网站真实的公开数据接口。parse_comment方法里的字段名需要根据真实接口的 JSON 结构调整。time.sleep(1)表示每次请求间隔 1 秒这是最基本的礼貌爬取策略避免对目标服务器造成压力。如果你暂时没有合适的接口也可以跳过爬虫直接构造一份模拟数据来跑通后面的分析和展示流程。项目核心是数据分析链路数据来源可以后续再补。3.3 数据清洗与存储采集到的原始数据不能直接用于分析原因主要有几个评论文本可能包含大量换行、特殊符号。评论时间格式不统一。有些字段可能为空。评分可能出现异常值。所以数据分析前需要先做清洗。这部分直接在数据分析模块中处理。4. 基于 Pandas 的数据分析4.1 数据读取与清洗文件路径analysis/data_analysis.pyimport pandas as pd def load_and_clean_data(file_path: str ../data/comments.csv) - pd.DataFrame: 读取评论 CSV 数据并完成基础清洗。 df pd.read_csv(file_path, encodingutf-8-sig) # 1. 删除完全重复的行 df.drop_duplicates(inplaceTrue) # 2. 删除评论内容为空的行 df.dropna(subset[comment_text], inplaceTrue) # 3. 将评论时间统一转换为 datetime 类型无法解析的置为 NaT df[comment_time] pd.to_datetime(df[comment_time], errorscoerce) # 4. 过滤评分为空的记录 df df[df[rating].notna()] # 5. 清洗评论内容中的换行和多余空格 df[comment_text] df[comment_text].astype(str).str.replace(\n, ) df[comment_text] df[comment_text].str.strip() return df def generate_statistics(df: pd.DataFrame) - dict: 生成基础统计指标供 Flask 接口和前端展示使用。 stats { total_comments: int(len(df)), avg_rating: round(float(df[rating].mean()), 2), max_like_count: int(df[like_count].max()), total_like_count: int(df[like_count].sum()), } return stats if __name__ __main__: data load_and_clean_data() print(data.head()) print(generate_statistics(data))清洗逻辑按顺序执行drop_duplicates()删除重复评论。dropna()去掉缺失关键字段的记录。pd.to_datetime()把字符串时间转成标准时间格式。正则替换掉换行符。4.2 评分分布统计评分分布是评论数据分析中最直观的指标之一适合用饼图展示。def rating_distribution(df: pd.DataFrame) - list: 统计各评分1-5星的评论数量返回 ECharts 饼图所需的数据格式。 rating_counts df[rating].value_counts().sort_index() result [] for rating, count in rating_counts.items(): result.append({name: f{rating} 星, value: int(count)}) return result输出结果示例[ {name: 1 星, value: 12}, {name: 2 星, value: 8}, {name: 3 星, value: 35}, {name: 4 星, value: 78}, {name: 5 星, value: 320} ]4.3 好评高频词统计高频词统计可以反映用户对产品的主要评价点。这里使用jieba分词库。import jieba from collections import Counter def stopwords_set() - set: 定义简单的停用词表。 实际项目中可以根据分析结果不断补充。 return { 这个, 一个, 真的, 感觉, 还是, 就是, 但是, 不过, 虽然, 他们, 我们, 你们, 什么, 可以, 觉得, 非常, 已经 } def top_keywords(df: pd.DataFrame, top_n: int 20) - list: 统计评论内容中出现次数最多的关键词。 all_text .join(df[comment_text].tolist()) words jieba.lcut(all_text) stopwords stopwords_set() filtered_words [ word.strip() for word in words if word.strip() and len(word.strip()) 1 and word.strip() not in stopwords ] counter Counter(filtered_words) result [] for word, count in counter.most_common(top_n): result.append({name: word, value: count}) return result这里有两个细节需要注意jieba.lcut返回的是分词后的列表。过滤条件中len(word.strip()) 1会过滤掉单个汉字避免无意义的“的、了、是”等字干扰。4.4 按照时间维度的评论趋势时间趋势可以看出产品口碑的变化过程。def time_trend(df: pd.DataFrame) - dict: 统计每天及每月的评论数量趋势。 df df.dropna(subset[comment_time]) # 按天统计 daily_counts df.groupby(df[comment_time].dt.date).size() # 按月统计 monthly_counts df.groupby(df[comment_time].dt.to_period(M)).size() return { daily_dates: [str(d) for d in daily_counts.index], daily_values: [int(v) for v in daily_counts.values], monthly_dates: [str(p) for p in monthly_counts.index], monthly_values: [int(v) for v in monthly_counts.values] }将这四个统计函数集中到一个入口方法中方便 Flask 调用def get_analysis_result() - dict: 统一调用所有分析函数返回完整分析结果。 df load_and_clean_data() result { statistics: generate_statistics(df), rating_distribution: rating_distribution(df), top_keywords: top_keywords(df), time_trend: time_trend(df), } return result if __name__ __main__: analysis_data get_analysis_result() print(analysis_data)5. Flask 后端接口开发5.1 Flask 应用基本结构Flask 是一个轻量级 Web 框架非常适合做小型数据可视化项目。后端只需要提供两个功能渲染index.html页面。提供 JSON 数据接口。文件路径app.pyfrom flask import Flask, jsonify, render_template from analysis.data_analysis import get_analysis_result app Flask(__name__) app.route(/) def index(): 渲染可视化大屏页面。 return render_template(index.html) app.route(/api/analysis) def analysis(): 返回评论数据分析结果前端通过 Ajax 请求该接口。 result get_analysis_result() return jsonify(result) if __name__ __main__: # debugTrue 方便开发调试生产环境务必关闭 app.run(host0.0.0.0, port5000, debugTrue)需要说明几点jsonify会将 Python 字典自动序列化为 JSON 格式。render_template会从templates目录查找对应的 HTML 文件。debugTrue开启后代码修改会自动重启服务但生产环境不能使用。5.2 数据接口返回格式运行 Flask 后访问http://127.0.0.1:5000/api/analysis会返回类似下面的 JSON 结构{ statistics: { total_comments: 453, avg_rating: 4.35, max_like_count: 128, total_like_count: 1024 }, rating_distribution: [ {name: 1 星, value: 12}, {name: 2 星, value: 8}, {name: 3 星, value: 35}, {name: 4 星, value: 78}, {name: 5 星, value: 320} ], top_keywords: [ {name: 颜值, value: 66}, {name: 做工, value: 54} ], time_trend: { daily_dates: [2025-01-01, 2025-01-02], daily_values: [10, 15], monthly_dates: [2025-01, 2025-02], monthly_values: [120, 200] } }前端页面拿到这个 JSON 后就可以用 ECharts 渲染图表了。6. ECharts 可视化页面6.1 页面整体布局可视化页面采用“顶部数据卡片 中部图表区 底部图表区”的经典布局。顶部展示核心指标卡片中部左侧放评分分布饼图中部右侧放评论趋势折线图下方放高频关键词柱状图。为了减少代码量页面中直接使用 ECharts 的 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 * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Microsoft YaHei, PingFang SC, sans-serif; background: #f5f7fa; color: #333; padding: 20px; } .header { text-align: center; padding: 24px 0; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #fff; border-radius: 12px; margin-bottom: 20px; } .header h1 { font-size: 24px; } .cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 20px; } .card { background: #fff; border-radius: 12px; padding: 20px; text-align: center; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); } .card .value { font-size: 32px; font-weight: bold; color: #667eea; } .card .label { font-size: 14px; color: #999; margin-top: 8px; } .chart-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; } .chart-box { background: #fff; border-radius: 12px; padding: 20px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); } .chart-box h3 { font-size: 16px; margin-bottom: 12px; color: #333; } .chart { width: 100%; height: 350px; } media (max-width: 768px) { .cards { grid-template-columns: repeat(2, 1fr); } .chart-row { grid-template-columns: 1fr; } } /style /head body div classheader h1泡泡玛特热门产品评论数据分析/h1 /div div classcards div classcard div classvalue idtotalComments0/div div classlabel评论总数/div /div div classcard div classvalue idavgRating0/div div classlabel平均评分/div /div div classcard div classvalue idmaxLikeCount0/div div classlabel最高点赞/div /div div classcard div classvalue idtotalLikeCount0/div div classlabel总点赞数/div /div /div div classchart-row div classchart-box h3评分分布/h3 div idratingChart classchart/div /div div classchart-box h3评论数量时间趋势/h3 div idtrendChart classchart/div /div /div div classchart-row div classchart-box h3高频评价关键词/h3 div idkeywordChart classchart/div /div div classchart-box h3数据说明/h3 div iddescriptionBox stylepadding: 20px; font-size: 14px; line-height: 2; color: #666; p1. 本项目展示的数据为评论采集与统计分析结果。/p p2. 评分分布统计了 1 星到 5 星的评论数量。/p p3. 时间趋势反映评论数量随时间的变化情况。/p p4. 高频关键词基于评论内容分词后统计得出。/p /div /div /div script src{{ url_for(static, filenamejs/main.js) }}/script /body /html6.2 ECharts 图表初始化与数据对接将图表渲染逻辑放在static/js/main.js中使用 Fetch API 获取后端数据。因为所有统计函数返回的数据结构都是 ECharts 可以直接使用的格式所以前端代码非常简洁。文件路径static/js/main.js// 初始化四个图表实例 var ratingChart echarts.init(document.getElementById(ratingChart)); var trendChart echarts.init(document.getElementById(trendChart)); var keywordChart echarts.init(document.getElementById(keywordChart)); // 从后端获取数据 fetch(/api/analysis) .then(function (response) { return response.json(); }) .then(function (data) { // 1. 更新顶部统计卡片 document.getElementById(totalComments).innerText data.statistics.total_comments; document.getElementById(avgRating).innerText data.statistics.avg_rating; document.getElementById(maxLikeCount).innerText data.statistics.max_like_count; document.getElementById(totalLikeCount).innerText data.statistics.total_like_count; // 2. 渲染评分分布饼图 ratingChart.setOption({ tooltip: { trigger: item }, legend: { bottom: 0 }, series: [{ type: pie, radius: [40%, 70%], data: data.rating_distribution }] }); // 3. 渲染评论数量时间趋势折线图 trendChart.setOption({ tooltip: { trigger: axis }, legend: { data: [评论数量] }, grid: { left: 3%, right: 4%, bottom: 5%, containLabel: true }, xAxis: { type: category, data: data.time_trend.monthly_dates, name: 月份 }, yAxis: { type: value, name: 评论数量 }, series: [{ name: 评论数量, type: line, smooth: true, data: data.time_trend.monthly_values }] }); // 4. 渲染高频关键词柱状图 // 为了让柱状图横向展示需要将关键词数据按数量排序后反转 var keywords data.top_keywords.slice().reverse(); keywordChart.setOption({ tooltip: { trigger: axis }, grid: { left: 10%, right: 4%, bottom: 5%, containLabel: true }, xAxis: { type: value, name: 出现次数 }, yAxis: { type: category, data: keywords.map(function (item) { return item.name; }) }, series: [{ type: bar, data: keywords.map(function (item) { return item.value; }), itemStyle: { color: #667eea } }] }); }) .catch(function (error) { console.error(数据加载失败, error); }); // 窗口大小变化时自动调整图表尺寸 window.addEventListener(resize, function () { ratingChart.resize(); trendChart.resize(); keywordChart.resize(); });6.3 ECharts 图表解释四个图表页面对应四条数据链路评分分布饼图直接展示rating_distribution数组体现用户满意度结构。时间趋势折线图使用time_trend中的月份数据展示评论量变化趋势。高频关键词柱状图展示评论中高频出现的词汇侧面反映用户关注点。顶部统计卡片展示评论总数、平均评分、最高点赞数、总点赞数。如果后续想增加词云图可以在页面中新增一个div再引入echarts-wordcloud插件把top_keywords的数据直接传入series.data即可。7. 运行与验证7.1 启动 Flask 服务在项目根目录执行python app.py看到类似输出说明启动成功* Serving Flask app app * Debug mode: on * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:50007.2 访问页面查看效果浏览器访问http://127.0.0.1:5000可以看到顶部四张数据卡片有数值显示。左侧评分分布饼图正常渲染。右侧时间趋势折线图展示各月评论数量。下方高频关键词柱状图展示关键词排行。再访问http://127.0.0.1:5000/api/analysis可以看到 JSON 数据。如果页面图表没有渲染优先在浏览器开发者工具的 Console 面板中查看是否有报错。8. 常见问题与排查思路我在开发和运行过程中遇到过不少问题下面整理成表格方便你按图索骥。问题现象常见原因解决思路运行python app.py提示找不到模块虚拟环境未激活或依赖未安装激活虚拟环境执行pip install -r requirements.txt页面打开后图表不显示请求/api/analysis失败或数据为空打开开发者工具 Network 面板查看接口返回状态ECharts 图表显示空白图表容器高度为 0确保.chart类设置了height: 350pxCSV 文件用 Excel 打开乱码编码不是 UTF-8-BOM写入 CSV 时使用encodingutf-8-sig爬虫请求超时网络问题或接口地址不可访问检查接口地址是否正确或增大 timeout 参数分词结果不准确缺少自定义词典使用jieba.add_word(泡泡玛特)添加领域词汇时间趋势图表 x 轴数据过多按天统计跨度太大前端切换为按月统计数据或限制展示最近 30 天刷新页面后数据没有变化分析结果是从 CSV 重新计算确认爬虫已抓取新数据并重新写入 CSV如果遇到页面接口返回 500可以在终端看到 Flask 日志中的完整报错。最常见的错误是 CSV 文件路径不对导致FileNotFoundError。此时检查运行app.py时的工作目录是否在项目根目录。9. 最佳实践与项目拓展9.1 代码与工程规范建议这个项目虽然是一个学习型案例但写法和生产项目保持一致的规范对你面试和后续维护都更有帮助。第一路径统一管理。建议把 CSV 路径、接口地址等配置信息集中放在config.py中方便修改# config.py import os BASE_DIR os.path.dirname(os.path.abspath(__file__)) DATA_PATH os.path.join(BASE_DIR, data, comments.csv)第二异常处理要完整。爬虫模块要处理网络超时、请求异常分析模块要处理空数据、字段缺失Flask 接口要处理数据加载失败的情况。第三日志记录。生产环境中不要使用大量print建议使用 Python 自带的logging模块记录关键步骤。import logging logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) logger.info(开始加载评论数据...)第四敏感信息保护。爬虫请求头、接口地址等如果涉及个人账号信息不要硬编码在代码中建议使用环境变量管理。9.2 项目功能拓展方向如果想让这个项目在简历中更有竞争力可以在以下方向做扩展增加情感分析使用 SnowNLP 或大模型 API 对评论文本做正向/负向判断新增情感分布图。增加词云图使用echarts-wordcloud插件把高频关键词做成词云。增加多产品对比采集多个产品的评论通过下拉框切换不同产品的分析结果。增加评论详情列表在页面下方展示评论原始数据支持翻页和搜索。部署上线使用 Gunicorn Nginx 部署 Flask 应用。9.3 面试时如何讲解这个项目准备面试时建议按照“项目背景 → 技术选型 → 数据流 → 难点与解决 → 改进方向”的结构来讲解。重点突出三条主线数据流从爬虫采集到 CSV 存储再到 Pandas 清洗统计最后通过 Flask 接口提供给前端。前端适配ECharts 直接消费后端统计好的结构化数据前端不需要做复杂数据处理。工程意识项目有目录分层、异常处理、基础配置管理代码不是一个文件写到底。这种“后端出数据、前端出图表”的结构在面试官眼中更像一个完整的小型系统而不是单纯的爬虫脚本。最后给你一个实践建议拿到本文代码后先不要急着改功能第一步是把整套项目完整跑通确认页面能正常展示。跑通之后再逐步替换成自己采集的数据源调整分析指标最后加上一两个个性化图表。这样既能保证项目可控又能把每一步的原理吃透。动手把项目跑起来比看十遍文章更有收获。
返回列表