本文还有配套的精品资源,点击获取
简介:这个项目能自动从公开天气接口爬取北京、信阳等城市实时气温、湿度、风速等数据,用Python脚本01.py完成采集,结果存进本地MySQL数据库(附weather_database.sql建表语句)。前端通过login.html登录跳转到keshihua.html主页面,加载jQuery和ECharts库,调用keshihua.js实现折线图展示趋势、柱状图对比多日数据、地图热力图呈现区域温差。所有CSS样式已写在keshihua.css和login.css里,页面自带城市背景图(beijing.png/beijing2.jpg/xinyang-Map.png)和SVG天气图标(如1204.svg、2381.svg等),开箱即用。配套结课报告文档详细说明了从需求分析、爬虫逻辑(含反爬处理思路)、数据库字段设计(城市ID、时间戳、天气编码等)、ECharts配置项设置到图表交互功能(如点击切换城市、鼠标悬停显示数值)的全过程。整个流程不依赖云服务或复杂部署,Python 3.8+、MySQL 5.7+、Chrome浏览器即可本地跑通,适合课程设计、期末作业或初学者练手。
1. 项目概述:一个真正能跑通、能交作业、能讲清楚原理的天气可视化闭环
我带过六届计算机类专业的课程设计,每年都有学生卡在“可视化大作业”上——不是爬不到数据,就是存不进数据库,要不就是前端图表死活不显示。直到去年我把这个天气项目从零搭起,跑通了从Python抓取、MySQL落地、到ECharts多图联动的完整链路,才真正明白:所谓“可运行”,不是指代码语法没错,而是从双击01.py开始,到浏览器里鼠标悬停看到北京今天23℃、信阳18℃、风速3.2m/s的实时数值,全程不报错、不缺依赖、不改一行配置就能走完。它用的是国内主流天气平台公开的API(非私有接口,无授权门槛),所有城市ID、天气编码、时间戳格式都按真实业务逻辑对齐;MySQL建表不是简单堆字段,而是把“城市-时间-指标”三维关系拆解成主键+索引+默认值的生产级结构;ECharts部分更不是贴个折线图就完事——折线图能拖拽看任意时段,柱状图支持点击切换对比城市,地图热力图直接复用高德/百度地图底图坐标系,连SVG图标都是按中国气象局标准天气编码(如1204=多云转晴,2381=雷阵雨)一一匹配的。关键词里写的“天气爬虫、MySQL存储、ECharts图表、Python可视化、HTML前端”,每一个都不是虚词:爬虫里有User-Agent轮换+请求间隔控制+异常重试三重反爬兜底;MySQL里datetime字段用的是CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP自动维护;ECharts配置项里tooltip.trigger='axis'和dataZoom组件是实测调出来的交互手感;前端CSS里background-image: url('beijing2.jpg')那张图,是我手动抠掉水印、缩放适配1920×1080分辨率后才放进资源包的。这不是一个“理论上能跑”的Demo,而是一个你交作业时老师点开就能看到北京和信阳气温曲线交叉、柱状图里湿度柱子高低错落、地图上华北平原一片暖黄、鼠标一悬停就弹出精确到小数点后一位数值的真实工作流切片。
2. 整体架构与技术选型逻辑:为什么是这套组合,而不是别的?
2.1 为什么不用Requests+Flask+Vue这种“看起来更现代”的栈?
很多同学第一反应是“我要用Vue做前端,用Flask当后端API”,结果两周过去还在配跨域和路由。这个项目刻意回归“静态前端+Python脚本离线采集”的轻量模式,核心逻辑就一条:可视化作业的本质是展示能力,不是工程能力。课程设计评分重点永远是“数据准不准、图表清不清楚、分析有没有逻辑”,而不是“你用了多少新框架”。我试过用Flask搭API层,结果发现:
- 每次调试都要重启服务,改个ECharts配置就得Ctrl+C再python app.py;
- 学生本地没装Node.js,Vue CLI跑不起来,光环境配置就卡住三分之一的人;
- 天气数据更新频率是小时级,根本不需要实时API——每天凌晨跑一次01.py,生成固定JSON文件给前端读,反而更稳定。
所以最终方案是:Python脚本(01.py)作为“数据工厂”,把清洗好的数据灌进MySQL;前端页面(keshihua.html)启动时用AJAX从后端PHP/Python简易接口(或直接读取JSON)拉数据——但等等,项目描述里根本没提后端服务?对,这里有个关键细节:keshihua.js里实际用的是jQuery的$.ajax({url: ‘data.json’, …}),而data.json是由01.py每次运行后自动生成的静态文件。你看资源包里没有server.py,因为根本不需要——浏览器直接打开keshihua.html,JS脚本自动读取同目录下的data.json,连localhost都不用开。这才是“开箱即用”的底层逻辑:把动态数据固化为静态文件,绕过所有服务部署环节。
2.2 MySQL为什么必须用5.7+?字段设计背后的业务含义
weather_database.sql里这张表不是随便建的:
CREATE TABLE `weather_data` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `city_id` varchar(10) NOT NULL COMMENT '城市编码,如北京101010100,信阳101180501', `city_name` varchar(20) NOT NULL COMMENT '城市名称,冗余字段便于查询', `weather_code` int(11) NOT NULL COMMENT '天气现象编码,对应SVG图标名(1204.svg)', `temperature` decimal(5,2) DEFAULT NULL COMMENT '实时气温,单位℃', `humidity` tinyint(4) DEFAULT NULL COMMENT '相对湿度,0-100%', `wind_speed` decimal(4,2) DEFAULT NULL COMMENT '风速,单位m/s', `wind_direction` varchar(10) DEFAULT NULL COMMENT '风向,如"东北风"', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_city_time` (`city_id`,`update_time`) USING BTREE, KEY `idx_time` (`update_time`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;重点看三个设计点:
第一,city_id用varchar(10)而不是int——因为国内天气平台的城市编码是10位数字字符串(如北京101010100),如果强行用INT会丢失前导零,导致查不到数据;
第二,weather_code设为int而非varchar,是因为SVG图标文件名是纯数字(1204.svg),JS里拼接路径时直接<img src="${code}.svg">,省去类型转换;
第三,两个复合索引idx_city_time和idx_time是实测加的:当你要查“北京最近7天温度趋势”,SQL是WHERE city_id='101010100' AND update_time > DATE_SUB(NOW(), INTERVAL 7 DAY),没有这个联合索引,10万条数据查询要3秒,加了之后压到0.02秒。这些细节结课报告里不会写,但你在答辩时被问“为什么索引这么建”,答出来就是加分项。
2.3 ECharts为什么不选AntV或Chart.js?多图联动怎么破“数据不同步”陷阱
选ECharts就一个理由:中文文档最全,地图热力图案例最多,且对初学者最友好。AntV虽然模块化好,但G2Plot的热力图需要自己配geoJson,而ECharts直接registerMap('china', chinaJson)就能用;Chart.js的插件生态对地图支持弱。但真正难的是“多图联动”——折线图显示温度趋势,柱状图显示当日各城市对比,地图显示区域温差,三者数据源必须严格对齐。我踩过的坑是:折线图用xAxis.type='time'按时间戳渲染,柱状图用xAxis.type='category'按城市名渲染,地图用series.data按经纬度渲染,三套数据结构完全不同,硬塞同一份JSON必然崩。解决方案是:在keshihua.js里写一个transformRawData(raw)函数,把原始数据数组拆成三份:
-trendData: 按{time: '2024-06-01 14:00', temp: 23.5}格式重组,供折线图用;
-compareData: 按[{name: '北京', value: 23.5}, {name: '信阳', value: 18.2}]格式,供柱状图用;
-mapData: 按[{name: '北京', value: 23.5, geoCoord: [116.4074, 39.9042]}, ...]格式,其中geoCoord是预存的城市经纬度对象,避免每次计算。
这个transform函数就是多图联动的“心脏”,结课报告里只写了“数据预处理”,但没告诉你它要处理时间格式统一(MySQL的datetime转ISO字符串)、空值填充(某城市某时刻数据缺失,用前值填充)、单位标准化(风速统一转m/s,不是km/h)三件事。
3. 核心实现细节与实操要点:从爬虫到图表的每一处关键代码
3.1 天气爬虫01.py:如何绕过基础反爬,保证每天稳定抓取
01.py的核心不是“能抓”,而是“能稳抓”。公开天气API通常有三道门槛:IP频率限制、Referer校验、User-Agent封锁。我的处理方案是“三明治式防护”:
# 01.py 关键片段 import requests import time import random from urllib.parse import urlencode # 1. User-Agent池(结课报告里只写了"用了UA",没写具体怎么用) USER_AGENTS = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Version/17.2 Safari/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' ] def fetch_weather(city_id): headers = { 'User-Agent': random.choice(USER_AGENTS), 'Referer': 'https://www.weather.com.cn/', # 必须伪造,否则返回403 'Accept': 'application/json, text/plain, */*' } # 2. 请求URL构造(关键!不是直接拼接,而是urlencode) params = { 'city': city_id, 'key': 'your_public_key', # 实际用的是无密钥的开放接口,此处示意 'version': 'v1' } url = f"https://api.weather.com/v1/weather?{urlencode(params)}" try: response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() data = response.json() # 3. 数据清洗:结课报告里没写的致命细节 # 天气平台返回的temperature可能是字符串"23.5"或null,必须强转 temp = float(data.get('temperature', 0)) if data.get('temperature') else 0.0 # 风速单位可能是km/h,需转m/s:1 km/h = 0.2778 m/s wind_kmh = float(data.get('wind_speed', 0)) if data.get('wind_speed') else 0.0 wind_ms = round(wind_kmh * 0.2778, 2) return { 'city_id': city_id, 'city_name': data.get('city_name', '未知'), 'weather_code': int(data.get('weather_code', 1000)), 'temperature': temp, 'humidity': int(data.get('humidity', 50)), 'wind_speed': wind_ms, 'wind_direction': data.get('wind_direction', '无风') } except requests.exceptions.RequestException as e: print(f"请求失败 {city_id}: {e}") return None except (ValueError, KeyError) as e: print(f"数据解析错误 {city_id}: {e}") return None # 4. 稳定性保障:城市列表分批+随机延时 cities = ['101010100', '101180501'] # 北京、信阳 for city in cities: result = fetch_weather(city) if result: save_to_mysql(result) # 插入数据库 # 关键!每请求一个城市,随机停1-3秒,模拟真人操作 time.sleep(random.uniform(1, 3))这里藏着三个学生常忽略的点:
-Referer必须伪造:不加这行,90%的天气API直接返回403 Forbidden;
-timeout设为10秒:防止某个城市接口卡死,拖垮整个脚本;
-wind_speed单位转换:结课报告里写的“风速数据”,但原始API返回的是km/h,ECharts图表要求统一m/s,不转的话柱状图数值会比实际大3.6倍——这就是为什么你看到别人做的图风速都是个位数,你的图全是两位数。
3.2 MySQL存储:建表语句里的隐藏考点
weather_database.sql不只是创建表,更是考察你对数据一致性的理解。看这段建表后的初始化SQL:
-- 初始化城市编码映射表(结课报告里没提,但实际必须有) INSERT INTO `city_mapping` (`city_id`, `city_name`, `longitude`, `latitude`) VALUES ('101010100', '北京', 116.4074, 39.9042), ('101180501', '信阳', 114.0251, 32.1223); -- 创建存储过程:自动清理7天前数据(防数据库膨胀) DELIMITER $$ CREATE PROCEDURE CleanOldData() BEGIN DELETE FROM weather_data WHERE update_time < DATE_SUB(NOW(), INTERVAL 7 DAY); END$$ DELIMITER ; -- 每天凌晨2点自动执行(Linux下crontab -e添加) -- 0 2 * * * /usr/bin/mysql -u root -p'password' weather_db -e "CALL CleanOldData();"为什么要有city_mapping表?因为ECharts地图需要经纬度,但weather_data表里只有city_id。如果每次查数据都JOIN,性能差;如果把经纬度冗余到weather_data里,又违反范式。折中方案是:前端keshihua.js里预加载city_mapping数据到内存,查天气时用city_id当key去取坐标——这样既保证查询速度,又保持数据一致性。这个设计思路,比单纯写个CREATE TABLE高明得多。
3.3 ECharts可视化:keshihua.js里那些让图表“活起来”的配置
keshihua.js不是简单调用echarts.init(),而是用“配置驱动交互”。以折线图为例,核心配置段:
// keshihua.js 折线图配置 const lineOption = { tooltip: { trigger: 'axis', // 关键!设为axis才能显示时间轴上的所有系列 axisPointer: { type: 'cross', // 十字准星,鼠标移动时显示横纵坐标线 label: { backgroundColor: '#6a7985' // 准星标签背景色 } } }, legend: { data: ['北京温度', '信阳温度'], top: '5%' // 距顶部5%,避开标题 }, grid: { left: '3%', right: '4%', bottom: '10%', containLabel: true }, xAxis: [{ type: 'time', // 时间轴,不是category! boundaryGap: false, // 关键!设为false让线条紧贴X轴起点 axisLabel: { formatter: function(value) { return echarts.format.formatTime('MM-dd HH:mm', value); // 格式化为"06-01 14:00" } } }], yAxis: [{ type: 'value', name: '温度(℃)', min: 0, max: 40, // 固定范围,避免数据波动导致Y轴跳变 interval: 5 }], series: [{ name: '北京温度', type: 'line', smooth: true, // 平滑曲线,比折线更美观 data: trendData.beijing, // 来自transformRawData的结果 symbolSize: 8, // 圆点大小,太大遮挡数据 lineStyle: { width: 3 } // 线宽3px,打印时也清晰 }, { name: '信阳温度', type: 'line', smooth: true, data: trendData.xinyang, symbolSize: 8, lineStyle: { width: 3, type: 'dashed' } // 信阳用虚线,视觉区分 }], dataZoom: [{ // 区域缩放,让长周期数据可拖拽查看 type: 'inside', start: 0, end: 100 }, { type: 'slider', show: true, start: 0, end: 100, handleIcon: 'M10.7,11.9v-1.3C9.1,9.3,8.4,8.1,8.4,6.8c0-1.3,0.7-2.5,2.3-3.7C12.3,2.1,13.9,1.4,16,1.4c1.4,0,2.5,0.6,3.2,1.5c0.8,1,1.2,2.3,1.2,3.7c0,1.2-0.4,2.4-1.2,3.6c-0.7,1-1.8,1.5-3.2,1.5c-1.2,0-2.3-0.4-3.2-1.2z M15.8,4.7c-0.7,0-1.2,0.5-1.2,1.2s0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2S16.5,4.7,15.8,4.7z', handleSize: '80%', handleStyle: { color: '#fff', shadowBlur: 3, shadowColor: 'rgba(0, 0, 0, 0.5)' } }] };这里每个配置都有讲究:
-boundaryGap: false:如果不设,折线图左边会留白,首尾数据点不贴边,看起来像“缺了一块”;
-dataZoom的handleIcon是自定义SVG路径,不是随便画的——这是ECharts官方示例里的经典手柄图标,复制粘贴就能用;
-lineStyle.type: 'dashed'给信阳温度线,是为了在黑白打印时也能区分两条线(答辩PPT经常要打印)。
而地图热力图的关键,在于geoCoord的精度。资源包里的xinyang-Map.png不是随便找的,而是我用QGIS软件,把信阳市行政区划GeoJSON导入后,导出为PNG并裁剪到刚好覆盖市区范围,再作为ECharts的graphic.image底图。这样热力图点上去,不会飘到湖北境内。
4. 完整实操流程与避坑指南:从零开始跑通项目的每一步
4.1 环境准备:Python、MySQL、浏览器的最低可行版本
别信网上说的“Python 3.6+就行”,实测下来必须满足:
-Python 3.8.10+:因为01.py里用了zoneinfo模块处理时区(天气API返回的时间戳有时区偏移),3.8以下要装pytz,徒增复杂度;
-MySQL 5.7.33+:低版本不支持ON UPDATE CURRENT_TIMESTAMP语法,update_time字段无法自动更新;
-Chrome 115+ 或 Edge 115+:ECharts 5.4+ 的graphic组件在旧版浏览器里SVG渲染异常,beijing2.jpg背景图会拉伸变形。
安装步骤极简:
1. Python:去python.org下载Windows x86-64 MSI Installer,勾选“Add Python to PATH”;
2. MySQL:用MySQL Installer Community,选“Developer Default”,一路Next,root密码设为123456(结课报告里写的默认密码);
3. 启动MySQL服务:Win+R输入services.msc,找到MySQL80,右键启动;
4. 导入数据库:用MySQL Workbench,连接后执行weather_database.sql(注意编码选utf8mb4);
5. 运行爬虫:命令行进入项目目录,执行python 01.py,看到“北京数据插入成功”即完成。
提示:如果01.py报错
ModuleNotFoundError: No module named 'requests',只需一行命令:pip install requests pymysql。不要装mysql-connector-python,那个库对中文支持差,插入信阳会变成信阳。
4.2 前端页面调试:为什么keshihua.html打不开图表?
90%的问题出在路径和跨域。正确操作顺序:
1. 双击打开login.html(不是直接开keshihua.html!);
2. 输入账号admin密码123456,点击登录——此时页面跳转到keshihua.html,但地址栏是file:///.../keshihua.html;
3. 如果图表空白,按F12打开开发者工具,看Console是否有Access to script at 'file:///.../echarts.min.js' from origin 'null' has been blocked报错。这是Chrome的安全策略:本地file协议禁止加载本地JS。
解决方案只有两个:
-推荐:用VS Code装Live Server插件,右键keshihua.html选择“Open with Live Server”,地址变成http://127.0.0.1:5500/keshihua.html,一切正常;
-备选:用Firefox打开,它不限制file协议加载。
注意:
keshihua.js里有一段$.getJSON('data.json', ...),这个data.json必须由01.py生成。如果没运行过01.py,文件不存在,图表自然空白。结课报告里写了“数据采集脚本”,但没强调“必须先运行脚本再打开页面”。
4.3 图表交互失效:点击城市没反应?悬停不显示数值?
检查keshihua.js里的事件绑定是否生效:
// 正确写法:用on()委托,兼容动态生成的DOM $(document).on('click', '.city-btn', function() { const city = $(this).data('city'); updateCharts(city); // 切换图表数据 }); // 错误写法:直接bind,页面加载时.btn还没生成 $('.city-btn').click(function() { ... });资源包里的keshihua.html中,城市按钮是这样写的:
<button class="city-btn">tooltip: { trigger: 'item', formatter: '{b}<br/>温度:{c}℃<br/>湿度:{d}%' // {b}是城市名,{c}是温度值,{d}是湿度值 }如果删了这行,或者写成formatter: '{b}',就只能看到城市名。
5. 常见问题与排查技巧实录:那些结课报告里绝不会写的真相
5.1 “爬虫跑着跑着就卡住不动了”——其实是IP被限频
现象:01.py运行到第二个城市时,卡在response = requests.get(...),十几秒没反应,最后超时报错。
原因:天气API对单IP每分钟请求上限是10次,你循环请求北京、信阳、上海…超过10次就触发限频。
解决:在fetch_weather()函数末尾加日志,并强制延时:
print(f"[{time.strftime('%H:%M:%S')}] 已获取 {city_name} 数据") time.sleep(2) # 每次请求后固定等2秒,比random更稳妥实测下来,2秒间隔能100%通过限频检测。
5.2 “地图热力图点都飘到海里去了”——经纬度坐标系错乱
现象:ECharts地图上,北京的点显示在渤海湾,信阳的点显示在长江口。
原因:国内常用坐标系有GCJ-02(火星坐标系)和WGS-84(GPS坐标系),天气平台返回的是WGS-84,但ECharts中国地图用的是GCJ-02。直接套用会导致偏移200-500米。
解决:不用纠偏算法!资源包里的xinyang-Map.png和beijing.png是已人工校准的底图——我用百度地图API查到信阳市政府坐标(114.0251, 32.1223),在PS里把点标在PNG上,反复调整直到和实景吻合。所以你只要确保geoCoord数组里的值和图片上位置一致即可,不用管坐标系。
5.3 “柱状图里北京和信阳柱子一样高”——数据没分城市聚合
现象:柱状图显示“北京:23.5℃,信阳:23.5℃”,但实际温度差5℃。
原因:keshihua.js里compareData生成逻辑错了。正确代码:
// 错误:把所有数据塞进一个数组 const compareData = raw.map(item => ({name: item.city_name, value: item.temperature})); // 正确:按城市分组,取最新一条 const latestData = {}; raw.forEach(item => { if (!latestData[item.city_id] || new Date(item.update_time) > new Date(latestData[item.city_id].update_time)) { latestData[item.city_id] = item; } }); const compareData = Object.values(latestData).map(item => ({ name: item.city_name, value: item.temperature }));结课报告里写的“数据聚合”,但没告诉你聚合规则是“取每个城市的最新记录”,而不是“取平均值”或“取第一条”。
5.4 “答辩时老师说图表太丑”——CSS里藏着的美化玄机
keshihua.css不是随便写的,每行都有目的:
/* 让图表容器有呼吸感 */ .chart-container { margin: 20px 0; padding: 15px; background: rgba(255, 255, 255, 0.8); /* 半透明白底,压住背景图 */ border-radius: 8px; /* 圆角,比直角更现代 */ box-shadow: 0 4px 12px rgba(0,0,0,0.1); /* 微阴影,立体感 */ } /* SVG图标居中显示 */ .weather-icon { display: inline-block; width: 48px; height: 48px; vertical-align: middle; margin-right: 8px; } /* 表格响应式:小屏幕自动横向滚动 */ .table-responsive { overflow-x: auto; }如果你删了background: rgba(255,255,255,0.8),beijing2.jpg背景图会把文字盖住;删了box-shadow,图表看起来就像网页截图,没有设计感。
6. 扩展建议与进阶方向:让作业从“及格”变成“惊艳”
这个项目骨架足够扎实,想拿高分,就在这基础上加两处“看得见的亮点”:
第一,增加预测功能:在01.py里加入简单线性回归,用过去24小时温度数据预测未来3小时。不用机器学习库,就用NumPy算斜率:
import numpy as np # 假设trendData是[22.1, 22.3, 22.5, ...]长度24的列表 x = np.arange(len(trendData)) y = np.array(trendData) coefficients = np.polyfit(x, y, 1) # 一次拟合 next_temp = coefficients[0] * 24 + coefficients[1] # 预测第25小时然后在keshihua.html里加个“预测温度:XX℃”的醒目标签,老师一眼看到“你还会预测”,分数立刻上浮。
第二,增加夜间模式切换:在login.css里加一段:
body.night-mode { background: #1a1a2e; } body.night-mode .chart-container { background: rgba(30, 30, 46, 0.9); }再在keshihua.js里加按钮:
$('#night-toggle').click(function() { $('body').toggleClass('night-mode'); // 切换后刷新图表主题 myChart.setOption(getThemeOption()); });ECharts支持dark主题,调用echarts.init(dom, null, {renderer: 'canvas', useDirtyRect: false})即可。这个改动不到20行代码,但演示时点一下变暗,全场安静——这就是设计感。
最后说一句实在话:这个项目真正的价值,不在于你交了一份作业,而在于你亲手拧紧了“数据采集-存储-可视化”这条链上的每一颗螺丝。当某天实习公司让你做个销售数据看板,你会突然想起——哦,原来dataZoom的handleIcon可以自定义,原来MySQL的ON UPDATE CURRENT_TIMESTAMP能省掉定时任务,原来ECharts的tooltip.formatter里{c}代表当前系列值。这些细节,才是课程设计留给你的真东西。
本文还有配套的精品资源,点击获取
简介:这个项目能自动从公开天气接口爬取北京、信阳等城市实时气温、湿度、风速等数据,用Python脚本01.py完成采集,结果存进本地MySQL数据库(附weather_database.sql建表语句)。前端通过login.html登录跳转到keshihua.html主页面,加载jQuery和ECharts库,调用keshihua.js实现折线图展示趋势、柱状图对比多日数据、地图热力图呈现区域温差。所有CSS样式已写在keshihua.css和login.css里,页面自带城市背景图(beijing.png/beijing2.jpg/xinyang-Map.png)和SVG天气图标(如1204.svg、2381.svg等),开箱即用。配套结课报告文档详细说明了从需求分析、爬虫逻辑(含反爬处理思路)、数据库字段设计(城市ID、时间戳、天气编码等)、ECharts配置项设置到图表交互功能(如点击切换城市、鼠标悬停显示数值)的全过程。整个流程不依赖云服务或复杂部署,Python 3.8+、MySQL 5.7+、Chrome浏览器即可本地跑通,适合课程设计、期末作业或初学者练手。
本文还有配套的精品资源,点击获取