Python餐厅推荐系统源码解析:从爬虫到Flask可视化全流程

发布时间:2026/9/23 15:09:15

Python餐厅推荐系统源码解析:从爬虫到Flask可视化全流程 简介这份资源是面向Python初学者与推荐系统入门者的餐厅菜品推荐系统完整项目包以Python为核心技术栈解决从数据采集到个性化推荐落地的全流程实践问题。压缩包共97个文件约5.76MB包含7个py脚本、6个html页面、18个js与16个css前端资源以及xlsx城市数据表、png/jpg界面截图和requirements.txt依赖清单覆盖爬虫、Web服务与前端展示各环节。项目结构清晰spider-main目录负责抓取大众点评、美团等平台数据main模块实现城市与区域检索templates下提供搜索、排行、词云等页面便于理解推荐系统的数据获取、预处理、特征工程与模型构建思路。目前已有139人学习下载适合希望掌握Python数据分析、协同过滤与Flask/Django部署的读者参考可据此快速搭建可运行的推荐服务原型并拓展为课程设计或毕业项目。1. 从一份能跑起来的餐厅推荐系统源码说起很多做 Python 入门项目的人卡在同一个地方爬虫、清洗、建模、Web 展示各写各的拼不成一条能演示的链路。这份「基于 Python 的餐厅菜品推荐系统」把整条链路塞进了一个 zipspider-main负责从大众点评、美团抓城市和门店数据main目录里放着搜索与区域校验脚本app.py用 Flask 把推荐结果渲染到templates下的页面static/assets和img里是 ECharts 图表和界面截图。它解决的不是「推荐算法有多先进」而是「一个能讲清楚数据从哪来、怎么进模型、怎么在网页上看到」的完整闭环。适合正在找 Python 课程设计、毕业设计参考或者想跑通爬虫到可视化全流程的人。下面按我实际拆包的顺序讲重点放在怎么复现、参数怎么调、哪里容易翻车。2. 拆开 spider-main城市列表、门店搜索与区域校验怎么串2.1 三个脚本的分工与调用顺序spider-main里不是一个大爬虫而是拆成了city_search.py、store_search.py、store_search_dianping.py、area_check.py四个脚本配合dianping_cities.xlsx和meituan_cities.xlsx两个城市清单。这个设计的好处是城市列表可以离线维护门店搜索按平台分开区域校验单独跑不会因为某个平台改版把整条链路拖死。常见做法是先用city_search.py把两个 Excel 里的城市名转成平台可识别的城市 ID 或拼音再交给store_search.py和store_search_dianping.py去搜门店最后用area_check.py校验抓到的门店地址是否落在目标区域内。我一般会按这个顺序跑# 1. 先确认城市清单能读进来 python spider-main/city_search.py # 2. 跑美团门店搜索示例具体参数看脚本里的 argparse python spider-main/store_search.py --city-file spider-main/meituan_cities.xlsx --output data/meituan_stores.csv # 3. 跑大众点评门店搜索 python spider-main/store_search_dianping.py --city-file spider-main/dianping_cities.xlsx --output data/dianping_stores.csv # 4. 区域校验过滤掉不在目标商圈的门店 python spider-main/area_check.py --input data/meituan_stores.csv --area 朝阳区逻辑说明city_search.py通常只做城市名到平台参数的映射不发起大量请求所以先跑它成本最低。store_search.py和store_search_dianping.py是真正发请求的输出 CSV 方便后续用 pandas 处理。area_check.py放在最后是因为它依赖前面产出的地址字段如果地址本身没抓全校验结果会大量误杀。参数说明--city-file指向城市清单换城市就改这个文件--output决定中间结果落盘位置建议单独建data/目录不要和源码混在一起--area是区域过滤关键词不同平台地址格式不一样大众点评常带「商圈」后缀美团可能只到区所以这个参数要按平台微调。2.2 城市清单 Excel 的字段与维护方式dianping_cities.xlsx和meituan_cities.xlsx是整个爬虫的入口配置。它们通常至少包含城市名、城市拼音或 ID、所属省份这几列。很多人拿到源码直接跑报「城市不存在」八成是 Excel 里的城市名和脚本里拼 URL 用的字段对不上。我一般会先读一遍表头import pandas as pd for f in [spider-main/dianping_cities.xlsx, spider-main/meituan_cities.xlsx]: df pd.read_excel(f) print(f, df.columns.tolist(), df.shape) print(df.head(3))逻辑说明先看列名和前三行确认脚本里引用的列比如city_name、city_id确实存在。如果列名是中文而脚本里写的是英文要么改脚本要么在读取时重命名。参数说明pd.read_excel默认读第一个 sheet如果城市分多个 sheet要加sheet_name参数。提示城市清单不要频繁改改完先跑city_search.py验证再跑门店搜索。直接改 Excel 后跑全量出错很难定位是配置问题还是网络问题。2.3 请求频率与输出字段的控制门店搜索脚本里通常会有time.sleep或请求间隔参数。这个参数不是摆设调太小会被平台限流调太大跑一个城市要很久。我的经验是先拿一个城市、一个关键词试跑看返回条数和耗时再决定全量跑多久。# 伪代码展示常见控制点 import time import requests def search_store(city_id, keyword, page): url fhttps://example.com/search?city{city_id}kw{keyword}page{page} headers {User-Agent: Mozilla/5.0 ...} resp requests.get(url, headersheaders, timeout10) time.sleep(1.5) # 请求间隔按平台容忍度调整 return resp.json()逻辑说明timeout防止单次请求卡死time.sleep控制频率。参数说明间隔从 1 秒到 3 秒都有人用但更稳的做法是随机化比如time.sleep(1 random.random())避免固定节奏被识别。输出字段方面门店搜索至少要有门店名、地址、评分、评论数、人均价格后面推荐和可视化都依赖这些列。3. 从原始门店数据到推荐结果清洗、特征与 Flask 接口3.1 用 pandas 做缺失值、异常值和字段标准化爬下来的门店数据常见问题是评分是「暂无评分」、人均价格带「¥」符号、地址里混着换行和空格。直接丢给模型会报类型错误。我一般先做一轮清洗import pandas as pd import numpy as np df pd.read_csv(data/meituan_stores.csv) # 评分转数值非数值置为 NaN df[rating] pd.to_numeric(df[rating], errorscoerce) # 人均价格去掉货币符号和「元」 df[avg_price] df[avg_price].astype(str).str.replace(r[¥元], , regexTrue) df[avg_price] pd.to_numeric(df[avg_price], errorscoerce) # 缺失值处理评分缺失用中位数补价格缺失用同类均值补 df[rating] df[rating].fillna(df[rating].median()) df[avg_price] df[avg_price].fillna(df.groupby(category)[avg_price].transform(mean)) # 地址去空白 df[address] df[address].astype(str).str.strip().str.replace(r\s, , regexTrue) df.to_csv(data/stores_clean.csv, indexFalse)逻辑说明errorscoerce把无法转换的值变成 NaN避免整列报错。价格用正则去掉符号后再转数值。缺失值按业务补评分用中位数价格按品类均值比全局均值合理。参数说明groupby(category)里的category要确认清洗后还存在如果品类字段也是脏的先做品类标准化再补价格。3.2 特征选择评分、价格、品类和评论数怎么用推荐系统不一定非得上协同过滤。这份源码的场景是餐厅菜品推荐用户量未必大常见做法是用基于内容的推荐把门店或菜品的品类、价格区间、评分、评论数做成特征算相似度后排序。from sklearn.preprocessing import MinMaxScaler from sklearn.metrics.pairwise import cosine_similarity features df[[rating, avg_price, review_count]].copy() features[review_count] np.log1p(features[review_count]) # 评论数长尾取对数 scaler MinMaxScaler() features_scaled scaler.fit_transform(features) sim_matrix cosine_similarity(features_scaled)逻辑说明MinMaxScaler把不同量纲的特征压到 0 到 1避免价格数值大就主导相似度。评论数取log1p是因为少数门店评论数极高不处理会拉偏。参数说明如果品类是类别型要先做 one-hot 再拼进特征矩阵cosine_similarity输出的是门店两两相似度取 Top-N 就是推荐候选。注意不要直接把门店 ID 当特征也不要用未来数据比如推荐之后才产生的评论训练否则离线指标好看上线就翻车。3.3 app.py 里的路由与模板渲染app.py是 Flask 入口templates下有index.html、search.html、rank.html、region.html、word.html、team.html。从文件名看首页、搜索、排行、区域、词云、团队页都有。推荐结果通常通过/search或/recommend路由返回模板里用 Jinja2 渲染。from flask import Flask, render_template, request import pandas as pd app Flask(__name__) df pd.read_csv(data/stores_clean.csv) app.route(/search) def search(): keyword request.args.get(kw, ) if keyword: result df[df[name].str.contains(keyword, naFalse)].head(20) else: result df.head(20) return render_template(search.html, storesresult.to_dict(records)) if __name__ __main__: app.run(debugTrue)逻辑说明request.args.get拿查询参数str.contains做简单匹配to_dict(records)把 DataFrame 转成模板能遍历的列表。参数说明debugTrue只适合本地调试部署要关掉head(20)限制返回条数避免页面卡顿。如果推荐逻辑在单独模块里这里应该调用推荐函数而不是直接过滤。3.4 ECharts 图表与静态资源路径static/assets和main/echarts.py说明可视化是用 ECharts 做的。常见做法是后端把数据转成 JSON前端在rank.html或region.html里初始化图表。// 在模板里注入数据后初始化 var chart echarts.init(document.getElementById(rankChart)); chart.setOption({ xAxis: { type: category, data: {{ names | tojson }} }, yAxis: { type: value }, series: [{ type: bar, data: {{ scores | tojson }} }] });逻辑说明tojson是 Jinja2 过滤器把 Python 列表安全转成 JS 数组。参数说明names和scores要长度一致否则图表错位。静态资源路径在 Flask 里默认是/static/如果页面图表空白先看浏览器控制台是不是 404。4. 环境配置与依赖安装requirements.txt 之外还要注意什么4.1 用虚拟环境隔离依赖requirements.txt里通常有 Flask、pandas、numpy、scikit-learn、requests、beautifulsoup4、openpyxl、lxml 这些。直接全局装容易和系统里的包冲突我一般先建虚拟环境python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate pip install -r requirements.txt逻辑说明虚拟环境把项目依赖和系统 Python 隔开删掉 venv 目录就能清理。参数说明如果requirements.txt没锁版本装完最好pip freeze requirements-lock.txt下次复现更稳。4.2 常见依赖版本冲突与处理pandas 和 numpy 版本不匹配、scikit-learn 太新导致旧 API 报错是这类项目最常见的环境问题。如果pip install后跑app.py报ImportError或AttributeError先看报错里提到的包和版本。pip show pandas numpy scikit-learn逻辑说明确认实际安装版本。参数说明如果源码里用了sklearn.cross_validation这种旧路径新版本已经移除要改成sklearn.model_selection。不要盲目降级所有包先定位是哪个 API 变了。提示openpyxl是读 Excel 城市清单用的如果没装pd.read_excel会报缺少引擎。lxml是 BeautifulSoup 的解析器不装会退回内置解析器速度慢且容错差。4.3 启动 Flask 与端口调整python app.py # 或指定端口 flask --app app run --port 5001逻辑说明app.py里如果写了app.run()直接跑就行。参数说明5000 端口在 macOS 上可能被系统服务占用换 5001 或 8080。如果页面能打开但静态资源 404检查templates里引用路径是不是/static/assets/...以及static目录是否在项目根下。5. 避坑与排查爬虫、编码、模板和模型加载的翻车记录5.1 爬虫返回空数据或直接 403现象store_search.py跑完输出 CSV 是空的或者请求返回 403。原因平台对请求头、频率、IP 有校验默认 User-Agent 或固定间隔容易被拦。解决补全User-Agent、Referer请求间隔随机化先小批量试跑确认能拿到数据再放大。5.2 Excel 城市清单读取报编码或引擎错误现象pd.read_excel报FileNotFoundError或ImportError: Missing optional dependency openpyxl。原因路径不对或者没装 openpyxl。解决用绝对路径或确认工作目录pip install openpyxl。如果 Excel 是.xls老格式还要装xlrd。5.3 模板渲染中文乱码现象页面显示房间这类乱码。原因文件编码不是 UTF-8或者 Flask 响应头没指定。解决确保templates下 HTML 和app.py都是 UTF-8HTML 里加meta charsetUTF-8Python 文件头加# -*- coding: utf-8 -*-。5.4 推荐结果每次刷新都一样现象搜索或推荐页面返回的列表固定不变。原因推荐逻辑写成了静态排序没有引入用户输入或随机性。解决检查app.py里是否真的调用了相似度计算还是直接df.head(20)。如果是演示至少按评分或评论数排序并允许通过参数切换。5.5 模型文件或数据路径写死现象换台机器跑就报FileNotFoundError。原因源码里用了绝对路径比如C:\Users\xxx\data\stores.csv。解决改成相对路径或者用os.path.dirname(__file__)拼路径。我一般会在项目根建data/所有中间文件都放里面脚本里统一用相对路径。6. 进阶把推荐结果做成可解释的排序与验证跑通之后真正让这个项目拿得出手的是推荐结果能解释、能验证。我一般会加一个简单的排序打分函数把相似度、评分、评论数加权而不是只按单一指标排。def rank_stores(df, sim_scores, w_sim0.5, w_rating0.3, w_review0.2): df df.copy() df[sim] sim_scores df[review_log] np.log1p(df[review_count]) df[score] ( w_sim * df[sim] w_rating * (df[rating] / 5.0) w_review * (df[review_log] / df[review_log].max()) ) return df.sort_values(score, ascendingFalse)逻辑说明w_sim、w_rating、w_review三个权重控制推荐偏向。相似度高但评分低的店不会排太前评论数取对数避免一家独大。参数说明权重之和建议为 1方便解释如果业务更看重评分把w_rating调到 0.5 以上。验证时可以用留一法拿掉用户历史里的一家店看推荐列表里是否出现同类店。验证方式看什么指标适用场景留一法命中率用户历史较少评分排序对比平均评分提升冷启动人工抽查品类相关性演示前快速检查注意离线指标好不代表线上好尤其是爬来的数据本身有偏差。我一般会在rank.html里同时展示推荐理由比如「相似度 0.82 / 评分 4.6」方便演示时讲清楚。从那以后我每次拿到这类源码包都强制先跑通一条最小链路一个城市、一个关键词、一个页面确认数据能落盘、模板能渲染、图表能出来再扩全量。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/9/23 15:09:15

