简介:这是一套面向Python初学者与数据分析爱好者的天气预测与可视化完整项目源码,适合用作课程设计、毕业设计或数据挖掘练手案例。项目以Python为核心,串联数据采集、清洗、建模预测到前端展示的完整链路,帮助读者理解天气数据从原始CSV到预测结果的全流程处理思路。压缩包共27个文件,约2.86MB,包含4个Python源码文件承载数据分析与预测逻辑,4个CSV文件存储原始及处理后天气数据,1个Pickle模型文件保存训练结果,1个HTML文件用于前端可视化展示,另有12张jpg图像呈现可视化效果,以及若干Markdown说明与编译缓存文件。目前已有955人学习下载,具备一定参考热度。读者可从中获取可运行的预测脚本、模型持久化方案、数据预处理范例与可视化图表参考,并借助目录结构快速定位数据、代码与展示模块,适合对照复现与二次开发。
1. 从一份 29 文件的天气预测源码包说起:它到底能跑出什么
如果你手头正好有一份upload.zip,解压后看到main.py、GetData.py、ProcessData.py、GetModel.py四个源码文件,外加date_train.csv、date_test.csv、date_valid.csv三份数据和一个Model.pkl,那你拿到的不是玩具 demo,而是一条从抓数、清洗、建模到出图的完整链路。它解决的核心问题是:把天气网站上的原始观测数据抓下来,整理成可训练的时序样本,训练一个预测模型,再把预测结果和真实曲线画在一起,最后用天气网.html做前端展示。适合谁?适合刚学完 Python 基础、想找一个能跑通「数据采集 + 预测 + 可视化」全流程的练手项目的人,也适合需要快速搭一个天气预测原型的从业者。12 张 jpg 图不是装饰,它们是可视化结果的实物证据,说明这条链路真的出过图。
2. 拆开源码包:四个 .py 文件的分工与数据流
2.1 GetData.py 负责抓数,天气网.html 是它的产物
GetData.py是整个链路的入口。它的职责很明确:从天气网站拉取数据,落成 CSV。项目里出现的天气网.html和china_today.csv就是这一步的产物——前者是抓下来的页面快照,后者是解析后的当日数据。常见做法是用requests拿页面,再用BeautifulSoup或lxml解析表格。这里要注意,天气网站的结构会变,所以抓取逻辑不能写死某一个 class 名,最好把选择器抽成变量。
# GetData.py 抓取逻辑示意 import requests from bs4 import BeautifulSoup import pandas as pd URL = "http://www.weather.com.cn/..." # 实际地址以源码为准 HEADERS = {"User-Agent": "Mozilla/5.0"} # 不加 UA 容易被拒 def fetch_page(url): resp = requests.get(url, headers=HEADERS, timeout=10) resp.encoding = "utf-8" # 天气网常见编码,写错会乱码 return resp.text def parse_table(html): soup = BeautifulSoup(html, "lxml") rows = soup.select("table tr") # 选择器按实际页面调整 data = [] for tr in rows: tds = [td.get_text(strip=True) for td in tr.find_all("td")] if tds: data.append(tds) return pd.DataFrame(data) if __name__ == "__main__": html = fetch_page(URL) df = parse_table(html) df.to_csv("china_today.csv", index=False, encoding="utf-8-sig")逻辑说明:fetch_page负责网络请求,timeout=10是防止卡死;resp.encoding必须显式设置,否则中文会变乱码。parse_table把表格行转成 DataFrame,utf-8-sig是为了 Excel 打开不乱码。参数上,HEADERS里的 UA 不能省,很多站点会直接拒绝空 UA 的请求。如果你跑GetData.py报ConnectionError,先检查 URL 是否还有效,再看是否需要加Referer。
2.2 ProcessData.py 做清洗与特征,date_train/test/valid 三份 CSV 从这里来
ProcessData.py是承上启下的模块。它读入原始 CSV,处理缺失值、统一时间格式、构造时序特征,然后按时间顺序切分成date_train.csv、date_test.csv、date_valid.csv。这里的关键是切分不能随机打乱,时序数据一旦 shuffle,验证集就会「偷看」未来,指标虚高。常见做法是按时间点切:前 70% 训练,中间 15% 验证,最后 15% 测试。
# ProcessData.py 清洗与切分示意 import pandas as pd import numpy as np def clean(df): df = df.dropna(subset=["temperature", "humidity"]) # 关键列缺失直接丢 df["date"] = pd.to_datetime(df["date"], errors="coerce") df = df.dropna(subset=["date"]).sort_values("date") # 必须按时间排序 return df def split_by_time(df, train=0.7, valid=0.15): n = len(df) i, j = int(n * train), int(n * (train + valid)) return df.iloc[:i], df.iloc[i:j], df.iloc[j:] if __name__ == "__main__": raw = pd.read_csv("china_today.csv") df = clean(raw) tr, va, te = split_by_time(df) tr.to_csv("date_train.csv", index=False) va.to_csv("date_valid.csv", index=False) te.to_csv("date_test.csv", index=False)逻辑说明:dropna只针对关键列,避免把整行都删掉;pd.to_datetime加errors="coerce"是为了把非法日期转成 NaT 再统一丢弃。split_by_time用位置索引切分,保证时间顺序。参数上,train=0.7是经验值,数据量小可以调到 0.8。如果你发现date_train.csv里日期不连续,检查原始数据是否有重复行没去重。
2.3 GetModel.py 训练并落盘 Model.pkl,main.py 串起全流程
GetModel.py负责建模。项目里已经有Model.pkl,说明训练过一次并序列化了。常见做法是用scikit-learn的回归模型或statsmodels的时序模型,训练完用pickle或joblib存下来。main.py则是总调度:调GetData抓数、调ProcessData清洗、调GetModel训练或加载模型、最后出图。
# GetModel.py 训练与保存示意 import pandas as pd, pickle from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error def train(train_csv, valid_csv): tr = pd.read_csv(train_csv) va = pd.read_csv(valid_csv) feats = ["humidity", "pressure", "wind"] # 特征列按实际数据调整 X_tr, y_tr = tr[feats], tr["temperature"] X_va, y_va = va[feats], va["temperature"] model = RandomForestRegressor(n_estimators=200, random_state=42) model.fit(X_tr, y_tr) pred = model.predict(X_va) print("MAE:", mean_absolute_error(y_va, pred)) with open("Model.pkl", "wb") as f: pickle.dump(model, f) return model if __name__ == "__main__": train("date_train.csv", "date_valid.csv")逻辑说明:RandomForestRegressor对特征缩放不敏感,适合这种小规模表格数据;n_estimators=200是精度和速度的折中,数据量小可以降到 100。random_state=42保证可复现。MAE是回归任务最直观的指标,先看它是否合理再谈调参。pickle.dump存模型时注意 Python 版本要一致,__pycache__里的.pyc是 3.11 编译的,换版本可能加载失败。
3. 把项目跑起来:环境、依赖与执行顺序
3.1 依赖清单与安装命令
这个项目依赖不多,核心是pandas、numpy、scikit-learn、requests、beautifulsoup4、lxml、matplotlib。readme.txt里通常有说明,但如果没有,按下面这份装基本不会缺。
# 建议在虚拟环境里装,避免污染全局 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install pandas numpy scikit-learn requests beautifulsoup4 lxml matplotlib逻辑说明:虚拟环境是后悔药,装崩了直接删目录重来。lxml是BeautifulSoup的解析器,不装会退化成内置解析器,速度慢且容错差。如果你用的是 Python 3.11,.pyc文件能直接复用;换 3.12 可能触发重新编译,一般不影响运行。
3.2 执行顺序:先抓数,再清洗,再训练,最后出图
顺序不能乱。main.py通常已经串好,但如果你想分步调试,按GetData.py→ProcessData.py→GetModel.py→main.py走。每步产出的文件就是下一步的输入,缺一环就断链。
| 步骤 | 执行文件 | 输入 | 输出 |
|---|---|---|---|
| 1 | GetData.py | 天气网站 | china_today.csv、天气网.html |
| 2 | ProcessData.py | china_today.csv | date_train/test/valid.csv |
| 3 | GetModel.py | date_train.csv、date_valid.csv | Model.pkl |
| 4 | main.py | Model.pkl、date_test.csv | 12 张 jpg 可视化图 |
逻辑说明:这张表就是数据流的实物映射。如果你只想要预测结果不想重新抓数,可以跳过第 1 步,直接用现成的 CSV。但要注意,china_today.csv是「当日」数据,放久了就过期,预测意义会打折。
3.3 可视化出图:12 张 jpg 是怎么生成的
main.py里通常用matplotlib画图,把预测曲线和真实曲线叠在一起,再存成 jpg。项目里 12 张图对应不同维度或不同时间段。常见坑是中文显示成方块,需要设置字体。
import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["SimHei"] # 中文显示,Windows 常用 plt.rcParams["axes.unicode_minus"] = False # 负号正常显示 def plot(y_true, y_pred, path): plt.figure(figsize=(10, 4)) plt.plot(y_true, label="真实值") plt.plot(y_pred, label="预测值") plt.legend() plt.title("天气预测对比") plt.savefig(path, dpi=150, bbox_inches="tight") plt.close() plot([1,2,3], [1.1,1.9,3.2], "wps17.jpg")逻辑说明:font.sans-serif设成SimHei是 Windows 下的常规做法,Linux 上要换成系统里有的中文字体,否则中文全是方框。axes.unicode_minus=False解决负号显示异常。dpi=150保证图片清晰度,bbox_inches="tight"去掉多余白边。plt.close()必须加,否则循环画 12 张图会内存暴涨。
4. 避坑与排查:这份源码最容易翻车的五个地方
4.1 抓数返回空或乱码
现象:china_today.csv只有表头没有数据,或者中文全是乱码。原因:天气网站改版导致选择器失效,或者编码没设对。解决:先用浏览器打开天气网.html看结构,把parse_table里的选择器改成实际标签;编码统一用resp.encoding = resp.apparent_encoding让 requests 自己猜。
4.2 时序切分用了随机 shuffle
现象:验证集 MAE 低得离谱,但测试集一跑就崩。原因:train_test_split默认 shuffle,时序数据被打乱后模型「看到」了未来。解决:改用按时间位置切分,参考 2.2 里的split_by_time,绝不加shuffle=True。
4.3 Model.pkl 加载报版本不兼容
现象:pickle.load抛UnpicklingError或AttributeError。原因:.pkl是用 Python 3.11 存的,你换了 3.12 或换了 scikit-learn 版本。解决:要么切回 3.11 环境,要么删掉Model.pkl重新跑GetModel.py生成一份。.pyc文件同理,版本不对就删掉让 Python 重新编译。
4.4 中文图表显示成方块
现象:12 张 jpg 里标题和标签全是方框。原因:matplotlib默认字体不含中文。解决:按 3.3 设置font.sans-serif,Linux 上先fc-list :lang=zh查可用中文字体,再填进去。如果还不行,检查字体文件是否真的存在。
4.5 路径写死导致换目录就报错
现象:在项目根目录能跑,换个目录就FileNotFoundError。原因:源码里用了相对路径如"date_train.csv",依赖当前工作目录。解决:用os.path.dirname(__file__)拼绝对路径,或者统一在项目根目录执行。常见做法是加一个BASE_DIR变量,所有路径基于它拼。
import os BASE_DIR = os.path.dirname(os.path.abspath(__file__)) train_path = os.path.join(BASE_DIR, "date_train.csv")逻辑说明:__file__是当前脚本路径,abspath转绝对,dirname取目录。这样无论从哪执行,路径都对。这是血泪经验,路径问题排查起来最费时间。
5. 进阶用法:把预测结果接到 HTML 和可视化大屏
5.1 用天气网.html 做静态展示的改造思路
项目里的天气网.html目前只是抓取快照,但你可以把它改造成结果展示页。思路是:main.py出图后,把图片路径和预测数值写进一个 JSON,HTML 用fetch读 JSON 再渲染。这样每次跑完模型,刷新页面就能看到最新结果,不用手动换图。
// 在天气网.html 里加一段渲染逻辑 fetch('result.json') .then(res => res.json()) .then(data => { document.getElementById('temp').innerText = data.pred_temp + '℃'; document.getElementById('chart').src = data.chart_path; });逻辑说明:fetch读同目录下的result.json,把预测温度和图表路径填进页面。result.json由main.py用json.dump生成。这样 HTML 就从静态快照变成了动态展示页。注意浏览器直接打开本地 HTML 时fetch可能被跨域策略拦,起一个python -m http.server就能解决。
5.2 接 ECharts 做可视化大屏的可行路径
如果你想把 12 张静态 jpg 升级成可交互的图表,ECharts 是最省事的选择。做法是:main.py除了存 jpg,再把预测序列导出成 JSON 数组,HTML 里用 ECharts 的line组件渲染。这样鼠标悬停能看具体数值,比 jpg 直观得多。常见做法是把date_test.csv和预测结果合并成一个{date: [], true: [], pred: []}的结构,前端直接消费。
| 方案 | 优点 | 代价 |
|---|---|---|
| 静态 jpg | 零依赖,跑完就有 | 不可交互,改图要重跑 |
| HTML + JSON | 轻量,刷新即更新 | 需要起本地服务 |
| ECharts 大屏 | 可交互,适合演示 | 前端工作量增加 |
逻辑说明:这张表帮你按场景选。自己看结果,jpg 够了;要给同事演示,HTML + JSON 最快;要做成可视化大屏,再上 ECharts。别一上来就追求大屏,先把预测跑准。
5.3 验证模型是否真的可用:三个必看指标
跑通不等于可用。我一般会强制走一遍这三个检查:第一,看date_test.csv上的 MAE 是否和验证集接近,差距大说明过拟合;第二,把预测曲线和真实曲线叠图,看趋势是否跟得上,滞后太多说明特征不够;第三,拿最近 7 天数据做一次滚动预测,看误差是否稳定。这三步走完,心里才有底。
从那以后我每次拿到这种时序预测源码包,都先跑一遍测试集叠图,再决定要不要调参。希望帮到你。
本文还有配套的精品资源,点击获取