基于Python的京东手机销售数据分析系统全流程解析 📅 发布时间:2026/9/9 14:44:42 👁 浏览次数: 每年毕业季我都会收到不少关于这个题目的咨询——基于Python的京东手机销售数据分析系统。很多人一开始觉得这就是个爬虫项目把京东手机页面的数据抓下来画几张图就完事了。等真正动手才发现价格反爬、品牌字段混乱、销量数据缺失、图表展示没逻辑任何一环都能卡住你好几天。这篇文章我就以完整做完这个项目的视角把从技术选型、数据采集、清洗入库、指标体系、可视化展示到论文撰写和答辩准备的全过程拆开讲清楚。不管你是正在做这个毕设的学生还是想拿它练手的数据分析初学者这篇都能帮你少走很多弯路。1. 毕业设计题目背后的真实含义不是系统是完整链路1.1 题目拆解评审老师到底想看什么这个题目全称是基于Python的京东手机销售数据分析系统在毕业设计里属于非常典型的数据采集分析展示三类合一的综合性题目。但很多学生容易把它理解窄了以为核心是爬虫。实际上从答辩角度看题目里的重点词是数据分析和系统爬虫只是获取数据的手段不是主角。评审老师评估这个题目时通常会关注四个层面的能力数据获取层能否稳定地获得足够规模、足够规范的数据数据处理层能否把非结构化的网页数据清洗成可分析的结构化数据分析建模层能否从数据中挖掘出有业务意义的结论而不是给一张统计表系统展示层能否把分析结果以图表、界面的形式呈现让用户方便查看所以你在开题阶段就要想明白这个系统不是一个爬虫脚本而是一个包含数据管理、指标计算、可视化展示的完整工具。如果只是抓数据、画图那就只能算爬虫图表练习达不到毕业设计的工作量要求。这也是为什么不少人的课题被导师打回来的原因——工作量不够、技术深度不足。注意在这个题目里系统意味着你要有数据入库、模块化代码结构、可交互的展示界面这三个基本要素。缺一个答辩时都会被追问。1.2 技术选型为什么是Python这套组合题目已经限定了Python但Python生态里能做数据分析的方案很多不同组合对开发量和演示效果影响非常大。我见过有人一上来就选ScrapyRedis分布式爬虫方案结果光环境就配了一周数据量又根本用不上分布式。对毕业设计来说技术选型要匹配题目规模核心原则是够用、能讲清楚、跑得动。我推荐的组合是这样的模块技术选型选型理由网页请求requests BeautifulSoup4requests简单直接BS4解析HTML对新手友好调试成本低数据存储MySQLSQLite可作备用体现数据库设计能力MySQL是主流答辩时更好说明数据处理pandas numpy数据清洗、去重、聚合的标准方案代码量少中文分词jieba处理评论数据时的标配工具安装简单可视化pyechartsECharts封装生成HTML交互图表比matplotlib更适合Web展示Web框架Flask轻量几行代码就能把图表模板挂到网页上这套组合里每一种技术都很常规但组合起来就是一个完整的系统。更重要的是每一层你都能在论文里单独写一章逻辑非常顺畅。相比用Java写SSM框架再拼前端图表Python这套把数据链路串起来的效率高太多了这正是题目限定Python的用意所在。1.3 项目模块划分与整体结构想清楚了选型我建议在写代码之前先把项目结构定下来。清晰的分层结构不仅开发的时候不容易乱写论文时直接按模块截图就行。我常用的结构是这样的project/ ├── spider/ # 爬虫模块 │ ├── jd_spider.py # 商品信息爬虫 │ └── review_spider.py # 评论数据爬虫 ├── data_clean/ # 数据清洗模块 │ └── clean.py ├── analysis/ # 分析模块 │ ├── price_analysis.py # 价格分析 │ ├── brand_analysis.py # 品牌分析 │ └── comment_analysis.py# 评论分析 ├── web/ # Flask展示模块 │ ├── app.py │ └── templates/ ├── sql/ # 建表语句 │ └── init.sql └── output/ # 图表输出目录这样做的好处是代码在逻辑上高内聚低耦合爬虫只管收数据清洗只管处理分析层只管算指标Web层只管展示。答辩时被问到你的系统架构是什么你直接画出这个模块图就能解释清楚。每个模块都能单独测试出了问题也知道去哪里查。2. 数据采集模块京东手机销售数据的获取与稳定性处理2.1 数据源与爬虫方案选型京东手机销售数据的获取途径主要有三种官方开放API、第三方数据平台、自己写爬虫。前两种要么需要企业资质要么要付费订阅对毕业设计不现实所以自己写爬虫几乎是唯一选择。JD的商品列表页、搜索页、详情页和评论页都是可以采集的对象。我建议采集两个层面的数据一是搜索列表页数据。根据关键词比如手机采集搜索结果可以获得商品名称、价格、店铺、评论数、好评率等基本信息。列表页的数据相对好拿因为大部分内容由服务端渲染requests直接请求就能拿到完整的HTML。二是商品详情页和评论页数据。详情页能补充更细的商品规格评论页则能拿到用户评论文本。这里有一个关键点JD的评论数据是异步加载的HTML页面上看不到数据是通过一个Ajax接口返回的。所以评论爬虫要直接请求它的接口URL而不是解析页面源码。很多人爬评论数据死活拿不到就是因为一直在看页面HTML里找内容方向就错了。2.2 字段设计采集哪些数据才有分析价值在设计爬虫字段之前先想清楚后面要做什么分析。不然你吭哧吭哧抓了20个字段最后用到的只有3个纯粹浪费时间。我最终确定的字段和用途如下字段来源分析用途product_id商品页URL中提取唯一标识避免重复数据product_name商品标题品牌、型号提取price商品页价格标签价格分布、价格与销量关系brand从标题中提取品牌竞争格局shop_name商品页店铺名店铺类型分布comment_count商品页评论数作为销量热度的近似指标rating商品好评率商品口碑分析product_url商品链接跳转验证这里有个常见认知坑要提前说京东不直接公开支付销量你能拿到的通常是评论数或好评率。所以在学术分析中一般用评论数作为销量热度的一个近似指标。这个替代在严格意义上并不完全等价但它是在平台数据约束下最合理的方案。你要在论文的数据说明部分明确写出这一假设及其局限评审老师通常能接受因为这是所有做电商数据分析的人都面临的客观限制。2.3 实际开发中的反爬处理与请求策略JD有反爬机制是必然的但毕业设计的数据量级不大完全没必要上分布式爬虫、IP代理池那种重型武器。我实测下来只要做好下面四个基础策略采集几千台手机商品的数据完全没问题。第一User-Agent随机化。不要只用默认的requests UA准备一个UA列表每次请求随机取一个模拟不同浏览器。代码很简单import random import requests UA_LIST [ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36, Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36, # 建议再多准备几个 ] headers { User-Agent: random.choice(UA_LIST), Referer: https://www.jd.com/, Accept-Language: zh-CN,zh;q0.9, } resp requests.get(url, headersheaders, timeout10)第二请求间隔控制。这是最朴素也最有效的策略。每抓一页sleep 1到3秒频率不要固定否则反而容易被识别为脚本行为。我习惯在1到3秒的范围内取随机值既保证速度又降低风险。第三异常重试机制。网络请求不可能百分百成功。我封装了一个简单的重试逻辑连续失败3次就放弃该页面并记录日志方便排查from time import sleep def fetch_with_retry(url, headers, max_retry3): for i in range(max_retry): try: resp requests.get(url, headersheaders, timeout10) if resp.status_code 200: return resp except requests.RequestException as e: print(f请求失败{e}第{i1}次重试) sleep(2) return None第四遇到滑块验证时及时降速。JD在检测到异常流量时会弹出验证页面。一旦在响应内容中检测到验证码特征就停止采集等一段时间再继续。千万别想着绕过验证码那既麻烦又带灰色性质对毕业设计完全没必要。老老实实降频慢慢跑数据量是够用的。防爬的本质是频率管理不是对抗。评审老师更关心你数据采集流程是否完整、字段是否合理反爬策略做到有意识、有手段、有限度就足够了。3. 数据清洗与存储决定分析质量的第一步3.1 京东数据里典型脏数据长什么样不管数据是爬虫抓的还是手工录的原始数据一定脏。我处理京东手机数据时遇到最多的四类问题价格字段缺失或异常有些商品缺货时价格为0有些参加促销的价格会低得离谱品牌字段不统一Apple和苹果混用HUAWEI和华为并存重复数据同一商品在不同关键词下被重复爬取评论数为空部分商品没有评价数据爬虫拿不到值如果不处理这些问题分析结果会出现明显偏差。比如你统计品牌份额如果苹果和Apple被当成两个品牌那份额计算全错了。这种低级错误在答辩时会被一眼看穿导师会觉得你连基本的数据质量意识都没有。3.2 清洗规则与pandas处理思路数据清洗我建议全部用pandas完成不要手工去Excel改。原因有两个一是可复现清洗逻辑写进代码后以后重新跑数据不用重来二是论文里可以放代码和清洗前后的对比结果显得规范。核心清洗逻辑大概是这样的import pandas as pd df pd.read_csv(jd_phone_raw.csv) # 1. 删除价格缺失或小于100元的异常数据 df df[df[price].notna() (df[price] 100)] # 2. 品牌字段标准化映射 brand_map { 苹果: Apple, Apple苹果: Apple, 华为HUAWEI: HUAWEI, 华为: HUAWEI, # 根据自己的数据继续补充映射 } df[brand] df[brand].replace(brand_map) # 3. 重复商品去重保留第一条 df df.drop_duplicates(subset[product_id]) # 4. 评论数空值填充为0 df[comment_count] df[comment_count].fillna(0) # 5. 输出清洗后的数据 df.to_csv(jd_phone_clean.csv, indexFalse, encodingutf-8-sig)价格阈值的设定是有讲究的。手机类目下不会出现低于100元的产品京东在售手机里基本没有所以用100做下限可以过滤掉大量测试数据和异常值。你也可以用分位数法做异常值过滤比如删掉价格在1%分位数以下和99%分位数以上的数据那种方法更通用但手机类目直接设业务阈值更简单直观。两种方法选一种就行论文里说清楚理由即可。清洗环节还要注意百分比字段的处理。好评率爬下来可能是98%也可能是0.98一定要统一格式。我建议统一转成小数入库时用DECIMAL(3,2)字段类型分析时不至于被格式问题干扰。3.3 数据库表结构与存储方案数据清洗完之后要入库。很多同学喜欢把清洗后的数据直接存成CSV分析阶段再读CSV。这样做不是不行但系统感就弱了。我建议用MySQL至少建两张核心表CREATE TABLE phone_info ( id INT PRIMARY KEY AUTO_INCREMENT, product_id VARCHAR(50) UNIQUE COMMENT 商品ID, product_name VARCHAR(255) COMMENT 商品名称, brand VARCHAR(50) COMMENT 品牌, price DECIMAL(10,2) COMMENT 当前价格, shop_name VARCHAR(100) COMMENT 店铺名称, comment_count INT COMMENT 评论数, rating DECIMAL(3,2) COMMENT 好评率, product_url VARCHAR(255) COMMENT 商品链接, crawl_time DATETIME COMMENT 采集时间 ); CREATE TABLE review_info ( id INT PRIMARY KEY AUTO_INCREMENT, product_id VARCHAR(50) COMMENT 商品ID, review_content TEXT COMMENT 评论内容, comment_time DATETIME COMMENT 评论时间, user_rating INT COMMENT 用户评分 );有几个细节要提醒product_id加UNIQUE约束防止爬虫重复写入price用DECIMAL而不是FLOAT避免浮点精度问题review_content用TEXT类型因为评论可能比较长每张表都加一个id自增主键方便后续分页查询写入数据库用pandas的to_sql方法比较省事但要注意如果表已存在用if_existsappend追加即可同时处理一下重复值避免主键冲突from sqlalchemy import create_engine engine create_engine(mysqlpymysql://root:123456localhost/jd_analysis?charsetutf8mb4) df.to_sql(phone_info, engine, if_existsappend, indexFalse)4. 销售数据分析的核心维度让数据开口说话4.1 价格区间分布手机市场的基本盘数据分析的第一步一定是了解数据的整体分布。价格是最直观的维度。我通常用区间统计的方式把手机价格划分为1999以下、2000-2999、3000-4999、5000-7999、8000以上几个档位然后统计每个区间的商品数量和平均评论数。这里分档的依据来自手机行业公认的价位段划分不是随意切的。这个分析的价值在于它揭示了京东手机市场的核心竞争带。比如你常常会发现2000-2999这个区间商品数量最多但按评论热度看3000-4999的区间可能才是主力。这说明京东用户在中高端机上的购买意愿更强也符合京东核心人群的消费画像。这个结论放到论文里就是价格与市场热度分层的完整故事线。用pandas做区间统计非常快bins [0, 1999, 2999, 4999, 7999, float(inf)] labels [1999以下, 2000-2999, 3000-4999, 5000-7999, 8000以上] df[price_level] pd.cut(df[price], binsbins, labelslabels) level_stats df.groupby(price_level, observedTrue).agg( 商品数量(product_id, count), 平均评论数(comment_count, mean) ).reset_index()4.2 品牌竞争格局与市场集中度品牌分析是数据里最有看点、也最容易出故事的部分。我建议从两个角度切入品牌市场占有率分别按商品数和评论总数统计可以对比商品供给和市场热度的差异品牌平均价格带每个品牌的平均价格能看出品牌定位是走高端还是性价比路线这里分享一个非常实用的计算指标市场集中度CR4。CR4就是前4大品牌的市场份额之和公式是CR4 (评论数前4大品牌评论数之和) / (全部品牌评论数总和) × 100%我算过某次采集的数据CR4可以达到75%以上。这个数字在论文中很有价值可以引出手机市场头部集中度较高的结论也可以对比不同价格带下CR4的变化。比如高端价位段的CR4可能更高说明消费者在高端市场更认头部品牌这个洞察让分析一下子就立体了。计算CR4的代码只有几行brand_total df.groupby(brand)[comment_count].sum().sort_values(ascendingFalse) top4_sum brand_total.head(4).sum() total_sum brand_total.sum() cr4 top4_sum / total_sum * 100 print(fCR4 {cr4:.2f}%)4.3 评论数据的文本挖掘与情感倾向有了评论数据不做文本挖掘就太可惜了。但毕业设计不要一上来就搞深度学习用jieba分词加词频统计加词云就能把故事讲清楚而且讲得明白。评论分析的核心步骤就三步先分词再统计词频最后可视化。示例代码如下import jieba from collections import Counter import pandas as pd df_review pd.read_sql( SELECT review_content FROM review_info, engine ) stopwords set([的, 了, 是, 很, 在, 和, 一种, 这个, 有点, 感觉]) words [] for content in df_review[review_content].dropna(): for w in jieba.cut(content): if w not in stopwords and len(w) 1: words.append(w) word_counts Counter(words).most_common(50) for word, count in word_counts[:20]: print(word, count)情感倾向分析可以做但没必要用复杂的模型。最简单可行的是基于情感词典的打分法准备一个正面词表和一个负面词表统计每条评论中正负词的出现次数。正面词出现的次数减去负面词出现的次数差值为正就是正面评价为负就是负面评价。准确率虽然比不了深度学习模型但胜在思路清晰、代码简单、论文里容易解释。你可以在论文里诚实地写本方法基于通用情感词典未针对手机领域做微调这样反而显得严谨。情感数据还可以和价格档位交叉分析比如5000元以上的手机用户正面评价占比更高还是更低不同价位段的差评聚焦在哪些词上这种交叉分析是拉开论文档次的关键。4.4 价格与销量热度的相关性分析最后一个值得做的分析是价格和评论数之间的关系。用pandas的corr方法就能算corr df[[price, comment_count]].corr() print(corr)你会经常发现price和comment_count的皮尔逊相关系数为负这在手机品类里非常常见。意思是手机价格越低评论热度往往越高。从业务逻辑上很好解释低价手机的消费人群基数大、购买决策更轻更容易产生评价高价手机的购买门槛高决策周期长评论量相对少。需要特别提醒的是相关性不等于因果性。论文里表述要严谨写成价格与评论热度存在负相关关系而不是低价导致更多评论。导师非常在意这种措辞的准确性一个导致可能就把你从数据分析拉回主观臆断的坑里。你还可以进一步按品牌分组做相关系数对比看哪个品牌的价格敏感度最高这个结论对商业运营有直接参考价值。5. 可视化与系统展示从图表到可操作的界面5.1 为什么选择pyecharts而不是matplotlibmatplotlib是Python数据可视化的基本功但它生成的是静态图片交互性差而且中文字体经常出问题。pyecharts直接调用ECharts的JS库生成的是HTML页面鼠标悬停有提示、有缩放、有数据视图展示效果在答辩现场会更抓眼球。pyecharts的基本用法很简单两三行代码就能出一个交互图表from pyecharts.charts import Bar from pyecharts import options as opts bar ( Bar() .add_xaxis([1999以下, 2000-2999, 3000-4999, 5000-7999, 8000以上]) .add_yaxis(商品数量, [120, 230, 180, 90, 45]) .set_global_opts(title_optsopts.TitleOpts(title京东手机价格区间分布)) ) bar.render(output/price_dist.html)还有一个隐藏优势是中文支持。matplotlib在Windows下画中文图要额外设置字体不然全是方块字pyecharts生成的是网页天然支持UTF-8和中文文本省掉了这个折腾过程。5.2 Flask搭建数据展示后台有了单个图表下一步是把它们串成一个系统。Flask在这个场景下最合适因为它的模板引擎可以直接把pyecharts生成的HTML文件嵌入页面或者通过接口动态返回数据。我推荐用接口返回JSON、前端渲染ECharts的方式虽然代码量稍微多一点但前后端分离的思路更清晰论文里写基于Flask的轻量级前后端交互也更专业。核心代码结构这样组织from flask import Flask, render_template, jsonify import pandas as pd from apscheduler.schedulers.background import BackgroundScheduler app Flask(__name__) app.route(/) def index(): return render_template(index.html) app.route(/api/brand_share) def brand_share(): sql SELECT brand, SUM(comment_count) as total FROM phone_info GROUP BY brand ORDER BY total DESC df pd.read_sql(sql, engine) return jsonify(df.to_dict(orientrecords)) if __name__ __main__: app.run(debugTrue, port5000)在templates的HTML页面里用ECharts的JavaScript接口拉取数据并渲染。这里要留心一个细节Flask内置服务器的并发能力有限如果页面访问人数多、数据接口响应慢可以引入缓存或预先计算好结果集。对毕业设计来说最省事的方案是在系统启动时把分析结果预先算好存入内存或静态JSON文件接口直接读结果不做实时聚合计算。这样展示流畅性大幅提升答辩演示时不至于卡顿。5.3 图表选择的表达逻辑展示层面最后要提醒的是图表不是越多越好每个图表都要对应一个分析结论。我在设计图表展示时遵循一条原则——一图一结论。具体对应关系可以参考价格分布用柱状图对应中端机竞争最激烈的结论品牌市场份额用饼图或环形图对应头部品牌集中度高的结论价格和评论数的关系用散点图对应价格与热度负相关的结论评论高频词用词云对应用户关注的核心维度的结论各品牌平均价格用横向条形图对应品牌定位分层的结论价格区间和好评率用折线图对应不同价位段口碑差异的结论如果你发现某张图讲不出结论那张图就是多余的删掉。这一点在答辩时非常加分因为体现的是数据分析思维而不是工具操作能力。导师问为什么选这个图你要能回答因为我要表达的是占比关系所以用饼图如果要表达多个类别的大小排序我更倾向于用条形图而不是饼图。这种回答一出老师就知道你是真的理解可视化逻辑不是套了个模板。6. 从开发到答辩踩过的坑与文档撰写经验6.1 编码、中文与数据库连接的经典坑这个项目的坑主要集中在三块几乎每个人都会踩提前说清楚能省很多时间。第一是编码坑。Windows环境下CSV文件默认可能是gbk编码pandas读取时直接报错。解决方法很简单读取和写入时都显式指定encodingutf-8-sig。写数据库时也要注意MySQL连接字符串里的charset参数建议统一用utf8mb4它比utf8多支持一些生僻字符和emoji评论内容里经常出现这些字符import pymysql conn pymysql.connect( hostlocalhost, userroot, password123456, databasejd_analysis, charsetutf8mb4 )第二是数据库时间字段的坑。如果爬虫抓到的评价时间是2024-06-01 12:30:00这种字符串直接插入DATETIME字段没问题。但如果你在Windows下本地时间格式是2024/6/1MySQL的严格模式可能会拒绝写入。稳妥的做法是入库前用pandas的to_datetime统一转换df[comment_time] pd.to_datetime(df[comment_time], errorscoerce)第三是数据量陷阱。有些同学一次性爬了几万条数据然后用pandas处理时内存占用过高电脑直接卡死。毕业设计的数据量控制在几千到一万条完全够用图表的规律性已经能体现出来没必要贪多。在论文里你也可以说明本文采集了X条有效商品数据和Y条评论文本数据量足以支撑所设计的分析维度显得对数据规模有清醒的认识。6.2 LW文档论文的结构组织与写作要点题目里写的LW文档就是毕业设计论文。论文结构建议按开发流程走评委最容易跟随你的逻辑具体章节划分可以参考如下框架第一章 绪论研究背景、国内外研究现状、研究意义和主要内容第二章 相关技术介绍对Python、pandas、MySQL、pyecharts逐个介绍不要抄官方文档要结合本项目的使用场景来写第三章 需求分析功能性需求和非功能性需求可以用用例图描述系统角色和功能第四章 系统设计总体架构、数据库表设计、各模块详细设计第五章 系统实现分模块贴核心代码和运行界面截图每个模块附功能说明第六章 系统测试测试环境、测试用例表格、测试结果分析写作时注意两个问题。第一代码不要全文大段粘贴只保留核心代码片段并加注释说明这段代码实现了什么逻辑全文代码一般控制在总篇幅的20%以内。第二每个图表都要有结论性描述不能只放图不解释这是论文和项目报告最本质的区别。比如价格分布图下面至少写两句话从图中可以看出哪个价格区间商品数量最多、这个现象可能的业务原因是什么。6.3 答辩演示的实操建议答辩时间通常只有5到10分钟你必须把最亮眼的东西放在前面讲。我的建议是这样安排演示流程先打开系统首页展示整体界面布局点一下导航说明系统的功能模块。然后演示品牌分析页结合图表讲一个具体的业务结论比如从图中可以看出前四大品牌占据了75%以上的评论热度市场集中度很高。最后切到评论分析页展示词云和情感分析结果说明用户最关注哪些关键词。整个流程控制在5分钟内剩下的时间留给老师提问。常见的答辩问题提前准备答案我列几个高频的为什么用评论数代替销量——京东不公开具体销量数据评论数在平台上是公开可获取的与销量存在正向相关性论文中已说明该替代的局限性数据是怎么保证代表性的——通过搜索关键词覆盖主流手机商品按分页全量采集清洗后保留了有效样本如果数据量达到百万级方案还适用吗——当前方案适用于中小规模数据大规模场景可以引入Scrapy框架、消息队列和分布式存储这是后续扩展方向分析结果如何验证——通过两个途径定性上与行业公开报告对比验证趋势一致性定量上用相关系数、集中度等统计指标刻画数据内在结构这些问题都不难关键是你要在答辩前把自己的技术方案想透不要在为什么上支支吾吾。另外提醒一句答辩前至少完整走一遍演示流程把浏览器缓存清掉、数据库服务启动好、端口没被占用这些细节看起来小翻车了却是大事。作为一个带过不少毕业设计的人我最后想说的是这个题目的上限其实很高。同样是基于Python的京东手机销售数据分析系统有人只做三张图有人能做出带交互的多维分析平台。差别不在于学的技术多高级而在于你有没有把每一个环节落实到位、把每一张图背后的业务逻辑讲清楚。你把这个完整链路跑通技术的熟练度、论文的素材、答辩的信心都会自然而然地出来。真到了演示那一刻你会觉得这些敲过的代码、改过的bug都值了。