3个高频坑点搞定狂暴飞车下载,面试必问不再挂

3个高频坑点搞定狂暴飞车下载,面试必问不再挂 看了一堆教程还是不会写项目?别慌,这其实是90%新手的通病。 很多兄弟在准备 面试必问 的编程题时,卡在“狂暴飞车下载”这个看似简单实则暗藏玄机的场景里。…

2026/9/23 15:09:15

JSP+Servlet+MySQL宠物管理系统:JavaWeb课设完整实现与避坑指南

简介:这是一个基于JSPServletMySQL搭建的宠物管理系统源码包,面向初学Java Web的开发者,以简单直观的宠物分类查询、添加、编辑与删除功能,完整呈现增删改查模块的落地方式。系统原先缺少编辑与删除能力,后续补充升级&…

2026/9/23 15:54:25

三万英尺等于多少米?开发者的单位换算速查手册

三万英尺等于多少米?开发者的单位换算速查手册 看了一堆教程还是不会写项目?别慌,很多时候卡住你的不是高深的架构,而是那些看似基础却极易出错的细节。今天咱们不聊虚的,直接拆解一个在面试和实际业务中经常“阴人”的小知识点: 三万英尺等于多少米…

2026/9/23 15:54:25

DeepSeek+微表情分析:房地产精准获客与话术生成实战

