基于 Python 的订餐系统:从数据爬取到个性化推荐与可视化的一站式实践
面向学习者与实践者的一篇完整技术分享,覆盖项目架构、目录结构、技术栈、部署运行、核心代码、推荐算法、数据可视化与扩展方向。文末附联系渠道。
目录
- 项目简介与功能概览
- 目录结构与核心模块
- 技术栈说明(后端/前端/数据库/数据分析/可视化)
- 快速开始(环境、数据库、启动)
- 核心模块详解与代码
- 用户认证与安全(验证码、登录、注册、密码重置)
- 数据模型与关系
- 推荐系统(相似度与个性化推荐)
- 数据爬取(大众点评示例)
- 项目可视化
- 数据库设计要点
- 扩展方向与最佳实践
- 常见问题(FAQ)
- 预留可视化展示位
- 版权与联系方式
项目简介与功能概览
本项目是一个基于 Flask + MySQL 的订餐系统,提供从店铺/菜品浏览、购物车和订单流程,到评论、收藏、礼品积分、数据爬取、可视化与推荐系统的一整套能力。面向课程设计、毕设与实际小型项目落地均可快速上手与扩展。
已实现的核心能力包括:
- 用户体系:注册、登录、验证码校验、退出、个人资料编辑、密码找回/重置、积分记录。
- 店铺与菜品:分类/区域筛选、店铺详情、菜品详情、评论与评分、收藏与统计。
- 购物与订单:购物车增删改、订单创建/状态跟踪、历史记录与评价。
- 礼品中心:礼品分类与兑换、积分扣减、礼品订单与核销。
- 消息互动:用户留言与管理员回复。
- 数据分析:数据爬取、可视化图表展示、基于收藏行为的个性化推荐。
目录结构与核心模块
以下为关键目录与文件(节选):
food-add/
app.py # 应用入口,蓝图注册、验证码、登录/注册、个人中心等
config.py # 数据库与全局配置(MySQL + PyMySQL)
ext.py # SQLAlchemy 初始化
models.py # 核心业务模型(用户/店铺/菜品/订单/评论/收藏/礼品…)
blueprints/ # 业务蓝图:前台、用户、后台等
templates/ # Jinja2 模板页面(首页、详情、下单、后台管理等)
static/ # 前端静态资源(JS/CSS/图片/图表库)
spider/ # 数据爬取脚本(requests + lxml + pandas)
util/ # 推荐算法与分析工具(NumPy + scikit-learn)
dependency.txt # 依赖安装命令清单
design_159_order.sql # 数据库结构与示例数据(建议导入)
技术栈说明
- 后端
- Flask 3.x(Web 框架)
- Flask-SQLAlchemy(ORM)、Flask-Migrate(迁移)
- Flask-WTF(表单)、Flask-CORS(跨域)
- PyMySQL(MySQL 驱动)
- 数据库
- MySQL(业务数据存储)
- 数据处理与推荐
- NumPy(数值计算)
- Pandas(数据处理/CSV 读写,用于爬取结果存档)
- scikit-learn(余弦相似度计算,店铺相似度与推荐)
- 前端/可视化
- Bootstrap、jQuery
- ECharts(主要图表库,含词云/liquidfill 等插件)
- Chart.js(辅助图表库)
是否使用了 NumPy/Pandas:项目实际使用了二者,分别见
util/analyze.py
(NumPy)与spider/food.py
(Pandas)。
快速开始
- 环境准备
# Python 3.8+ 建议
python -m venv .venv
. .venv/bin/activate # Windows: .venv\\Scripts\\activate
# 安装依赖(逐条执行 dependency.txt 内命令,或自行转为 requirements.txt)
pip install flask==3.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install flask-migrate==4.0.4 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install flask-sqlalchemy==3.0.3 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install flask-wtf==1.2.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install pandas==1.1.5 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install pymysql==1.0.3 -i https://pypi.tuna.tsinghua.edu.cn/simple
- 数据库配置与初始化
- 本地 MySQL 新建数据库(例如:
design_159_order1
)。 - 修改
config.py
连接串以匹配本机账号密码(生产环境切勿使用弱口令)。 - 导入
design_159_order.sql
的表结构与示例数据。
- 运行项目
python app.py
# 浏览器访问 http://127.0.0.1:5000/
核心模块详解与代码
1. 用户认证与安全
验证码、登录、注册、找回/重置密码等逻辑集中在 app.py
。示例:
# 生成四位随机数字验证码
def generate_captcha():
return ''.join(random.choices('0123456789', k=4))
# 验证码图片路由
@app.route('/captcha')
def captcha():
captcha_text = generate_captcha()
session['captcha'] = captcha_text
image_buffer = generate_captcha_image(captcha_text)
response = make_response(image_buffer.getvalue())
response.headers['Content-Type'] = 'image/png'
return response
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
user_captcha = request.form.get('captcha')
if 'captcha' not in session or user_captcha != session['captcha']:
return render_template('login.html', message="温馨提示:验证码错误")
user = User.query.filter_by(username=username).first()
if user and check_password_hash(user.password, password):
session['user_id'] = user.id
session['username'] = username
user.login_time = datetime.now()
db.session.commit()
return redirect(url_for('index.index'))
else:
return render_template('login.html', message="温馨提示:密码错误或用户不存在")
return render_template('login.html')
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
email = request.form.get('email')
phone = request.form.get('phone')
address = request.form.get('address')
# ... 参数校验与重复用户检查 ...
new_user = User(
username=username,
password=generate_password_hash(password),
email=email,
phone=phone,
address=address,
)
db.session.add(new_user)
db.session.commit()
return redirect(url_for('login'))
return render_template('register.html')
2. 数据模型与关系(节选)
models.py
定义了用户、店铺、菜品、评论、收藏、礼品等表及关系:
class Store(db.Model):
__tablename__ = 'store'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
address = db.Column(db.String(255), nullable=False)
phone = db.Column(db.String(20), nullable=False)
average_price = db.Column(db.Float, nullable=True)
monthly_sales = db.Column(db.Integer, nullable=False, default=0)
rating = db.Column(db.Float, nullable=True)
category = db.Column(db.String(100), nullable=True)
districts = db.Column(db.String(100), nullable=True)
dishes = db.relationship('Dish', backref='store_dishes', lazy=True)
reviews = db.relationship('StoreReview', backref='store_reviews', lazy=True)
class Dish(db.Model):
__tablename__ = 'dish'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
description = db.Column(db.Text, nullable=True)
original_price = db.Column(db.Float, nullable=False)
promotional_price = db.Column(db.Float, nullable=True)
monthly_sales = db.Column(db.Integer, nullable=False, default=0)
store_id = db.Column(db.Integer, db.ForeignKey('store.id'), nullable=False)
image = db.Column(db.String(255), nullable=False)
3. 推荐系统(收藏驱动的相似度推荐)
推荐逻辑位于 util/analyze.py
,通过店铺评分构建向量,利用余弦相似度计算店铺相似度,并结合用户收藏生成推荐列表:
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
def calculate_store_similarities():
stores = Store.query.all()
store_data = {s.id: s.rating for s in stores}
store_ids = list(store_data.keys())
if not store_ids:
return {}
ratings_matrix = np.array([store_data[store_id] for store_id in store_ids]).reshape(-1, 1)
similarity_matrix = cosine_similarity(ratings_matrix)
store_similarity_dict = {}
for i, store_id in enumerate(store_ids):
store_similarity_dict[store_id] = {
other_id: similarity
for other_id, similarity in zip(store_ids, similarity_matrix[i])
if other_id != store_id
}
return store_similarity_dict
def recommend_stores(user_id, num_recommendations=5):
user_favorites = StoreFavorite.query.filter_by(user_id=user_id).all()
followed_store_ids = [f.store_id for f in user_favorites]
if not followed_store_ids:
return get_top_favorite_stores(num_recommendations)
store_similarity_dict = calculate_store_similarities()
recommendation_scores = {}
for store_id in followed_store_ids:
for similar_store_id, similarity in store_similarity_dict.get(store_id, {}).items():
if similar_store_id not in followed_store_ids:
recommendation_scores[similar_store_id] = recommendation_scores.get(similar_store_id, 0) + similarity
recommended_store_ids = sorted(recommendation_scores, key=recommendation_scores.get, reverse=True)[:num_recommendations]
return Store.query.filter(Store.id.in_(recommended_store_ids)).all()
可扩展建议:
- 引入更多画像特征(均价、销量、品类向量、地理位置 embedding)。
- 使用矩阵分解/隐语义模型或轻量级深度召回(如 LightFM、YouTube DNN 思路)。
4. 数据爬取(大众点评示例)
spider/food.py
展示了 requests + lxml + pandas 的爬取流程,抓取店铺信息并写入 CSV:
def crawl(url, city):
response = requests.get(url=url, cookies=cookies1, headers=headers)
txt = etree.HTML(response.text)
categories = [("小吃快餐", 'g112'), ("火锅", 'g110'), ("自助餐", 'g111')]
districts = [("渝中区", 'r42'), ("江北区", 'r44')]
for category_name, category_code in categories:
for district_name, district_code in districts:
fl = f'https://www.dianping.com/chongqing/ch10/{category_code}{district_code}'
List_index(fl, category_name, district_name, city, start_page=1, start_index=1)
time.sleep(3)
def down_load(wkb):
columns = ['city','food_category','districts','name','src','pj','price','main','business','recommend','link']
df = pd.DataFrame(wkb, columns=columns)
if not os.path.exists('大众点评.csv'):
df.to_csv('大众点评.csv', index=False, encoding='utf-8-sig')
else:
df.to_csv('大众点评.csv', index=False, header=False, mode='a', encoding='utf-8-sig')
合规提示:请遵守目标网站 Robots 协议与使用条款,合理设置频率与缓存,禁止用于商业抓取。
5. 项目可视化
👾 项目源码获取,码界筑梦坊各平台同名,博客底部含联系方式卡片,欢迎咨询!
前端主要使用 ECharts 构建交互式图表,并提供 Chart.js 作为补充。
基于Python的订餐系统
数据库设计要点(概述)
- 用户(User)关联订单、评论、收藏、积分与礼品兑换记录。
- 店铺(Store)关联菜品、评论与收藏统计;保留均价、销量、评分、分类、区域等特征。
- 菜品(Dish)关联价格、库存、月销量与评论。
- 订单与支付(Order/Payment)管理全流程状态(表定义见
models.py
)。 - 礼品与分类(Gift/GiftCategory)以及兑换流水(GiftRedeem、GiftOrder)。
建议:为高频查询列建立索引(店铺分类/区域、订单状态、用户外键等),订单编号唯一键,分表分库与归档策略可按数据量演进。
扩展方向与最佳实践
- 安全:开启 CSRF、完善权限校验、密码强度与多因子认证(Flask-Login/Flask-Principal 可引入)。
- 性能:读写分离、查询缓存、异步任务(Celery/RQ)处理图片/爬取/推荐批计算。
- 推荐:多特征融合、召回+排序两阶段、AB 测试与效果监控。
- 可视化:接入可视化大屏、时序数据库/OLAP(如 ClickHouse)做多维分析。
- 工程化:Docker 化、CI/CD、灰度发布与线上监控(Prometheus + Grafana)。
常见问题(FAQ)
- 看不到验证码/中文混乱?请确保 Pillow 字体加载正常,模板使用 UTF-8 编码;Windows 下可回退默认字体。
- 登录一直失败?检查 session/secret_key、验证码校验、数据库连接与用户密码是否使用
generate_password_hash
存储。 - 图表不展示?确认页面引用了
echarts.min.js
或Chart.min.js
,并在 DOM 加载后初始化。 - 爬取失败/数据为空?检查 Cookies/Headers 与反爬策略,降低频率并增加重试与代理策略。
版权与联系方式
本文与项目仅用于学习与技术交流,数据抓取请遵守相关法律法规与网站条款,严禁用于非法用途与商业侵权。
交流与合作:码界筑梦坊各大平台同名