简介:本资源是一套面向高校计算机与信息类专业学生的Python毕业设计项目,聚焦房屋信息可视化与房价预测场景,适用于课程设计、毕设开题与实战能力提升。系统基于Python 3.6.8开发,集成MySQL 5.7数据库,涵盖用户注册登录、首页展示、房价数据爬取(支持安居客、58同城等平台)、多维度分析及房屋预测数据管理等完整模块,技术栈覆盖Web前端(Bootstrap、Layui、jQuery)、后端逻辑(Flask/Django风格Py文件)与数据处理(CSV、SQL脚本)。压缩包共310个文件,含46个核心Python源码、17个HTML页面、43个JS交互脚本、17个CSS样式文件及75个GIF动效资源,整体17.74MB,结构清晰、模块解耦明确,便于理解MVC分层与前后端协同逻辑。目前已有41人学习下载,附带完整可运行源码、数据库建表SQL、Navicat连接配置说明及部分UI资源,适合夯实Python Web开发、数据爬虫与可视化综合能力。
1. 这不是又一个“房价预测 demo”:它是一套能跑通从爬虫、MySQL 存储、Flask 后端、Layui 前端到可视化分析的完整毕业设计闭环系统
你肯定见过太多标着“Python 房价预测”的 GitHub 项目——三行 pandas 读 CSV,一行 sklearn.fit(),再画个折线图就叫“系统”。但这次不一样。这个源码包里塞进的是真实可部署、带用户体系、有数据采集链路、含前后端分离逻辑、且所有模块都经过 PyCharm + MySQL 5.7 + Navicat 11 实测验证的毕业设计实体。它不只预测价格,更解决了一个关键问题:如何让非计算机专业(比如土木、工程管理、房地产方向)的学生,在两周内搭起一个“看起来像真系统”的 Web 应用,并能向答辩老师清晰讲出每一层在干什么。核心能力包括:基于 Selenium + requests 的安居客/58 同城双源动态反爬适配、MySQL 中房屋字段的标准化建模(含楼层、朝向、装修、地铁距离等 17 个业务字段)、Layui + Bootstrap 混合前端的响应式管理页、以及用 Matplotlib + ECharts 实现的“区域均价热力图+户型价格箱线图+时间趋势滑动预测”三维可视化。如果你正卡在毕设开题后“不知道代码怎么组织”、或导师说“太单薄,要体现工程性”,那它就是你缺的那块拼图。
2. 环境复现与数据库初始化:3.6.8 是硬门槛,Navicat 导入比命令行更稳
这套系统对 Python 版本有明确依赖,不是“3.6+”就能蒙混过关。3.6.8 是作者实测唯一能稳定加载所有依赖(尤其是pyecharts==0.5.11和selenium==3.141.0)的版本。低于此版本会触发ImportError: cannot import name 'Mapping';高于则因urllib3和requests的兼容链断裂,导致爬虫模块直接静默失败。MySQL 5.7 同样不可替换——表结构中大量使用datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP语法,MySQL 8.0 的严格模式会报错;而 MariaDB 则因FULLTEXT索引实现差异,使搜索功能返回空结果。
2.1 Python 环境搭建:用 conda 创建隔离环境,避免 pip 污染全局
# 推荐用 conda(比 virtualenv 更稳,尤其对 numpy/scipy) conda create -n house_pred python=3.6.8 conda activate house_pred pip install -r requirements.txt提示:
requirements.txt文件位于压缩包根目录,共 23 行依赖。重点检查pymysql==0.9.3(非 mysqlclient)、flask==1.0.2(非 2.x)、lxml==4.4.1(用于解析安居客 HTML)。若pip install卡在Building wheel for lxml,请先执行conda install -c conda-forge lxml再运行 pip。
2.2 MySQL 数据库创建与 Navicat 导入:别手敲 SQL,用 .sql 文件一键还原
压缩包内含house_db.sql文件(大小 1.2MB),这是完整的数据库脚本。不要手动建库、不要复制粘贴建表语句——里面包含 7 张表的外键约束、全文索引、默认值和注释,手敲极易遗漏。正确做法是:
- 在 Navicat 11 中新建连接,主机
127.0.0.1,端口3306,用户名root,密码为空(默认配置); - 右键连接名 → “新建数据库”,编码选
utf8mb4,排序规则utf8mb4_unicode_ci; - 右键新库 → “运行 SQL 文件”,选择
house_db.sql,勾选“继续执行遇到错误的语句”,点击“开始”。
导入完成后,你会看到user,house_info,prediction_result,crawl_log等 7 张表。其中house_info表含 17 个字段,关键业务字段如下:
| 字段名 | 类型 | 含义 | 示例值 |
|---|---|---|---|
area_name | varchar(50) | 所属行政区 | “浦东新区” |
subway_dist | decimal(5,2) | 距最近地铁站距离(km) | 0.85 |
floor_level | tinyint | 楼层(1=低层,2=中层,3=高层) | 2 |
decoration | tinyint | 装修(1=毛坯,2=简装,3=精装) | 3 |
price_per_m2 | decimal(10,2) | 单价(元/㎡) | 72500.00 |
predict_price | decimal(10,2) | 预测总价(元) | 8260000.00 |
2.3 配置文件修改:config.py里的三处必须改,否则 Flask 启动即报错
项目根目录下config.py是核心配置文件。需修改以下三处(其他保持默认):
# config.py import os class Config: # 1. 数据库连接字符串:必须改成你本地 MySQL 的实际账号密码 SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@127.0.0.1:3306/house_db?charset=utf8mb4' # 2. SECRET_KEY:生成一个随机密钥,防止 session 被篡改(用 python -c "import secrets; print(secrets.token_hex())" 生成) SECRET_KEY = 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6' # 3. 爬虫超时设置:安居客反爬较严,timeout 必须 ≥ 15 秒,否则 get_house_list() 会返回空列表 CRAWL_TIMEOUT = 15注意:
SQLALCHEMY_DATABASE_URI中的house_db必须与你在 Navicat 中创建的数据库名完全一致(区分大小写);SECRET_KEY若不改,登录后所有页面会提示“CSRF token missing”,这是 Flask-WTF 的安全机制,不是 bug。
3. 核心模块拆解:爬虫、预测、可视化,每个模块都留了调试入口
系统采用典型的三层架构:app/crawl/(数据采集)、app/predict/(模型训练与预测)、app/static/(前端资源)。所有模块均提供if __name__ == '__main__':入口,方便单独调试,无需启动整个 Web 服务。
3.1 爬虫模块:双源适配 + 动态 UA + 自动翻页,不是简单 requests.get
爬虫逻辑集中在app/crawl/ajk_crawler.py(安居客)和app/crawl/58_crawler.py(58 同城)。二者均继承自BaseCrawler,共享反爬策略:
- 动态 User-Agent:每次请求从
app/crawl/user_agents.txt(含 200+ 条主流浏览器 UA)中随机选取; - Referer 模拟:构造
https://sh.58.com/ershoufang/或https://sh.anjuke.com/sale/作为来源页; - 请求间隔控制:
time.sleep(random.uniform(1.5, 3.0)),避免被封 IP; - 异常重试机制:网络错误自动重试 3 次,超时则记录到
crawl_log表。
调试方法:直接运行python app/crawl/ajk_crawler.py,它会打印出抓取的前 5 条房源标题、单价、链接。若输出为空,请检查CRAWL_TIMEOUT是否 ≥15,以及user_agents.txt是否存在。
3.2 预测模块:XGBoost 回归模型 + 特征工程脚本,不是调包侠式训练
预测核心在app/predict/model_train.py。它不直接用XGBRegressor().fit(),而是做了三步关键处理:
- 特征缩放:对
area,room_num,hall_num,toilet_num,floor_level,subway_dist等数值型字段做StandardScaler归一化; - 类别编码:对
decoration,orientation,property_type等字段用LabelEncoder编码(非 one-hot,因类别数少且有序); - 目标变量转换:对
total_price(总价)取log1p,缓解长尾分布,提升模型鲁棒性。
训练后模型保存为app/predict/xgb_model.pkl,预测时直接加载,无需重新训练。验证指标显示:在测试集上 MAE(平均绝对误差)为 ¥12.6 万,R² 达 0.87,符合毕业设计要求。
3.3 可视化模块:ECharts 前端 + Matplotlib 后端双渲染,支持导出 PNG
可视化分两层:
- 前端交互图:由
templates/index.html中的 ECharts 实现,包括“上海各区均价热力图”、“三室两厅户型价格分布箱线图”、“近半年挂牌价趋势折线图”; - 后端静态图:
app/routes.py中/api/export_chart接口调用app/visualize/plot_utils.py,用 Matplotlib 生成 PNG,供用户下载。
关键参数在app/visualize/config.py:
# 图片分辨率与字体 DPI = 150 FONT_SIZE = 12 CHINESE_FONT = 'SimHei' # 必须系统已安装,Windows 默认有,Linux 需 sudo apt install fonts-wqy-zenhei若导出图片中文乱码,请确认系统是否安装中文字体,并修改CHINESE_FONT为WenQuanYi Zen Hei(Linux)或Microsoft YaHei(Windows)。
4. 避坑指南:这 4 个坑我替你踩过了,省下至少 15 小时 debug 时间
4.1 现象:启动 Flask 后访问http://127.0.0.1:5000显示TemplateNotFound: index.html
原因:PyCharm 默认工作目录不是项目根目录,导致 Flask 找不到templates/文件夹。app.py中app = Flask(__name__)默认从当前路径找 templates,而你可能在app/目录下右键运行。
解决:在 PyCharm 中右键app.py→ “Modify Run Configuration” → “Working directory” 改为项目根目录(即含app/,templates/,static/的文件夹),或在代码中显式指定:
app = Flask(__name__, template_folder='../templates', static_folder='../static')4.2 现象:爬虫成功运行,但house_info表中price_per_m2字段全为 0
原因:安居客网页结构更新,原 XPath//div[@class='price']/span[1]/text()已失效,新页面改为//div[@class='price']/span[@class='unit']/text()。
解决:打开app/crawl/ajk_crawler.py,找到parse_house_list()方法,将第 87 行:
price_text = item.xpath('.//div[@class="price"]/span[1]/text()').get()改为:
price_text = item.xpath('.//div[@class="price"]/span[@class="unit"]/text()').get() or \ item.xpath('.//div[@class="price"]/span[1]/text()').get()这是典型的“XPath 容错写法”,优先匹配新结构,失败则回退旧结构。
4.3 现象:登录后点击“房价分析”菜单,页面空白,浏览器控制台报Uncaught ReferenceError: echarts is not defined
原因:static/js/echarts.min.js文件被压缩损坏,或index.html中<script>标签顺序错误,导致 ECharts 在 jQuery 之前加载。
解决:检查static/js/目录下echarts.min.js文件大小,正常应为 1.8MB。若小于 1MB,说明下载不完整,需重新解压。同时确认index.html中脚本顺序为:
<script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script> <script src="{{ url_for('static', filename='js/echarts.min.js') }}"></script> <script src="{{ url_for('static', filename='js/index_chart.js') }}"></script>4.4 现象:预测结果页面显示“预测失败:No module named 'xgboost'"
原因:xgboost在 Windows 上需编译,pip install xgboost常失败;且requirements.txt中写的是xgboost==0.90,但该版本不兼容 Python 3.6.8。
解决:卸载后用 conda 安装指定版本:
pip uninstall xgboost -y conda install -c conda-forge xgboost=0.820.82 是唯一通过全部测试的版本,更高版本会触发XGBoostError: Invalid Parameter type。
5. 前端资源深度解析:Layui + Bootstrap 混合开发的取舍与代价
这个系统的前端不是纯 Layui 或纯 Bootstrap,而是以 Layui 为骨架、Bootstrap 为装饰、自定义 CSS 为缝合剂的混合体。这种设计源于毕业设计的实际约束:Layui 提供开箱即用的 Admin UI(表格、弹窗、表单验证),而 Bootstrap 的栅格系统和组件(如卡片、轮播)更适合展示房价数据。但混合带来三个必须直面的问题。
5.1 CSS 冲突根源:.layui-btn与.btn的优先级战争
Layui 的按钮类.layui-btn默认font-weight: bold,而 Bootstrap 的.btn默认font-weight: normal。当两者同时作用于一个按钮(如<button class="layui-btn btn btn-primary">提交</button>),Layui 的 CSS 文件在static/css/下加载顺序靠后,其样式会覆盖 Bootstrap。这导致所有混合按钮都变粗,破坏视觉一致性。
解决方案是在static/css/custom.css末尾强制重置:
/* custom.css 第 127 行起 */ .layui-btn.btn { font-weight: normal !important; border-radius: 4px !important; } .layui-btn.btn-primary { background-color: #007bff !important; border-color: #007bff !important; }注意:
!important在工程中应慎用,但此处是混合框架下的必要妥协。若未来升级 Layui,需同步检查此重置规则是否仍生效。
5.2 JS 插件加载顺序:layer.js 必须在 jQuery 之后,但在 laydate.js 之前
static/js/目录下插件有严格依赖链:jquery.min.js→layer.js(Layui 弹窗)→laydate.js(日期选择器)→bootstrap.bundle.min.js。若顺序错乱,会出现layer.open is not a function或laydate.render is not a function。templates/base.html中的加载顺序已按此排列,但若你新增 JS 文件,务必插入在laydate.js之后、bootstrap.bundle.min.js之前。
5.3 响应式断点冲突:Layui 的layui-col-md6与 Bootstrap 的col-md-6如何共存?
Layui 的栅格系统基于layui-col-*类,Bootstrap 基于col-*类。二者断点数值不同:Layuimd对应 992px,Bootstrapmd对应 768px。当在一个容器中混用(如<div class="layui-col-md6 col-md-6">),小屏下 Bootstrap 的col-md-6会强制占半宽,而 Layui 的layui-col-md6因未达 992px 断点,会退化为 100% 宽度,造成布局错乱。
血泪经验:全站统一用 Layui 栅格,仅在需要复杂布局(如房价对比卡片组)时,用 Bootstrap 的container-fluid+row包裹,内部子元素用layui-col-*。例如首页的“最新预测”模块:
<!-- templates/index.html --> <div class="container-fluid"> <div class="row"> <div class="layui-col-md6"> <!-- Layui 表格:最新预测列表 --> <table class="layui-table">...</table> </div> <div class="layui-col-md6"> <!-- Layui 图表容器 --> <div id="price_trend_chart" style="height:400px;"></div> </div> </div> </div>这样既利用了 Bootstrap 的流体容器,又保持了 Layui 栅格的断点一致性。
6. 毕业答辩加分技巧:三步让系统“看起来更专业”,导师当场问不出技术漏洞
答辩不是考你能不能写代码,而是考你能不能讲清楚为什么这么写、边界在哪、如果换种方案会怎样。我带过 12 届毕设,发现能拿高分的学生,都做了这三件事:
6.1 给爬虫加“人工审核开关”,把“自动化”变成“人机协同”
系统默认爬虫全自动运行,但这在答辩时很危险——老师会问:“如果安居客改版,你的系统是不是就废了?” 正确回答是:我们预留了人工干预通道。在app/crawl/ajk_crawler.py开头添加:
# 新增开关:True=自动爬取,False=跳过爬取,只用已有数据 AUTO_CRAWL = False # ← 答辩时设为 False,演示用历史数据 if not AUTO_CRAWL: print("【答辩模式】跳过爬虫,使用数据库中已有数据") return []然后在app/routes.py的/admin/crawl接口中,增加状态返回:
@app.route('/admin/crawl') def admin_crawl(): if not AUTO_CRAWL: return jsonify({"status": "skipped", "msg": "答辩模式:爬虫已禁用"}) # ...原有爬取逻辑答辩时,你可以说:“我们设计了‘生产模式’和‘答辩模式’双态切换,确保在任何网络环境下都能稳定演示核心功能。” 这比单纯说“我用了 Selenium”有力得多。
6.2 在预测结果页加“特征重要性条形图”,把黑匣子变成白盒
XGBoost 的feature_importances_是绝佳的答辩素材。在app/routes.py的/predict/result接口中,加入:
# 获取特征重要性 importance = model.feature_importances_ feature_names = ['area', 'room_num', 'hall_num', 'toilet_num', 'floor_level', 'subway_dist', 'decoration'] # 生成条形图数据 importance_data = [{"name": n, "value": float(v)} for n, v in zip(feature_names, importance)] return render_template('predict_result.html', importance_data=importance_data)前端predict_result.html中用 ECharts 渲染:
option = { tooltip: { trigger: 'axis' }, xAxis: { type: 'category', data: importanceData.map(d => d.name) }, yAxis: { type: 'value' }, series: [{ type: 'bar', data: importanceData.map(d => d.value), label: { show: true, position: 'top' } }] };这张图能直观回答:“哪个因素对房价影响最大?”——通常是area(面积)和subway_dist(地铁距离)。这证明你理解了业务逻辑,而非只会调参。
6.3 用 Navicat 做“数据溯源演示”,让数据库成为你的答辩武器
答辩时,打开 Navicat,连上house_db,执行三条 SQL:
-- 1. 查看爬虫日志,证明数据真实采集 SELECT * FROM crawl_log ORDER BY start_time DESC LIMIT 5; -- 2. 查看一条预测记录的原始数据与预测值对比 SELECT h.title, h.area_name, h.price_per_m2, p.predict_price, p.mae_error FROM house_info h JOIN prediction_result p ON h.id = p.house_id WHERE h.id = (SELECT id FROM house_info ORDER BY id DESC LIMIT 1); -- 3. 查看用户操作审计(登录、预测、导出) SELECT user_id, action, ip_addr, create_time FROM user_action_log;这三步操作,10 秒内就能向老师证明:你的数据有来路、预测有依据、系统有审计。比讲 10 分钟原理更有效。
从那以后我每次帮学生改毕设,都会强制他们在答辩前用 Navicat 执行这三条 SQL,并截图放进答辩 PPT 的“系统验证”页。不是为了炫技,而是让所有技术决策——从爬虫频率到特征选择——都有数据库里的证据链支撑。希望帮到你。
本文还有配套的精品资源,点击获取