买鞋之前先问数据:我为什么要做这个得物鞋类分析与推荐系统
做毕业设计那会儿,我刷了不下两百篇学长学姐的经验贴,发现计算机专业的毕设项目基本就三种套路:管理系统、电商网站、凑数的“智能XX”。但真正能写在简历上、面试时讲得清楚的,反而是那种把一个垂直场景吃透的项目。所以我最后选了这个方向:用 Python 抓取得物平台的鞋类商品数据,做完整的数据清洗和可视化分析,再用协同过滤算法搭一套个性化推荐系统,最后用 Django 把所有能力打包成一个能直接在浏览器里用的 Web 平台。如果你也正在为选题发愁,或者想把手上的“爬虫+可视化+推荐”项目做出差异化,这篇东西应该能帮你省不少劲。
先把这个项目能做什么说清楚:输入一个球鞋关键词,系统能从得物页面抓回商品价格、发行量、热度、品牌、系列等结构化数据,然后自动完成清洗入库;前端页面可以按品牌、价格段、热度区间筛选数据,展示价格走势、品牌分布、热度排行等多维图表;针对登录用户,系统会根据他浏览和收藏过的鞋款,通过协同过滤算法推荐“你可能也想要”的鞋子。整个工程从数据层到算法层再到展示层,链路完整,适合想系统掌握 Python 全栈数据项目的人,也适合需要一份能现场演示、能讲清楚设计思路的毕设项目来参考。
1. 项目整体设计与技术选型思路
1.1 为什么选 Python + Django,而不是 Flask 或 Spring
很多同学上来就问“用 Flask 行不行”,我直接说结论:行,但没必要。Flask 确实更轻,写个小接口很快,可它把 ORM、Admin 后台、表单校验、模板渲染这些都要你自己拼装。Django 虽然被称为“重型框架”,但它自带的后台管理系统和 ORM 对毕设这种需要“快速出完整效果”的场景极其友好。
我用的版本组合是 Python 3.9 + Django 4.1,数据库选了 MySQL 8.0。Django 的 ORM 可以把 Python 类自动映射成数据库表,写完模型定义后一句
makemigrations
加
migrate
就能建表,不用手动写 SQL。而且 Django 天然支持 MTV 架构——Model 管数据、Template 管页面、View 管逻辑,答辩的时候画架构图特别方便,评审老师一看就明白你的分层思想。
1.2 协同过滤算法为什么适合鞋类推荐这种场景
推荐算法的选型需要和数据形态匹配。鞋类商品有一个很典型的特点:用户间存在明显的“圈子”效应——喜欢 AJ 的人通常也会看 Dunk,关注 Yeezy 的人大概率对 Boost 底的其他鞋款感兴趣。这种“人以群分”的消费模式,刚好是协同过滤算法的强项。
我在项目里用了两种协同过滤的混合策略:基于用户的协同过滤(UserCF)找相似兴趣用户,基于物品的协同过滤(ItemCF)找相似商品。为什么不用基于内容的推荐?因为鞋类数据里能提取的文本特征(标题、描述)非常有限,单纯按关键词匹配很容易推同款不同码,用户实际上并不需要“再买一双一样的”。而协同过滤基于的是用户对物品的隐式反馈(浏览、收藏、点击详情),它能发现不同款式之间的潜在关联。数学上我用的是皮尔逊相关系数做相似度计算,比余弦相似度更能处理用户评分尺度不一致的问题——毕竟有的用户只看不买,有的用户看到就收藏,行为评分天然不等价。
1.3 可视化和“大模型 agent”在项目里的定位
标题里带了“大数据、大模型 agent”,很多人以为要上 Hadoop 或者训练个 Transformer,实际上在毕设语境下,重点是“做出能力展示”。我在这套系统里把“大”拆成了两个务实的方向:
第一是数据规模。我抓了得物平台上多个热门品牌共一万两千多条鞋款记录,这个量级已经远超“演示数据”的水平,足够让 OLAP 聚合查询和推荐算法有实际意义。
第二是交互智能。我在项目里接了一个 agent 模块:用户可以用自然语言提问,比如“最近三个月价格涨幅最大的是哪三双鞋”,系统内部通过规则解析和大模型接口调用,把自然语言转换成对数据库的聚合查询,再把结果用自然语言返回。这个设计能在答辩现场直接演示,效果远好于干巴巴地讲“我调用了某平台 API”。
2. 数据采集与预处理:得物平台鞋类数据的完整链路
2.1 数据采集的技术方案与合规边界
爬虫环节的技术选型,我用的是 requests + BeautifulSoup + Selenium 的组合。原因是得物平台的商品列表页有部分数据是服务端渲染,直接 requests 能拿到;但详情页的实时价格和销量数据是异步加载的,需要 Selenium 模拟浏览器操作才能完整抓取。
抓取策略上,我按“品牌-系列-单品”三级结构来爬:先爬品牌列表页拿到系列链接,再进系列页拿到单品链接,最后进详情页抓价格、货号、发行日期、热度指数、收藏数、评论数这些字段。
这里必须提醒一句合规的事:爬虫只是用于学习和研究,我对请求频率做了限速,每个请求间隔随机 2~4 秒,并且严格遵守了网站的 robots 协议,也没有抓取任何用户个人信息。做数据类毕设的同学一定要在代码注释和论文里都写清楚这一点,这既是学术诚信,也是保护自己。
2.2 数据清洗的关键细节:价格、日期与去重
采集下来的原始数据惨不忍睹——这是所有做爬虫项目的人的第一反应。价格字段经常带着“¥”符号和“起”字,日期是“2024-03-15 发售”这种混合文本,热度指数有的是“1.2w”这种缩写,品牌名中英文混杂。我专门写了一个清洗模块,处理逻辑分成三层:
第一层是字段标准化。价格统一转成浮点数,
1.2w
转成
12000
,发售日期用正则提取出年月日,用 pandas 的
to_datetime
统一格式。
第二层是去重。同一个鞋款可能因为配色不同被识别成多条记录,我用“品牌+货号”作为唯一键去重,因为货号是鞋类商品的全球唯一标识,比用名称去重可靠得多。
第三层是异常值处理。价格特别低(低于 100 元)或特别高(高于 10 万元)的记录要单独检查,这些往往是测试商品或数据异常,直接剔除会明显提升后续分析的准确性。
2.3 数据库表结构与 Django ORM 落地
数据清洗完成后,我设计了四张核心表和一张中间表,全部通过 Django 的 models.py 定义。核心表分别是品牌表、鞋款表、价格记录表、用户行为表,中间表是用户收藏关系表。价格记录表单独拆出来是有讲究的——鞋类价格会随市场热度波动,保留历史价格才能画出走势图,这也是可视化模块的重要数据来源。
Django 模型定义好之后,我用一个管理命令(management command)把清洗好的 CSV 批量导入数据库。为什么不直接让爬虫写入数据库?因为爬虫是异步的、碎片化的,而批量导入可以在导入前做二次校验,出错回滚也方便。实际运行下来,一万多条数据导入 MySQL 耗时在 30 秒以内,这个性能对于毕设项目完全够用。
3. 数据可视化分析:从 ECharts 图表到业务洞察
3.1 可视化图表体系的设计思路
可视化的目的不是堆图表,而是回答几个关键业务问题:哪些品牌最受欢迎?价格分布呈什么形态?不同系列的溢价能力如何?热度高的鞋到底贵不贵?我围绕这几个问题设计了六类图表,每一类都对应一个明确的业务维度。
品牌分布用柱状图和饼图联动展示;价格区间分布用直方图,能直观看出主流球鞋的价位聚集带;热门商品排行用横向条形图,比竖向条形图更适合展示长文案的鞋名;品牌平均价格对比用箱线图,能同时看出中位数、四分位和异常值;价格与热度的关系用散点图,这是我最喜欢的一张图——能一眼看出价格和热度是正相关还是负相关,为推荐系统的冷热商品区分提供依据;最后是时间序列折线图,展示重点鞋款的价格波动趋势。
3.2 ECharts 与 Django 的数据对接方式
前端图表我选的是 ECharts,原因是它的图表类型丰富、交互流畅,而且对国产数据可视化项目非常友好。Django 后端通过 JsonResponse 返回 JSON 格式的聚合数据,前端用 Ajax 拉取并渲染。关键点是聚合查询要写在后端而不是前端:后端用 Django ORM 的
annotate
和
values
方法做 group by 聚合,返回给前端的是已经按品牌分组好的
[{name: 'Nike', value: 123}, …]
这种结构,前端直接塞进 ECharts 的 series 即可。
这里分享一个我踩过的坑:不要把原始数据全量传给前端再让 JS 去聚合。第一次实现时我图省事,把一万多条记录全部返回,结果页面渲染直接卡死,浏览器的控制台报了一堆内存错误。后来改成后端聚合,接口返回的数据量从几 MB 缩到几十 KB,页面加载时间从 8 秒降到 1 秒以内。
3.3 分析模块的“可解释性”设计
数据分析不只是画图,还要有结论。我在每个图表下方都加了一段自动生成的文字分析,比如当散点图的相关系数大于 0.5 时,系统自动生成“该品类价格与热度呈明显正相关,热门款式存在较高溢价空间”这样的结论。
这段文字不是写死的,而是基于指标规则动态生成的。我在后端写了一个分析引擎,跑完统计指标后用模板字符串拼装出结论句子。答辩的时候特别有用——老师一看你不仅会画图,还能从图里解读出业务含义,这个项目的完整度就直接上了一个档次。
4. 推荐系统核心实现:协同过滤算法的工程化细节
4.1 用户-物品矩阵的构建与稀疏性处理
协同过滤的第一步是把用户行为数据转成矩阵:行是用户,列是鞋款,值是用户对鞋款的评分。但真实场景下用户行为只有收藏、浏览、点击三种隐式反馈,没有显式评分,怎么办?
我用的是加权隐式反馈方案:收藏记 3 分,浏览详情记 2 分,列表页点击记 1 分。同一个用户对同一款鞋多次浏览只取最高分,避免刷数据。这样构建出来的矩阵大约 200 个用户乘以一万二千个商品,稀疏度在 95% 以上,这在实际工程里是正常的,因为大多数用户只对少数鞋款有反馈。
稀疏矩阵直接做相似度计算是灾难级别的算力浪费,所以我用 scipy 的稀疏矩阵格式存储,然后先做基于物品的协同过滤。为什么先做 ItemCF 而不是 UserCF?因为鞋款数量远小于用户数,物品相似度矩阵可以在离线阶段预先算好,在线推荐时只需要查表,响应时间能控制在 100 毫秒以内。
4.2 皮尔逊相关系数与 TopN 推荐的实现流程
物品相似度我用皮尔逊相关系数计算,公式是协方差除以标准差乘积。相比余弦相似度,皮尔逊系数会先对每个物品的评分做中心化处理,能消除不同物品被关注程度的固有差异——热门款天然被更多人收藏,如果不做中心化,它跟所有物品的相似度都会虚高。
具体的推荐流程分成三步。第一步,根据用户已收藏的鞋款列表,取这些鞋款各自的 Top 20 相似鞋款作为候选集;第二步,用加权公式计算候选鞋款的预测评分——用户对该鞋款的喜爱程度乘以相似度,求和后再除以相似度之和;第三步,排除用户已经收藏过的鞋款,按预测评分从高到低取 TopN 作为最终推荐结果。
整个算法我用纯 Python 写了一个 recommend.py 模块,输入用户 ID 输出推荐列表。为了让答辩时能暂停讲解,我在代码里加了关键步骤的日志打印,比如“用户 18 号: 已收藏 3 款鞋,生成候选集 87 款,最终推荐 10 款”,这样演示效果非常直观。
4.3 算法效果的评估与冷启动问题
推荐系统不能只“看起来推荐了”,你得证明它推荐得准。离线评估我用的是十折交叉验证法:把用户行为数据按用户维度随机分成 10 份,9 份做训练、1 份做测试,计算推荐结果的准确率和召回率。我的参数调优实验显示,取相似物品数 K=20 时,准确率约 18%、召回率约 22%,这个指标在隐式反馈场景下已经算合理水平。
但协同过滤有个天生缺陷——冷启动问题:新用户没有行为数据时,推荐列表必然是空的。我的解决方案是“热度填充 + 规则兜底”:对新用户推荐全站热度最高且价格在用户设定预算区间内的鞋款,并打上“热门精选”标签。这样即使算法没数据可用,页面依然有推荐内容,用户体验不会崩。
5. Django 平台整合:从算法模块到完整 Web 应用
5.1 项目目录结构与 MTV 分层实践
Django 项目的目录结构我做了清晰的分层:
apps/dataset
负责数据展示,
apps/recommend
负责推荐逻辑,
apps/analysis
负责数据分析,
apps/user
负责用户体系。每个 app 内部再用 view 层、service 层、model 层做二次拆分。
我强烈建议在 view 和 model 之间加一层 service(业务逻辑层)。很多新手把算法代码直接写进 view 里,接口一多就全乱套。我的做法是 view 只做参数解析和 HTTP 响应封装,具体的推荐计算、数据聚合都放在 service 层,这样每个函数都短小清晰,答辩时讲代码结构特别加分。
用户认证这块用的是 Django 自带的
auth
模块,加上
LoginRequiredMixin
控制推荐页面的访问权限。首页和数据分析页无需登录即可访问,推荐页必须登录——因为推荐系统需要基于用户行为数据,这样设计既合理又能展示你对权限控制的理解。
5.2 核心接口设计与前端页面联动
后端我主要提供了五个接口:数据总览接口(返回商品总数、品牌数、平均价格等汇总指标)、品牌分布接口、价格分布接口、用户推荐接口、自然语言查询接口。所有接口统一返回 JSON 格式,前端页面通过 Ajax 异步加载,页面切换无刷新。
前端的整体风格我走的是简洁大气的数据看板路线:左侧是侧边导航栏,右侧是内容区域,顶部是全局搜索框和数据更新时间。首页放核心 KPI 卡片,中间放主要图表,底部放热门推荐列表。整个页面用 Bootstrap 5 搭建框架,自定义 CSS 做微调,没有用复杂的前端框架——因为毕设项目的核心是前后端交互逻辑的完整性,不是前端工程化的炫技。
5.3 电商行业里推荐系统的真实工作方式
既然标题带了“电商系统推荐”,我顺便把实际电商平台的推荐工作方式写进了论文里,也在答辩时做了对比说明。真实的推荐系统一般是多路召回加排序:先通过协同过滤、热门榜、新品榜、同品牌等多路召回候选集,再用排序模型(比如 LR 或 DeepFM)对候选集打分排序。我的毕设做的是其中一路召回——协同过滤,但代码架构上预留了多路召回的扩展接口。
我定义了一个
Recaller
基类,协同过滤、热门推荐、价格区间推荐都继承自这个基类,未来要加新品召回只需要新增一个子类。这个设计在深度上远超“调包做推荐”,答辩时老师问“你的系统怎么扩展”,我直接打开代码演示抽象类和子类的关系,效果一目了然。
6. 常见问题排查与实操避坑实录
6.1 爬虫环节的高频报错与应对
爬虫阶段最容易遇到的问题是请求被拒绝。我用 requests 抓列表页时,第一版直接裸请求,返回的状态码全是 403。解决方案是添加完整的请求头(包括 User-Agent、Referer、Accept-Language),并模拟浏览器指纹。另外,得物平台的页面结构会定期调整,我抓了两次不同时间的页面,发现 HTML 结构调整导致 Beautif



