
简介这是基于Python与MySQL的智能旅游推荐系统毕业设计完整项目包适合计算机相关专业毕业生、Python Web开发学习者以及需要快速搭建旅游类管理系统的开发者。系统覆盖首页、个人中心、用户管理、旅游资讯、景点信息、酒店信息、行程分享、交流论坛等核心模块并配有系统分析与设计、数据库设计、详细设计说明帮助读者理解从需求梳理到编码实现的全过程。资源包共799个文件压缩包大小25.71MB主要由Python源码45个py、40个pyc、Vue前端页面53个vue、164个js、数据库SQL脚本2个sql以及设计文档docx、md构成另附运行脚本、配置文件和静态素材便于本地搭建与二次开发。已有231人学习下载。读者可从中获得可直接运行的旅游推荐网站原型、建表SQL、前后端模块划分与设计文档既支持毕业设计参考与答辩演示也能基于现有模块扩展智能推荐策略、优化后台管理或补充移动端。1. 智能旅游推荐系统源码包打开之前先搞清这三件事临到交毕设才发现手里的代码东缺一块西缺一块这种滋味我太熟了。这份智能旅游推荐系统源码包是一个基于 Python MySQL 的完整毕设项目后端用 Python 提供接口和数据服务前端由 Vue 组件拼出管理后台覆盖首页、个人中心、用户管理、旅游资讯、景点信息、酒店信息、行程分享、交流论坛、系统管理这一整套功能还带着安装脚本、运行脚本和说明文档。对打算做 Python Web 方向毕设、又不想从零搭框架的同学来说它可以直接当底座。下面我从目录结构拆到数据库设计和推荐逻辑再讲运行时真正会踩的坑按顺序走完基本能跑起来。2. 源码目录与 Python Vue 技术栈.bak 后缀和三段式结构怎么处理2.1 解开 zip 包之后第一步不是看代码是把 .bak 还原资源拿过来是一个 zip 压缩包。Windows 下我习惯右键“全部解压缩”这一步很简单但解压完你会看到一堆以 .bak 结尾的文件index.html.bak、update-password.vue.bak、IndexMain.vue.bak、IndexAsideStatic.vue.bak、BreadCrumbs.vue.bak、IndexHeader.vue.bak。初次接触这种命名的人十有八九会懵这些文件到底是源码还是没用的备份.bak 在这里的意思是备份副本本质就是源码文件本身。开发同学一边改程序一边留副本是很常见的习惯打包的时候没清理扩展名就一起塞进 zip 了。所以你要做的第一件事就是把这些 .bak 后缀去掉让 index.html.bak 回到 index.html让 update-password.vue.bak 回到 update-password.vue。文件名里真正的后缀是 .html 和 .vue别把整个名字换成别的。还原之后这套系统的轮廓就清楚了。它是一个典型的前后端分离结构index.html 是单页入口后台的壳由 IndexMain.vue、IndexAsideStatic.vue、IndexHeader.vue 和 BreadCrumbs.vue 四件套拼出来update-password.vue 是后台的修改密码页Python 后端负责接收前端请求、读写 MySQL、返回 JSON 数据。这种“Vue 做界面、Python 做数据服务”的组合是近几年毕设里非常主流的写法。文件角色注意事项index.html.bak单页入口去掉 .bak确认挂载点 idIndexMain.vue.bak主内容区菜单切换后核心内容在这里渲染IndexAsideStatic.vue.bak侧边栏菜单用户管理、景点管理等入口在这里定义IndexHeader.vue.bak顶部导航栏用户信息和退出按钮BreadCrumbs.vue.bak面包屑导航展示当前页面层级update-password.vue.bak修改密码页前端校验逻辑比较完整适合入门读2.2 Python 后端承担什么接口、数据库和业务流程这套系统里的 Python 不是写个脚本跑一遍就完事而是提供一个常驻的 Web 服务。毕设的常见做法是用 Flask 这类轻量框架搭应用路由层接收前端请求模型层通过 MySQL 驱动读写数据业务层处理登录、景点信息增删改查、酒店管理、行程分享提交、论坛回复这些操作。我一般会先看“安装.bat”里帮你装了什么依赖。这个批处理文件的典型作用是调用 pip install 把项目依赖全部装好。如果压缩包里没有 requirements.txt那你至少需要装 pymysql连接 MySQL 用和 FlaskWeb 框架这两个是起步最基本的别的一边跑一边补。写接口时路径通常会按模块划分比如 /api/user/login、/api/news/list、/api/scenic/list。前端页面通过这些路径向后端要数据后端再拼接 SQL 去查表。第 3 章我会拿推荐接口出来拆那是最能体现“智能”两个字的地方。2.3 动手之前先配置 Python 环境VS Code 解释器选对再装包说 IDE 的事。用 VS Code 打开这个项目时推荐先把 Python 解释器指到项目环境里。按 CtrlShiftP 打开命令面板输 Python: Select Interpreter选你准备装依赖的那个 Python。这一步不做后面会出现“pip 明明装了 pymysql运行却报 ModuleNotFoundError”的怪事原因就是解释器选错了。然后批量还原 .bak 文件。Windows 下的 PowerShell 可以这样写Get-ChildItem -Path . -Filter *.bak | Rename-Item -NewName { $_.Name -replace \.bak$, }这段命令的逻辑是把当前目录下所有以 .bak 结尾的文件找出来逐个去掉后缀。两个细节要注意-Filter *.bak 只匹配文件不会动到文件夹-replace 里的 .bak$ 是正则写法那个反斜杠是把点号转义成普通字符$ 表示匹配到字符串结尾这样只会去掉末尾的 .bak不会误伤文件名中间的 bak 字样。如果你在 Mac 或 Linux 上操作等价写法是 for f in *.bak; do mv $f ${f%.bak}; done。还原之后对照目录检查一遍前端页面文件和后端 Python 文件应该在同一个项目根下说明文档是一个独立的压缩包里面有摘要、系统分析与设计、数据库设计和详细设计几个部分。如果页面文件嵌在子目录里注意看后端代码里引用模板或静态文件的相对路径别让路径对不上。3. 数据库与推荐算法实现从建表 SQL 到推荐接口返回 JSON3.1 核心表结构用户、景点、酒店、行程和论坛智能推荐依赖的数据来自一张张普通的关系表。按照说明文档里数据库设计章节的描述MySQL 里至少要建 7 张表才能撑起摘要里列的功能。我把功能清单和表对应起来理一理用户表管前台用户和后台管理员旅游资讯表存资讯文章景点信息表和景点分类表是推荐的主体数据酒店信息表给住宿推荐提供数据行程分享表存用户发布的行程交流论坛相关的帖子表存标题、内容和回复关联。建表时字符集必须统一否则后面中文全变问号。我一般先建库再建表SQL 写成这样CREATE DATABASE IF NOT EXISTS travel_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE travel_db; CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, nickname VARCHAR(50) DEFAULT , avatar VARCHAR(255) DEFAULT , create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE t_scenic ( id INT PRIMARY KEY AUTO_INCREMENT, scenic_name VARCHAR(100) NOT NULL, category_id INT NOT NULL, address VARCHAR(255) DEFAULT , price DECIMAL(10,2) DEFAULT 0, click_count INT DEFAULT 0, img_url VARCHAR(255) DEFAULT , content TEXT ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这两条 SQL 执行后travel_db 库里就有了用户表和景点表。字段类型上id 用自增主键username 加 UNIQUE 防重复注册价格用 DECIMAL(10,2) 而不是 FLOAT免得算钱丢精度正文类字段用 TEXT。如果你是从说明文档里抄建表语句重点检查三处表名和后端 SQL 引用是否一致、字段名是不是统一的下划线风格、外键字段类型和主表主键是否一致。这三类问题在答辩前最容易爆雷而且错得悄无声息。表用途关键字段t_user用户与管理员username, password, nicknamet_scenic景点信息scenic_name, category_id, click_countt_hotel酒店信息hotel_name, price, addresst_travel_note行程分享user_id, title, contentt_forum_post论坛帖子user_id, title, reply_countt_news旅游资讯title, content, publish_time3.2 推荐算法先按分类过滤再按热度排序很多同学看到“智能旅游推荐”六个字以为里面藏了什么深度神经网络。其实毕设阶段的推荐基本是两板斧先按照用户选择的分类或历史行为过滤数据再按点击量、时间、评分这些可量化指标排序。这套系统的实现思路也在这个范围内推荐接口做的事大致是用户访问首页时后端读一个分类参数从景点表里筛出对应分类的数据按点击量倒序取前 N 条返回用户没指定分类就把全表按点击量和新旧程度加权排序。我用 Python 写核心排序逻辑常见做法是在路由函数里拼 SQL 再取结果集def recommend_scenic(category_idNone, limit6): conn get_connection() cursor conn.cursor() if category_id: sql SELECT id, scenic_name, price, click_count, category_id FROM t_scenic WHERE category_id %s ORDER BY click_count DESC LIMIT %s cursor.execute(sql, (category_id, limit)) else: sql SELECT id, scenic_name, price, click_count, category_id FROM t_scenic ORDER BY (click_count * 0.7 (UNIX_TIMESTAMP(create_time) / 100000) * 0.3) DESC LIMIT %s cursor.execute(sql, (limit,)) rows cursor.fetchall() cursor.close() conn.close() return [dict(zip([col[0] for col in cursor.description], row)) for row in rows]这段代码的逻辑分两路。带了 category_id 时走精确分类ORDER BY click_count 就是按热度排序LIMIT %s 控制返回条数没带分类时走综合排序点击量占 0.7 权重创建时间的 Unix 时间戳除以 10 万再乘 0.3时间越新权重越高。两个细节说明一下cursor.description 用来取列名先把每行转成字典方便前端直接用字段名取值所有参数都用 %s 占位传值不要用字符串拼接否则 SQL 注入直接送走答辩。如果想引入价格或评分因素把字段加进 ORDER BY 表达式调权重就行。3.3 接口封装与返回格式前端要的是一份约定好的 JSON后端写完推荐查询逻辑还要把它暴露成一个 HTTP 接口。Flask 里写一个路由接收参数调用查询函数返回 JSONfrom flask import Flask, request, jsonify app Flask(__name__) app.route(/api/scenic/recommend, methods[GET]) def scenic_recommend(): category_id request.args.get(category_id, typeint) limit request.args.get(limit, default6, typeint) data recommend_scenic(category_idcategory_id, limitlimit) return jsonify({ code: 0, msg: success, data: data }) if __name__ __main__: app.run(host0.0.0.0, port5000, debugTrue)这个接口接收两个 GET 参数category_id 是景点分类 ID可选limit 是返回条数默认 6。返回结构统一成 code、msg、data 三层code 为 0 表示成功data 里放景点列表。前端拿到后直接遍历渲染错误分支根据 code 判断。request.args 从 URL 查询串取参数typeint 做类型强转传了非数字时 Flask 会直接返回 400 错误这在联调阶段比后端报 500 好定位得多。host 用 0.0.0.0 而不是 127.0.0.1是为了让同一局域网的手机也能访问这个接口演示时不用一直对着电脑。4. 前端 Vue 组件与联调管理后台页面怎么改成自己的项目4.1 index.html 入口与后台布局是怎么拼出来的前端这一层源码包给的是 Vue 风格的单页应用结构。index.html.bak 是入口页里面一般会有一个挂载点然后通过 script 标签引入 Vue 和组件文件由组件控制整个后台界面的渲染。很多毕设为了省事不会用 webpack 打包而是直接引入 vue.min.js 再声明组件这对你反而是好事——不用学 Node 打包工具也能改。IndexMain.vue 管主内容区就是后台中间那块会随菜单切换变化的区域。IndexAsideStatic.vue 是左侧静态菜单栏系统里的“用户管理、旅游资讯管理、景点信息管理、景点分类管理、酒店信息管理、行程分享管理、交流论坛、系统管理”这些入口基本都在这个组件里定义。IndexHeader.vue 是顶部导航栏放标题、用户信息和退出按钮。BreadCrumbs.vue 是面包屑导航告诉你当前在哪个页面层级。把这四个组件的模板读一遍后台的骨架就清楚了。4.2 改密页面 update-password.vue一个完整的表单交互样本源码包里 update-password.vue.bak 是修改密码页它在所有后台页面里最建议先读功能独立、逻辑短适合做前后端交互的切入口。这个页面的核心交互是三步用户输入旧密码、新密码、确认新密码前端校验两次新密码一致后调用后端接口后端校验旧密码正确后更新数据库。我把毕设里常见的提交逻辑抽出来核心部分长这样// update-password.vue 中的提交逻辑 methods: { submitForm() { if (this.form.newPassword ! this.form.confirmPassword) { alert(两次输入的新密码不一致); return; } axios.post(/api/user/updatePassword, { userId: this.userId, oldPassword: this.form.oldPassword, newPassword: this.form.newPassword }).then(res { if (res.data.code 0) { this.$message.success(密码修改成功); } else { this.$message.error(res.data.msg); } }); } }这段代码做了两层校验前端先拦截两次密码不一致的情况避免无效请求打到后端后端返回的 code 再决定页面提示成功还是失败。实际项目里务必在后端加一层 userId 与登录 session 的匹配校验防止越权改别人密码。参数方面newPassword 传到后端后要加密再入库明文存储是答辩评委最爱挑的毛病。4.3 前后端联调把请求地址统一收口到一个变量里页面里如果每个请求都把 IP 和端口写死在 axios 调用处换一台电脑演示就要全局替换。我习惯在前端建一个 base.js或者直接在 index.html 里定义一个全局常量把接口地址收口// 全局接口地址配置 const BASE_URL http://127.0.0.1:5000; // 统一封装 get 请求 function request(url, params) { return axios.get(BASE_URL url, { params }) .then(res res.data) .catch(err { console.error(接口请求失败, url, err); }); }后面所有页面都用 request(/api/scenic/recommend, { category_id: 2 }) 这种形式调用。换后端端口时只改 BASE_URL 一处全局生效。这里踩过一个坑浏览器直接访问 Flask 接口没问题但 Vue 页面从另一个端口发起请求时会触发跨域需要在 Flask 侧配 CORS。常见做法是安装 flask-cors 然后在应用上调用一次 CORS(app)否则请求会被浏览器拦下来控制台报的错误和接口本身没关系容易误判到后端代码上。5. 运行与部署排查依赖安装、中文乱码、端口冲突五个常见坑先说结论这份源码包跑不起来的案例里绝大多数栽在 .bak 没还原和数据库连不上这两步。下面按排查顺序写每一条都是现象、原因、解决三步走。5.1 pip 装包超时中断装到一半报错退出现象执行安装.bat 或者手动 pip install flask pymysql 时下载进度条走一会儿就卡住最后报 timeout 或者 connection error。原因默认的 PyPI 源在国外国内网络环境下访问速度慢、时常断连尤其是教学网里装几十 MB 的包超时是常态。解决换成清华或者阿里镜像源。命令写法是 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple 。如果项目里没有 requirements.txt就手工一条条装pip install flask pymysql -i https://pypi.tuna.tsinghua.edu.cn/simple 。装完用 pip list 看一眼版本Flask 用 2.x 和 3.x 的差异在 Python 版本上如果代码里用了 Flask-Migrate 这类扩展注意版本要匹配不然 import 阶段就报错。5.2 写入数据库的中文变成问号现象通过页面新增一个景点名称里带中文存进 MySQL 后查出来是一串 ??。原因建库时字符集没指定 utf8mb4MySQL 沿用了默认的旧字符集中文存不进去。解决把库和表的字符集一次改到位ALTER DATABASE travel_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE t_scenic CONVERT TO CHARACTER SET utf8mb4;第一条改库默认字符集第二条把已有表的字段字符集转换掉。注意已经存成乱码的数据转换后不会自动恢复把脏数据删掉重新导入。所以建表之前就要确认字符集这是最省事的路径。5.3 运行.bat 启动后终端直接闪退报 address already in use现象双击运行.bat终端窗口刚弹出来就报错关闭细看提示里有一句端口占用。原因5000 端口被其他程序占了。最常见的是上一次后端进程没关干净或者系统里别的服务恰好用了 5000。解决Windows 下执行 netstat -ano | findstr :5000找到处于 LISTENING 状态的 PID然后 taskkill /PID 那个数字 /F。如果这个端口被系统服务占用不好强杀就把后端代码里 app.run 的 port 改成 5001同时把前端 BASE_URL 里的端口一并改掉。改端口一定要改两处只改后端不改前端页面照样连不上。5.4 打开 index.html 白屏控制台报组件找不到现象浏览器打开 index.html页面一片空白F12 控制台报 Failed to load resource提示找不到 IndexMain.vue 或者其它组件文件。原因.bak 文件没有还原浏览器加载入口页时找不到真正要执行的组件文件。这个坑最容易卡人因为报错信息直指文件缺失很多人会误以为压缩包本身是坏的。解决回到第 2.3 节在项目根目录执行那段 PowerShell 批量重命名命令把 .bak 全部还原。还原完刷新浏览器组件就能正常加载了。判断依据很简单看项目目录里有没有干净的 index.html 和 update-password.vue有说明还原成功。5.5 明明装了 pymysql运行还是报 ModuleNotFoundError现象pip list 显示 pymysql 已经在列表里可程序一运行还是提示找不到模块。原因VS Code 当前选中的 Python 解释器不是装 pymysql 的那个环境。这种情况在电脑里装了多个 Python 版本时特别常见终端里用的 Python 和编辑器里用的不是同一个。解决CtrlShiftP 打开命令面板输 Python: Select Interpreter选 pip 装包时对应的那个 Python。如果项目目录下有 venv 文件夹就选 .\venv\Scripts\python.exe 这个路径。选完重启终端再跑一次症状大概率消失。这块在 python 入门阶段最容易浑属于环境配置里典型的黑匣子花时间搞清楚一次后面省很多事。6. 把推荐逻辑改成自己的参数权重调整、数据替换和答辩前自测三件事拿到这份源码最忌讳的就是只改标题就交。我的习惯是先从推荐逻辑动手把第 3 章那个排序权重调成自己的参数。可以把权重单独抽成一个配置块# recommend_config.py RANK_WEIGHT { click: 0.5, # 热度权重 time: 0.2, # 时间权重 price_score: 0.3 # 价格友好分 }排序前先算每个景点的综合分再以综合分倒序取前 N 条。这样答辩时问你“为什么推荐这个景点”你能清楚说出点击量、时间、价格三个因素的加权结果比一句“按点击量排的”听起来扎实得多。数据替换也简单把 t_scenic 表里的景点数据清空导入你自己城市或目标地区的真实景点图片链接放网上素材地址前端展示就完全是另一个项目的样子。第二件事是自测。启动后我一般按顺序走一遍完整链路用测试账号登录、进后台改密码、新增一个景点、把它顶到首页推荐位、去前台看展示、发一条行程分享、在交流论坛回一个帖子。任何一步报错都记下来改完再跑一遍。这套流程走完功能层面基本不会在演示时突然翻车。我还习惯把数据库导出成一份 SQL 备份放在项目外的目录万一现场误操作把数据清了还能快速还原。从那以后我每次接手这种源码包都会强制先走“还原 .bak、配解释器、改库字符集、启动自测”这四步再开始动业务代码顺序不变翻车概率小很多。希望帮到你。本文还有配套的精品资源点击获取