如果你准备拿“锦江酒店大数据分析与个性化推荐系统”这个题目做毕业设计,那这篇内容就是给你踩坑用的。标题里的关键词基本把整套技术栈都交代完了:Django 负责业务后端,Vue 负责前端页面,Hadoop 处理离线数据,爬虫拿外部数据,协同过滤出推荐结果,最后再用可视化图表把分析结论呈现在页面上。听起来是个标准的“全家桶”级课设,但真要动手,你会发现几乎每一个环节都藏着一堆坑,从环境搭到算法调参,每一步都能耗掉你一周。
这篇博文更像是一份项目复盘,我会从整体设计讲到具体实现,把我实际敲过的代码和踩过的坑全部展开,给毕业设计方向是这套技术栈的同学一个可以对照执行的参考。无论你是第一次接触 Django,还是对 Hadoop 半懂不懂,按这个思路往下走,至少能少走一半弯路。
1. 系统整体架构与设计思路
1.1 为什么选这套技术栈
毕业设计选技术栈跟点外卖是一个道理,不是越贵越好,而是要投导师所好、能稳定出餐。锦江酒店这个题目偏大数据方向,导师通常看重两件事:一是你有没有完整的数据处理链路,二是系统能不能真正跑起来。Django + Vue + Hadoop + 爬虫 + 协同过滤,恰好把这两个点全部覆盖了。
Django 的优势是自带 Admin 后台和 ORM,开发速度快,尤其适合做后台管理类和带用户体系的系统。Vue 的原因更直接,前端可视化和交互页面写起来比原生 JavaScript 清爽得多,配合 ECharts 做图表,效果很能撑场面。Hadoop 在这个项目里更多是“身份象征”,它的任务是证明你接触过分布式存储和离线计算,哪怕只是用 HDFS 存了几份日志、写了几个 MapReduce 统计,也能让答辩老师觉得项目有大数据底子。
爬虫则是数据来源的关键。酒店平台的公开数据不能直接拿来做算法验证,自己造数据又容易被问住,所以爬虫抓取公开的酒店评论、价格和地理位置是很常规的方案。协同过滤推荐算法则是系统的灵魂,用用户历史行为算相似度,给目标用户推荐可能感兴趣的酒店或客栈,这个逻辑在答辩时讲清楚,项目深度直接上一个台阶。
1.2 数据流向与模块划分
整个系统的数据会经过四个阶段:采集、存储、计算、应用。爬虫抓到的数据先落到原始层,经过清洗后进入 Hadoop HDFS,再通过 MapReduce 或 Hive 做离线统计,结果导出到 MySQL 中供 Django 查询。推荐算法读取用户行为数据,计算相似度矩阵,生成推荐结果写入数据库。前端 Vue 通过接口拉取分析结果和推荐列表,最终展示成可视化大屏和个性化推荐页面。
模块划分建议保持清晰,答辩时也好讲:
- 数据采集模块:爬虫抓取酒店、民宿、客栈的公开信息,包括标题、价格、评分、评论、地理位置等。
- 数据存储模块:HDFS 做原始数据备份,MySQL 做业务数据存储,Redis 可选,用于缓存热点数据。
- 数据计算模块:MapReduce/Hive 完成地区酒店数量统计、价格区间分布、评分趋势分析等离线任务。
- 推荐算法模块:基于协同过滤,分用户和物品两种维度做推荐。
- 可视化模块:Vue 页面通过 ECharts 展示统计图表,通过卡片列表展示推荐结果。
这样划分的好处是每个模块都能独立开发和测试,最后再通过接口串联,不用一上来就面对一堆互相依赖的代码,调试难度低很多。
2. 数据采集层:爬虫与数据预处理
2.1 爬虫目标与反爬策略
爬虫在这个项目里“吃相”要好看,建议优先抓取公开的、非核心的酒店信息,比如城市酒店列表、客栈简介、价格区间和评分。目标站点选择公开评论和基础信息已经有结构化入口的页面,解析起来成本低。用 requests + BeautifulSoup 做简单页面,遇到动态渲染的再用 Selenium 兜底,但 Selenium 太慢,尽量别用在大量页面上。
反爬是我实际踩得最多的坑。刚开始直接循环请求,发了几百个请求后 IP 就被限制,页面不返回数据只返回验证码。后来我加上 User-Agent 随机切换、请求间隔 sleep、重试机制三项,才基本稳定。如果是分布式爬虫实训,还可以用 Scrapy 的 downloader middleware 处理代理池,但毕业设计用单机加 sleep 就够,不需要把复杂度推上去。
爬下来的数据要及时落盘,我当时的做法是每条抓取结果先存成 JSON 行文件,文件名带时间戳,方便 Hadoop 那边直接读取。位置字段单独处理,解析出的经纬度尽量保留原名,因为后面要做地图展示和按城市筛选。
2.2 数据清洗与存储方案
原始数据脏是很正常的:价格字段可能是字符串“498元起”,评分可能带半角/全角空格,有些民宿的评论数干脆是空值。清洗这一步必须做扎实,否则后续统计全乱。我用 Pandas 做预处理,分三步走,先做字段标准化,把价格、评分、经纬度转成数值类型;再做缺失值处理,评论数为空的填 0,价格缺失的按同城平均价格补;最后做去重,同一酒店在多个源站出现时,按名称+城市+地址的哈希去重。
清洗后的数据我分了两份:一份 CSV 导回 MySQL 供 Django 直接用,另一份原样丢进 HDFS 的 /hotel_data 目录,用来写 MapReduce 离线任务。这个“双写”设计在答辩时很加分,因为你可以很自然地说明 MySQL 满足业务实时查询,HDFS 满足大规模历史数据分析和备份,两面都不耽误。
3. 大数据存储与计算:Hadoop 的落地姿势
3.1 Hadoop 伪分布式搭建与调试
我一开始就在本地 Windows 上强行装 Hadoop,结果折腾了两个月都没起得来,后来换成 Linux 虚拟机装伪分布式,一天就通了。伪分布式其实就是一台机器同时跑 NameNode、DataNode、ResourceManager、NodeManager,对毕设来说完全够用。核心配置围绕三个文件:core-site.xml里写 HDFS 的地址,hdfs-site.xml里把副本数改成 1,yarn-site.xml里配置调度器为容量调度。启动顺序固定是 start-dfs.sh 再 start-yarn.sh,打开 50070 端口能看到节点状态就算通了。
调试时的经验是,常出现Incompatible clusterIDs这类错误,多半是因为之前格式化过 NameNode 后没清空 dataDir。我建议每改一次配置文件,就把/tmp/hadoop-*下的数据目录删除,然后重新执行hdfs namenode -format,再重启一次。这个操作解决了我 90% 的启动问题,代价只是丢点测试数据,问题不大。
3.2 Hive 离线统计与 MapReduce 任务
做完基础统计后,我建议把 Hive 也装上去,它能让离线分析从写 Java 变成写 SQL,效率高一个量级。建外部表关联 HDFS 里清洗好的 CSV,字段类型按清洗后的结构定义。之后做“城市酒店数量统计”“各价位段酒店占比”“评分低于 4 分的客栈数量”这类查询,就是几条 HiveQL 的事。再把统计结果 sink 到 MySQL,Django 接口直接读 MySQL,前端图表就活了。
除了 Hive 查询,我还写了一个最简单的 MapReduce 程序,用来统计每个城市的民宿平均价格。Map 阶段按城市分组输出,Reduce 阶段用计数器求平均值。写这个程序不是为了取代 Hive,而是为了让答辩老师知道你真的理解 MapReduce 原理——Hive 是工具,MapReduce 是底层能力,两者在答辩中都会被问到。
4. 推荐算法:协同过滤从理论到实现
4.1 算法选型与相似度计算
协同过滤一般分两种,一种是基于用户的 UserCF,另一种是基于物品的 ItemCF。酒店推荐场景里用户行为数据往往很稀疏,UserCF 容易算出一堆“没有相似度”的用户,所以毕业设计我推荐 ItemCF 作为主算法:用户点了某个酒店,就去找和这个酒店“相似”的酒店推荐给他。
相似度计算我一开始用编辑距离,结果完全不对,后来换成余弦相似度,才符合直觉。物品之间的特征向量用价格、评分、城市、酒店类型这四个维度构建,数值型字段做归一化,类别字段做 one-hot。推荐时先取出用户最近点过或收藏过的酒店,按相似度加权排序,得分最高的前 N 个即为推荐结果。代码核心不到二十行,但效果取决于特征工程,特征选得好,推荐才有意义。
4.2 冷启动与混合推荐策略
冷启动是协同过滤绕不过去的问题,新用户没有历史行为,新酒店没有评分记录,相似度计算直接失效。我当时的处理是加了一个“热度推荐”兜底:没有行为数据的用户默认推荐城市热门酒店,有少量行为但不足 k 条时按 70% ItemCF + 30% 热度推荐,行为数据充足后再切回纯 ItemCF。这种混合策略代码简单,但答辩时能体现出你考虑到了实际业务问题。
我给系统的推荐接口设计了两个返回字段:recommend_reason和recommend_type,推荐原因写明“根据您浏览过的某酒店推荐”,推荐类型标明是协同过滤还是热度兜底。这样前端能展示推荐依据,后端也能通过日志观测推荐策略是否生效。这条经验是我在实际测试中慢慢加出来的,但效果很直观。
5. 后端服务与前端可视化:Django + Vue 联调
5.1 Django REST Framework 接口设计
后端我用的 Django + DRF(Django REST Framework)来实现 Restful API。项目结构按功能拆分成了users、hotels、stats、recommend四个 app。爬虫清洗好的 CSV 用 Django 的loaddata或者脚本批量导入 MySQL,然后建模型映射表。一个需要特别注意的点是 Django ORM 查询大数据量时的性能,比如聚合统计不要用 Python 层做循环,而要用 ORM 的aggregate或者直接写原生 SQL。
接口设计要贴近前端需求。推荐接口示例:
# recommend/views.py from rest_framework.views import APIView from rest_framework.response import Response from .services import hybrid_recommend class RecommendView(APIView): def get(self, request): uid = request.query_params.get('uid') hotels = hybrid_recommend(uid, top_n=6) return Response({'data': hotels})Django 的跨域问题用django-cors-headers一次搞定,Vue 开发服务器默认跑在 5173,Django 跑在 8000,不加这个中间件所有请求都会被浏览器拦截。这一条我在联调第一天就踩中,必须写进常用问题清单。
5.2 Vue 可视化大屏与 ECharts 渲染
前端我用 Vue 3 + ECharts 做了三个核心页面:数据看板、酒店地图和推荐页。数据看板用 ECharts 的柱状图展示城市酒店数量 Top10,饼图展示价格区间分布,折线图展示评分趋势。地图直接用 ECharts 的 map 类型,需要引入 GeoJSON 数据,我用的中国城市经纬度数据,加载后把点坐标按经纬度打上去即可。
页面路由用 vue-router 配了三条:/dashboard、/map、/recommend,请求统一封装在axios实例里,做一些 Loading 和错误提示处理。需要注意 ECharts 实例销毁时机,Vue 路由切换时如果没调用echarts.dispose(),内存会被一直占用,页面切几次后卡到怀疑人生。我是把图表初始化放在onMounted,在onBeforeUnmount里 dispose 掉,之后就没有卡顿过。
6. 常见问题与排查技巧实录
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| Hadoop 启动后 NameNode 起不来 | dataDir 目录冲突或格式化失败 | 清空临时数据目录重新格式化 |
| Django 接口能访问但前端报跨域错误 | 没装 django-cors-headers | 安装并配置 CORS 白名单 |
| ECharts 地图不显示 | GeoJSON 路径错误或地图类型未注册 | 检查注册和映射关系 |
| 爬虫爬到一半被限制 | IP 被反爬策略封禁 | 加随机 UA、sleep、重试 |
| 协同过滤推荐结果全为空 | 用户行为表太稀疏 | 走热度推荐兜底 |
| Vue 打包后资源路径 404 | base 路径配置问题 | 把base: '/'改成base: './' |
| Hive 无法写入 MySQL 数据 | 缺少 jar 包或表权限问题 | 检查 MySQL JDBC 驱动和授权 |
6.1 项目答辩前的最后自测清单
答辩前一天,我建议把下面的路径完整跑一遍:启动 Hadoop 和 Hive,从 HDFS 读取部分数据,统计出结果;启动 Django,调用统计接口,确认返回 JSON;启动 Vue,确认页面能显示图表和推荐列表;清空用户行为表,确认推荐接口自动切换热度推荐。这四步全过了,系统基本稳了。
另外,建议在项目里写一个README和启动脚本,把依赖列表、启动顺序、账号密码写清楚。老师不一定看代码,但一定可能现场让你跑一次,如果你连启动命令都要翻文档找十分钟,印象分就低了。
6.2 我在这个项目里学到的两件小事
第一件是不要在项目一开始就追求“完美架构”。我最初想用 Redis 做缓存、用 Kafka 传数据、用 Spark 算推荐,结果光环境搭建就耗了半个月,后面完全失控。后来砍掉所有非必要组件,只保留核心的 Django、Vue、Hadoop、爬虫、协同过滤这五样,项目反而顺利落地了。毕业设计追求的不是架构炫技,而是把核心流程跑通并讲清楚。
第二件是数据要尽早做“确定性验证”。我最初爬完数据就丢到 Hadoop 里,没检查内容,后来发现大量 NaN 和重复数据,导致推荐结果惨不忍睹。后来把清洗逻辑改成“先抽样 100 条人工看,再批量处理”,问题立刻少了很多。
7. 写在最后:个人经验与扩展建议
这套系统我从爬虫开始到最终答辩,前后写了差不多 40 天。作为一个过来人的体会是,真正值钱的不是代码量,而是你在做每一步时留下的调试记录和问题笔记。答辩时老师问得最多的也不是你写了多少页面,而是“你为什么用协同过滤”“Hadoop 在你的系统里到底承担了什么任务”,这些问题在我刚才分享的模块拆分中都能找到答案。
如果你时间充裕,后续还可以在现有系统上做两个很小的扩展:一个是用 Redis 缓存热点城市的统计结果,让页面秒开;另一个是把协同过滤的结果人工抽检几十条,在答辩时展示推荐质量的抽样评估。这两个点都不难,但能让项目在细节上超越绝大多数同题作品。
建议收藏这篇,每当你卡在某一个模块,就回来看一眼对应的章节。技术栈虽然多,但只要按“采集、存储、计算、应用”这条主线拆着做,每一步都不会白走。