做天气预报气候研究系统这个念头,是我去年年底整理家里旧硬盘时冒出来的。当时翻出自己三年前记录的一堆本地气温数据,突然想看看这几年天气到底有没有明显变化,但单纯靠Excel做统计实在太费劲,就想着干脆用Python写个Web系统,既能看实时天气,又能把历史气候数据做成趋势图。于是就有了这个基于Flask + Vue + PyCharm的天气预报气候研究系统。项目做下来,前后端分离、数据采集、图表可视化、分析统计全都走了一遍,收获很大,这篇文章准备把完整思路和实操过程都写出来,给想用Python做Web可视化系统的朋友当一条可以参照的路线。
这个系统到底能做什么?简单说:后端用Flask提供天气查询和历史数据统计的API接口,前端用Vue组件展示实时天气卡片、未来几天预报以及历史气候趋势图,开发环境直接用PyCharm搞定。它适合已经会Python基础、想学Flask和Vue联调的人,也适合对天气数据分析感兴趣、想做一个完整项目练手的同学。整个项目代码量不大,但麻雀虽小五脏俱全,覆盖了Web开发的常见套路。
1. 项目整体设计与技术选型
1.1 需求拆解:天气预报气候研究系统到底要做什么
好多初学者拿到这种项目标题,第一反应就是“查天气呗”,然后就开始调API,写个输入框,查完显示温度就完事了。但“气候研究”这几个字把项目拔高了一个档次,它意味着系统除了展示今天的天气,还要有历史数据的积累、趋势分析、统计对比。我给自己列了几个核心功能点:
- 实时天气查询:输入城市名,返回当前温度、湿度、风力、气压、天气现象。
- 未来多日预报:展示未来3到7天的天气情况,方便判断近期变化。
- 历史气候数据管理:把每次查询的数据存到本地SQLite,长期积累。
- 气候趋势分析:对历史温度数据进行月平均、年变化趋势处理,用图表展示。
- 前端可视化:通过Vue + ECharts把数据以卡片、折线图、柱状图等形式直观呈现。
所以这个项目的本质不是“调个天气接口”,而是“数据采集 + 存储 + 分析 + 可视化”的完整闭环。后端不只是简单的路由转发,还需要处理数据持久化;前端也不是写一个静态页面,而是要通过接口驱动动态渲染。综合考虑后,我的技术选型就很明确了。
1.2 技术栈选型:为什么是Flask而不是Django
项目标题里同时出现了flask和django,但仔细看“python基于flask的天气预报气候研究系统”,主后端肯定是Flask。那为什么不用Django?我在开发前专门对比过:
- Flask轻量灵活,适合快速搭建小规模API服务,路由和中间件都自己控制,代码透明。
- Django太“重”,自带Admin后台、ORM、模板系统,虽然功能全,但很多是这个小项目用不到的,还会增加理解成本。
- 这个系统主要提供RESTful API给前端Vue调用,Flask按照蓝图组织接口非常舒服。
- Flask生态里的库足够用了,SQLAlchemy做ORM,Flask-CORS解决跨域,requests抓数据,一套下来干净利落。
当然,Django也不是不能用。如果项目规模大、需要自带后台管理系统、又要做用户权限,Django比较合适。但我个人对这种偏展示型和研究型的Web系统,还是倾向Flask。当初我把标题里的“django”理解成一个备选项,实际建设时果断选了Flask,用PyCharm管理器创建虚拟环境,装Flask和相关依赖,整个过程非常顺畅。
1.3 项目结构规划:前后端分离的目录设计
天气预报气候研究系统虽然是个人项目,但代码组织结构不能乱。我用的是前后端完全分离的结构,后端只暴露接口,前端单独跑Vue开发服务,通过HTTP请求和Flask通信。这样以后换掉前端框架,或者把后端换成Django,都可以独立演进。
weather-research/ ├── backend/ │ ├── app.py # Flask入口,注册蓝图 │ ├── config.py # 配置项(端口、数据库路径) │ ├── db.py # SQLite连接/初始化 │ ├── weather_api.py # 天气查询接口 │ ├── climate_api.py # 气候分析接口 │ └── requirements.txt └── frontend/ ├── public/ ├── src/ │ ├── api/ │ │ └── index.js # axios封装,统一请求路径 │ ├── components/ │ │ ├── WeatherCard.vue │ │ ├── ForecastList.vue │ │ └── TrendChart.vue │ ├── App.vue │ └── main.js ├── package.json └── vite.config.js # 开发服务器配置这个结构你看着清爽,开发时也省心。后端和前端各自维护依赖,互不污染。
2. 核心细节解析与数据链路设计
2.1 天气数据从哪来:数据源与抓取策略
天气数据是系统的“原材料”。为了开发调试方便,我第一版用的是本地模拟数据,就是写一个随机生成温度和天气现象的函数,先把前后端联调跑通。等到界面稳定了,再去对接公开天气API。
对接真实天气数据时要注意几个坑:
- 接口稳定性:我用的国内和风天气API,注册后可以获得免费Key,请求地址是
https://devapi.qweather.com/v7/weather/now,支持城市编码和经纬度。 - 城市名到城市编码的转换:直接传中文城市名有时不稳定,建议用城市编码。我维护一个小字典,把常用城市和编码对应起来。
- 请求频率和用量:免费版有调用限制,查询时做好缓存,不要每次打开页面都请求一次。
如果你的网络环境访问第三方API时感觉不够顺畅,可以考虑用本地模拟数据或公开的JSON文件做降级处理,至少保证系统演示和开发流程不受影响。我在代码里做了一个简单的缓存,同一个城市五分钟内请求过的数据直接走本地缓存,不重复请求,既快又省额度。
2.2 后端Flask API设计要点
Flask后端我按接口职责拆了两个蓝图:一个负责实时天气和预报,一个负责气候分析统计。主入口app.py负责创建应用、注册蓝图、启用CORS。
后端接口设计遵循RESTful风格,例如:
GET /api/weather/current?city=北京:返回当前天气。GET /api/weather/forecast?city=北京&days=3:返回未来预报。GET /api/climate/monthly?year=2024&month=5:返回指定月份的历史统计。POST /api/climate/record:把查询到的数据写入数据库。
写接口时一定记得用JSON格式返回统一结构,我会固定返回这样一组字段:
{ "code": 0, "message": "success", "data": { } }这样前端不管接什么接口,都能先判断code再处理data,出错时也能通过message快速定位。
2.3 前端Vue页面与数据交互
前端我用Vue 3 + Vite + Element Plus,组件化开发。整体页面分三块:
- 顶部搜索栏:输入城市名,点击查询。
- 中间天气卡片区域:展示当前天气和未来预报。
- 底部图表区域:显示历史气温趋势、月平均气温柱状图。
Vue这边的核心逻辑就是通过axios访问Flask接口。比如获取当前天气时,我在组件里写一个方法:
import axios from 'axios' async function getCurrentWeather(city) { const res = await axios.get(`http://localhost:5000/api/weather/current`, { params: { city } }) if (res.data.code === 0) { // 更新组件数据 } }要注意开发环境下前端在5173端口,后端在5000端口,直接跨域请求会报错,所以Flask后端必须加CORS支持。我用flask-cors扩展,在app.py里一行代码解决。这个细节看起来小,但忘了配就是那种“明明接口单独访问没问题,前端却死活调不通”的经典坑。
前端和后端交互时的另一个重点是数据字段对齐。比如Flask返回的实时温度字段是temp,前端组件里也一定用temp,不要前端又改成temperature,然后调试半天。我建议后端把数据结构定义好后,前端项目里放一份接口文档或者类型定义文件,两边保持一致,这套系统现在跑得稳就是因为当初这一步做得早。
3. 实操过程与核心模块实现
3.1 环境准备:PyCharm + Python + Flask + Vue
先说我本地的开发环境:Windows 11 + PyCharm Community Edition,Python 3.10,Node.js 16。PyCharm社区版虽然是免费的,但对Flask开发完全够用,直接新建项目时选“Flask”模板,它会自动创建虚拟环境并安装Flask。如果是手动创建,在PyCharm的Terminal里执行:
python -m venv venv venv\Scripts\activate # Windows pip install flask flask-cors requests sqlalchemy前端部分需要先安装Vue CLI或Vite。我用的Vite,创建命令:
npm create vite@latest frontend -- --template vue cd frontend npm install npm install axios element-plus echarts装完依赖后,在PyCharm里可以打开两个终端,一个跑后端,一个跑前端,分别执行:
python app.py npm run dev这样两个服务就同时跑起来了,非常方便。
3.2 后端实现:天气数据接口开发
后端weather_api.py的核心是请求天气API并解析数据。为了演示,我先写一个基于模拟数据的版本,逻辑清晰,不依赖外网:
import random import time from flask import Blueprint, request, jsonify weather_bp = Blueprint('weather', __name__) # 简单缓存:key是城市,value是(时间, 数据) _cache = {} def mock_weather(city): temp = random.randint(-5, 30) humidity = random.randint(30, 90) condition = random.choice(['晴', '多云', '阴', '小雨', '雪']) return { 'city': city, 'temp': temp, 'humidity': humidity, 'wind': random.choice(['东南风2级', '北风3级', '西风1级']), 'condition': condition, 'time': time.strftime('%Y-%m-%d %H:%M:%S') } @weather_bp.route('/api/weather/current', methods=['GET']) def current_weather(): city = request.args.get('city', '北京') now = time.time() if city in _cache and now - _cache[city][0] < 300: return jsonify({'code': 0, 'message': 'success', 'data': _cache[city][1]}) data = mock_weather(city) _cache[city] = (now, data) return jsonify({'code': 0, 'message': 'success', 'data': data})这段代码里,缓存逻辑虽然简单,但真实系统里很实用。五分钟内重复请求直接返回缓存数据,避免频繁调用外部接口。如果后面接入真实API,只需要把mock_weather函数替换成requests请求即可,接口部分不用改。
3.3 气候分析模块:数据存储与统计
气候分析离不开历史数据,我新建了一个climate.db的SQLite数据库,建表语句放在db.py里:
import sqlite3 def get_db(): conn = sqlite3.connect('climate.db') return conn def init_db(): conn = get_db() conn.execute(''' CREATE TABLE IF NOT EXISTS weather_record ( id INTEGER PRIMARY KEY AUTOINCREMENT, city TEXT NOT NULL, date TEXT NOT NULL, temp REAL, humidity REAL, condition TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ''') conn.commit() conn.close()每当查询实时天气后,我会把数据保存一条到weather_record表。时间长了数据积累足够,就可以做气候研究了。统计接口例如计算某个城市今年的月平均气温,用SQL一条语句就能搞定:
SELECT strftime('%m', date) AS month, AVG(temp) AS avg_temp FROM weather_record WHERE city = ? AND strftime('%Y', date) = ? GROUP BY month ORDER BY month这个统计结果再交给前端ECharts画折线图,气候趋势一目了然。我有时候把三年的数据导出来对比,确实能看到一些有趣的规律。
3.4 前端实现:天气卡片与趋势图表
前端组件化让页面结构特别清晰。WeatherCard.vue负责展示当前天气,界面用Element Plus的卡片组件,把温度、湿度、天气现象用大号字体显示。ForecastList.vue循环渲染未来几天预报。
趋势图表用ECharts,在TrendChart.vue里初始化图表,并监听父组件传过来的统计数据:
<template> <div ref="chartRef" style="width: 100%; height: 400px"></div> </template> <script setup> import { ref, onMounted, watch } from 'vue' import * as echarts from 'echarts' const props = defineProps({ trendData: { type: Array, default: () => [] } }) const chartRef = ref(null) let chart = null onMounted(() => { chart = echarts.init(chartRef.value) }) watch(() => props.trendData, (data) => { if (!chart) return chart.setOption({ xAxis: { type: 'category', data: data.map(d => d.month) }, yAxis: { type: 'value', name: '平均气温(°C)' }, series: [{ type: 'line', data: data.map(d => d.avg_temp) }] }) }) </script>Vue 3的script setup写起来比Vue 2简洁很多,配合watch自动更新图表,数据一回来图表就刷新,体验很好。
3.5 系统运行与联调时的小技巧
在PyCharm里跑Flask项目时,一定记得关掉调试模式或者只开调试模式的端口。为了保证前端能访问后端,我在app.py里这样启动:
if __name__ == '__main__': app.run(host='127.0.0.1', port=5000, debug=True)前端Vite的vite.config.js里配置了开发代理,直接用/api开头请求,代理到5000端口,这样的好处是前端代码里不用写死目标地址:
export default { server: { proxy: { '/api': { target: 'http://127.0.0.1:5000', changeOrigin: true } } } }配上代理后,前端里所有请求写成axios.get('/api/weather/current'),不仅简洁,还能避开跨域。个人项目里这招强烈推荐,比在后端配CORS更省心。
4. 常见问题与排查技巧实录
4.1 跨域报错:前后端明明正常,浏览器就是拦着
这是前后端分离项目最高频的问题。症状是后端接口在浏览器地址栏直接访问能返回JSON,但前端页面调用时报“CORS policy”错误。解决办法有两个:
- 后端加
flask-cors,CORS(app)全开。 - 前端用Vite代理(上面已写),请求不走跨域。
我当时两个方法都试了,最后选择前端代理,因为后端接口以后部署到服务粒度,代理可以统一配置。
4.2 端口占用导致服务起不来
Flask默认5000端口,如果之前有别的程序占用,启动会报Address already in use。处理方式很简单:
# Windows下查看端口占用 netstat -ano | findstr 5000 # 找到PID后结束进程 taskkill /PID <pid> /F或者直接改Flask监听端口,比如改成app.run(port=5001),同时改前端代理目标端口。
4.3 SQLite数据库路径找不到
在PyCharm里直接运行Flask时,工作目录通常是当前文件所在目录,climate.db会生成在根目录。但如果你从别的目录启动app,就会出现找不到数据库文件的问题。我建议在配置里用绝对路径,或者用os.path.dirname(__file__)拼出稳定的数据库路径:
import os BASE_DIR = os.path.dirname(os.path.abspath(__file__)) DB_PATH = os.path.join(BASE_DIR, 'climate.db')这样无论从哪里启动,数据库都能找到。
4.4 pycharm里安装依赖包总是失败怎么办
PyCharm安装Flask失败,通常是因为pip源速度慢或网络不稳定。我的解决办法是在终端直接指定国内镜像源:
pip install flask flask-cors requests -i https://pypi.tuna.tsinghua.edu.cn/simple另外,一定记得先激活虚拟环境。PyCharm底部Terminal里,如果前面没有(venv)字样,就要手动激活,否则pip会装到全局Python环境里去,项目里import依然报错。新手容易在这里翻车,我见过好几个人明明提示安装成功,代码里却红波浪线,原因就是装错环境了。
4.5 时间字段和数据格式不一致
前端图表显示温度折线时,可能出现月份乱序或者日期格式不对。SQLite里存date字段我建议统一格式YYYY-MM-DD,这样strftime能直接格式化。如果用MySQL或PostgreSQL,日期函数略有区别,但思路一样。遇到统计结果不对,先打印出原始SQL和数据,别急着调前端,大概率是SQL逻辑写错了。
5. 气候研究模块的扩展思路
项目做完后,我又看了些气象数据和气候分析的资料,觉得这个方向可以继续延伸。现在的系统还只是“记录 + 统计”,后面完全可以加入更多研究功能:
- 温差分析:计算每个城市一天内的最高最低温差,找出温差大的城市。
- 季节划分研究:根据气温数据反推入春入夏时间,看年份之间的差异。
- 湿度与体感温度建模:结合温度和湿度计算体感温度,让研究更有实用价值。
这些功能不需要更换技术栈,只要在Flask后端加接口,前端再添加对应的图表组件就行。框架搭好了,加功能是非常自然的事。我后续的打算是把历史数据备份成CSV,结合pandas做个离线分析,再把分析结果导入数据库,这样即使不调用外部接口也能做气候趋势研究。
最后分享一个我在实际操作中的小体会:做这类项目,一定不要一上来就急着写代码。先把数据流想清楚,也就是“数据从哪里来、存到哪里去、怎么展示”,这些没问题后再动手,后面会顺畅很多。我当时就是因为先花了半天设计接口和数据结构,后面写前后端几乎没有返工。天气气候研究系统的顶层设计一旦做好了,剩下就是敲码的体力活。希望这篇记录能帮你少踩几个坑,顺利跑起来。