基于Python与Vue3的多维度天气数据可视化平台
系统架构与核心目标
本项目构建了一个面向历史气象数据的分析与展示平台,采用前后端分离设计,融合爬虫采集、数据清洗、数据库建模、机器学习预测及前端动态可视化能力。系统支持多城市数据接入,实现从原始网页抓取到智能趋势推演的完整闭环。
关键技术选型
- 后端框架:Flask 3.0 提供轻量级API服务,配合 SQLAlchemy 实现对象关系映射
- 前端技术栈:Vue3 + Vite 构建响应式界面,使用 Element Plus 组件库增强交互体验
- 数据可视化:ECharts 5 实现复杂图表渲染,支持时间序列、热力图与词云等展示形式
- 数据处理:Pandas 和 NumPy 完成数据清洗与特征工程,提升分析准确性
- 机器学习:Scikit-learn 提供线性回归与随机森林模型,用于未来气温走势预估
模块化目录结构
weather_analytics/ ├── backend/ # 后端服务 │ ├── app/ │ │ ├── api/ # REST接口分组 │ │ │ ├── auth.py # 用户认证逻辑 │ │ │ ├── report.py # 数据报表接口 │ │ │ ├── query.py # 查询服务 │ │ │ ├── analysis.py # 统计分析 │ │ │ ├── predict.py # 预测接口 │ │ │ └── wordcloud.py # 文本可视化 │ │ ├── models.py # ORM实体定义 │ │ ├── cache.py # Redis缓存配置 │ │ └── ml_engine.py # 模型加载与推理 │ ├── config.py # 环境配置文件 │ ├── requirements.txt # Python依赖清单 │ └── run.py # 应用启动脚本 │ ├── frontend/ # 前端应用 │ └── weather-dashboard/ │ ├── src/ │ │ ├── api/ # 请求封装 │ │ ├── views/ # 页面组件 │ │ │ ├── Overview.vue │ │ │ ├── HistoryQuery.vue │ │ │ ├── TempTrend.vue │ │ │ ├── AirQuality.vue │ │ │ ├── CityCompare.vue │ │ │ ├── MapView.vue │ │ │ ├── CloudText.vue │ │ │ └── Forecast.vue │ │ ├── router/ # 路由管理 │ │ ├── store/ # Pinia状态管理 │ │ └── utils/ # 工具函数 │ ├── package.json │ └── vite.config.js │ ├── crawler/ # 数据采集模块 │ ├── scripts/ # 爬虫主程序 │ ├── cleaners/ # 清洗逻辑 │ ├── loader.py # 数据入库脚本 │ ├── updater.py # 增量更新工具 │ └── city_codes.json # 城市编码配置 │ └── docs/ # 项目文档
数据仓库设计:星型模型
为支持多维分析,数据库采用星型结构设计,包含一个事实表和多个维度表:
- 事实表:fact_weather 存储每日气象记录
- 维度表:dim_date(时间)、dim_city(城市)、dim_weather_type(天气类型)
通过外键关联,实现高效的时间切片、区域对比与主题聚合查询。
数据采集流程
利用 Selenium 模拟浏览器行为,访问目标网站并提取结构化数据:
# crawler/scripts/weather_scraper.py
from selenium import webdriver
from bs4 import BeautifulSoup
def fetch_daily_data(city_code, target_year, target_month):
url = f"https://weather-data.example.com/{city_code}/{target_year}-{target_month}"
options = webdriver.ChromeOptions()
options.add_argument("--headless")
driver = webdriver.Chrome(options=options)
driver.get(url)
soup = BeautifulSoup(driver.page_source, 'html.parser')
records = []
for row in soup.select('table tbody tr'):
cols = row.find_all('td')
if len(cols) >= 6:
records.append({
'date': cols[0].get_text(strip=True),
'high': cols[1].get_text(strip=True),
'low': cols[2].get_text(strip=True),
'condition': cols[3].get_text(strip=True),
'wind_dir': cols[4].get_text(strip=True),
'wind_level': cols[5].get_text(strip=True)
})
driver.quit()
return records
数据清洗与转换
使用 Pandas 对原始数据进行标准化处理:
# crawler/cleaners/data_processor.py
import pandas as pd
class DataProcessor:
def standardize(self, raw_df):
df = raw_df.copy()
# 移除空值
df.dropna(subset=['date', 'high', 'low'], inplace=True)
# 异常值过滤
df = df[
(df['high'].astype(float) >= -40) &
(df['high'].astype(float) <= 60) &
(df['low'].astype(float) >= -40) &
(df['low'].astype(float) <= 60)
]
# 类型转换与日期拆解
df['date'] = pd.to_datetime(df['date'])
df['high'] = pd.to_numeric(df['high'], errors='coerce')
df['low'] = pd.to_numeric(df['low'], errors='coerce')
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day
return df
后端数据接口实现
提供统一的 API 接口,支持按城市、年份筛选查询结果:
# backend/app/api/report.py
from flask import Blueprint, request, jsonify
from app.models import db, FactWeather, DimCity, DimDate
report_bp = Blueprint('report', __name__)
@report_bp.route('/trend', methods=['GET'])
def get_temperature_trend():
city_id = request.args.get('city_id', type=int)
year = request.args.get('year', type=int)
query = db.session.query(
DimDate.date,
FactWeather.high,
FactWeather.low,
FactWeather.aqi
).join(DimDate).join(DimCity)
if city_id:
query = query.filter(FactWeather.city_id == city_id)
if year:
query = query.filter(DimDate.year == year)
results = query.order_by(DimDate.date).all()
return jsonify([
{
'date': r.date.strftime('%Y-%m-%d'),
'high': r.high,
'low': r.low,
'aqi': r.aqi
} for r in results
])
前端可视化实现
结合 Vue3 的响应式特性与 ECharts 的强大绘图能力,实现动态图表:
<template>
<div ref="chartContainer" class="chart-wrapper"></div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'
import { fetchTrendData } from '../api/report'
const chartContainer = ref(null)
const dataSeries = ref([])
const renderChart = () => {
const chart = echarts.init(chartContainer.value)
const option = {
title: { text: '温度变化趋势' },
tooltip: { trigger: 'axis' },
legend: { data: ['最高温', '最低温', '空气质量'] },
xAxis: {
type: 'category',
data: dataSeries.value.map(d => d.date)
},
yAxis: [
{ type: 'value', name: '℃' },
{ type: 'value', name: 'AQI' }
],
series: [
{
name: '最高温',
type: 'line',
data: dataSeries.value.map(d => d.high),
smooth: true
},
{
name: '最低温',
type: 'line',
data: dataSeries.value.map(d => d.low),
smooth: true
},
{
name: 'AQI',
type: 'line',
yAxisIndex: 1,
data: dataSeries.value.map(d => d.aqi),
smooth: true
}
]
}
chart.setOption(option)
}
onMounted(async () => {
dataSeries.value = await fetchTrendData()
renderChart()
})
</script>
部署与运行
系统可独立部署于服务器或容器环境中:
# 后端启动 cd backend pip install -r requirements.txt python run.py # 前端开发 cd frontend/weather-dashboard npm install npm run dev # 数据初始化 cd crawler python updater.py --mode full_import
功能展示
系统包含以下关键页面:
- 首页概览:展示全国主要城市的实时气象摘要
- 历史查询:支持按城市、时间段检索具体天气记录
- 温度趋势图:显示长期气温波动曲线
- 空气质量分析:结合污染指数进行环境评估
- 城市对比面板:横向比较不同地区的气候特征
- 词云图:基于天气描述生成关键词视觉呈现
- 预测模块:基于历史数据输出未来7天天气预判
所有图表均支持缩放、平移与数据导出功能,满足科研与决策支持需求。