简介:一份关于DeepSeek在房地产精准获客场景的技术方案文档,面向营销策划、NLP算法工程师及方案设计人员,提供从客户微表情识别到销售话术生成的完整思路。文档共一百三十七页,以PDF格式打包,大小约十一点零七兆字节&a…

2026/9/23 15:54:25

夜间行人检测:5000张图三种格式标签与YOLO11跨平台训练

简介:面向夜间监控与低光行人检测需求,这套资源包含5000张真实场景夜间行人高质量图片,涉及夜间街景行人、道路行人、遮挡行人及严重遮挡行人等丰富场景,并采用LabelImg逐张标注,标注质量可靠,统一提供VOC(…

2026/9/23 15:54:25

深度学习DOA估计入门:从数据生成到模型训练的避坑指南

简介:一份面向窄带信号波达方向(DOA)估计的 Python 深度学习入门代码包,供信号处理与机器学习初学者学习使用。DOA 估计旨在确定信号源相对接收阵列的方向,是雷达、通信与声学系统中的重要课题;窄带信号频率…

2026/9/23 15:54:25

TM1640驱动详解:裸机GPIO模拟I²C时序与数码管控制

简介:本资源是一份面向嵌入式开发初学者与单片机爱好者的TM1640 LED数码管驱动程序实现,专为简化7段数码管显示控制而设计,适用于电子钟、计数器、简易仪表等常见应用场景。压缩包仅含2个核心文件(1个.h头文件与1个.c实现文件&…

2026/9/23 12:07:00

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/23 12:06:55

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/23 0:01:54

3个实战技巧搞定形式英语:从看教程到跑通性能优化

3个实战技巧搞定形式英语:从看教程到跑通性能优化 看了一堆教程还是不会写项目?别慌,这种“眼高手低”的困境在开发者圈子里太常见了。很多人以为卡点在语法,其实真正拦路虎是缺乏将知识点串联成完整链路的能力。今天咱们不聊虚的,直接拿【形式英语】这…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码