/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
每年到这个节点,总有准备毕设或课程设计的同学来找我参谋,主题翻来覆去就那么几类,但今年“Python旅游推荐系统”出现的频率特别高。仔细想想也不意外:旅游是大家都有感知的场景,数据好解释,功能模块能撑得起“爬虫 + 算法 + 可视化”一条完整的链路,不管是毕业设计还是期末大作业,都容易做出亮点。我自己帮人跑通过好几个类似项目,最近整理了一套比较成熟的方案,从爬虫抓数据、协同过滤推荐,到最终的图表展示和万字报告组织方式,全部走了一遍。这篇就把整个过程和踩过的坑都写出来,给准备动手的同学一个可以直接参考的路线图。
先给个整体的定位:这不是一个只写算法就完事的项目,而是一个完整的小型应用系统。核心是协同过滤推荐算法,数据来源靠网络爬虫,结果呈现靠可视化图表。三者必须串起来,才能形成闭环——爬虫负责给系统“喂数据”,协同过滤负责把数据变成“推荐结果”,可视化则负责把结果呈现得清清楚楚。很多同学犯的错误是三个模块各做各的,最后拼起来发现根本跑不通,所以后文会重点讲模块之间的衔接。
1. 项目概述:旅游推荐系统到底在解决什么问题
1.1 这题怎么理解:推荐系统的产品逻辑
先把需求翻译成大白话:旅游推荐系统,就是让用户打开系统之后,不需要自己一条条翻景点列表,而是系统根据他过去的行为,自动推荐他可能感兴趣的景点。
这里的关键是要区分两个概念:一个是“热门景点展示”,比如把评论数最多的10个景点列出来,这不叫推荐,这叫排行榜;真正的推荐是“个性化”,比如用户A平时喜欢逛古镇、拍人文照片,系统就不应该给他推一大堆水上乐园。
理解了这一点,整个项目的主线就清晰了:用户有历史行为数据(浏览、收藏、评分、预订),系统基于这些行为刻画用户偏好,然后预测用户对未接触过的景点的兴趣程度,按兴趣程度排序返回Top-N推荐列表。
顺便说一句,很多同学在开题报告里写“基于Python的旅游推荐系统设计与实现”,但落实到代码才发现,连用户行为数据都没有,整个推荐引擎就是空转。所以项目的第一步不是写算法,而是先把数据管道打通。
1.2 技术选型为什么锁定Python全家桶
Python在这个项目里几乎是毫无争议的第一选择,原因很实在:
第一,爬虫生态成熟。requests发请求、BeautifulSoup解析HTML、Selenium处理动态加载,这些都是Python的看家本领,写起来比Java简洁太多。旅游平台的数据大多分布在列表页和详情页,解析逻辑不复杂,用Python处理非常顺手。
第二,数据处理和算法库齐全。pandas做数据清洗和矩阵运算、numpy做相似度计算,scikit-learn里还直接封装了多种距离度量函数,实在不想手写公式也可以调用现成的。对于要做演示和答辩的项目来说,效率很重要。
第三,可视化配合方便。Flask或者FastAPI做后端接口,前端用ECharts或者pyecharts渲染图表,数据通过JSON接口传给页面即可。整套链路都是Python能搞定的,调试起来不用跨语言。
我见过有人用Java写这个题目,代码量翻倍不说,爬虫和可视化部分还经常因为依赖库问题卡壳。除非你有明确的Java技术栈要求,否则没必要给自己加难度。
技术栈汇总一下:Python 3.9+,pandas、numpy、scikit-learn、requests、BeautifulSoup、Flask、pyecharts,数据库用SQLite或者MySQL都行。如果追求简单,SQLite就够用了,一个文件搞定存储,答辩演示的时候也不用担心数据库服务没启动。
2. 算法核心:协同过滤怎么落到旅游场景
2.1 基于用户的协同过滤:找口味相近的人
协同过滤的思想概括成一句话:让相似的人帮你做选择。它有两派,先看基于用户的(User-Based Collaborative Filtering)。
它的逻辑是:如果用户A和用户B在历史上对若干个景点的评分或行为高度一致,那么A喜欢的、B还没去过的景点,有很大概率也符合B的口味。生活中很好理解——你闺蜜和你口味差不多,她强烈推荐的地方,你闭眼去基本不会踩雷。
算法流程分三步:
举个具体的例子。假设我们有3个用户、4个景点,评分矩阵如下(0表示未评分):
| 小明 | 5 | 3 | 0 | 1 |
| 小华 | 4 | 0 | 4 | 0 |
| 小红 | 1 | 1 | 0 | 5 |
用余弦相似度算一下小明和小华的相似度:它们共同评分的景点只有一个景点X(5 vs 4),余弦相似度为 5×4 / (√(25+9+1) × √(16+16)) ≈ 20 / (√35 × √32) ≈ 0.60。而小明和小红的相似度算出来是负值。所以小华是“更相似的用户”。小华喜欢景点Z评了4分,小明没去过,系统就会把景点Z推荐给小明,推荐分数按相似度加权,大概是 4 × 0.60 = 2.4 分。
实际项目里当然不能只有3个用户,但原理完全一样。数据量越大,相似



