
简介本资源是一份面向Python初学者与课程设计实践者的天气数据爬取与可视化项目聚焦网络数据获取、清洗及图表呈现全流程适用于高校编程入门、数据分析基础课或小型课程设计作业。压缩包仅含1个核心Python脚本.py体积精简至3KB代码内嵌requests库发起HTTP请求获取天气数据结合pandas完成结构化处理并调用matplotlib实现温度趋势折线图等基础可视化完整覆盖爬虫→解析→清洗→绘图四阶段技术链。目前已有3270人学习下载适合作为可直接运行的轻量级教学案例读者不仅能获得开箱即用的单文件脚本还可通过其清晰逻辑理解API调用规范、DataFrame数据操作要点及matplotlib绘图参数配置是掌握Python数据处理闭环实践的高效入门素材。 前阵子想给新手朋友找个既能练爬虫、又能练数据分析、还能出点炫酷效果的项目翻了半天资料最后决定把“Python爬取天气数据 可视化”这套流程完整做了一遍。说实话天气数据是最适合做全流程练习的素材接口免费、字段结构清晰、爬下来还能直接画曲线图和地图不用像电商数据那样做一堆清洗。这篇文章就把我从选型、爬虫、清洗、可视化到打包exe的完整过程拆开讲包括踩过的坑和我自己总结的几条经验希望能给你省点时间。1. 为什么选天气数据当练手项目全流程覆盖性价比极高1.1 天气数据天然适合做学习与演示很多人练爬虫喜欢盯着电商评论、招聘岗位这类数据但这类目标要么登录复杂要么反爬严格新手很容易在第一步就劝退。天气数据不一样它有几个非常适合新手和演示项目的特征数据更新频繁实时性和预测性都有能展示“动态数据采集”的价值。公开接口无需认证只需要关心如何构造请求、解析响应。字段齐全包含温度、湿度、风力、天气现象、日期等可以覆盖大部分Pandas数据处理场景。可视化表现力强既能画折线图、柱状图也能画地图热力图适合做“可视化大屏”的底子。这个项目不仅是一个爬虫Demo它串起了完整的数据工程流程网络请求、HTML/JSON解析、数据清洗、结构化存储、可视化呈现、打包部署。学完这一套后续换任何数据源都只是换接口和解析规则的问题。1.2 核心目标与最终效果我给自己定的目标是自动获取国内主要城市的天气数据包括实时温度和未来15天预报。把数据清洗后存成CSV/Excel方便后续离线分析。用matplotlib画温度曲线用pyecharts画全国温度分布地图并拼成可交互的可视化页面。打包成exe让不装Python的人也能直接运行。最终的效果是运行程序后桌面会生成一个HTML大屏文件浏览器打开后能看到全国主要城市的实时温度地图、近15天温度趋势曲线、风力/天气现象统计面板。2. 爬虫设计请求什么样的接口、怎么拿城市代码、如何防止被封2.1 数据源选型对比做天气爬虫项目最常见的几个数据源是和建议数据源是否需要Key反爬强度数据结构建议和风天气API需要注册中JSON规范适合有Key的开发不适合纯爬虫练习中国天气网公开接口无需低JSON / HTML最适合本项目第三方聚合API大多收费中高JSON不推荐手动抓包App接口无高加密较多不建议新手尝试我最终选择了中国天气网weather.com.cn的公开数据接口。原因很简单免费、无需注册、返回JSON结构清晰而且涵盖了实时天气、逐日预报、城市代码查询等常用数据。需要注意这是公开信息接口仅用于学习和技术演示不能用于高频抓取和商业行为。2.2 城市代码自动获取天气接口大体上是按城市代码来区分的比如101010100代表北京101020100代表上海。手动维护一份几百个城市的代码表不太现实好在官方提供了城市代码的层级接口省级列表http://www.weather.com.cn/data/city3jdata/china.html市级列表http://www.weather.com.cn/data/city3jdata/provshi/{province_code}.html区县级列表http://www.weather.com.cn/data/city3jdata/cityxi/{city_code}.html这几个接口返回的都是JavaScript中的数组结构例如省级列表返回的是{ 01: 北京, 02: 上海, ... }所以解析方式是先用正则或json解析出字典再逐级拼接出完整城市代码。我用requests直接请求加上UA头伪装浏览器然后将市级代码和区县代码拼接为9位城市代码。这里有个容易踩的坑市级接口返回的键是两位数字比如北京下的0101而区县接口返回的键也是两位。拼接城市代码时必须注意将省市县三级编码拼成省码 市码 县码的9位格式不要把前缀弄丢。2.3 实时天气与15天预报接口城市代码拿齐后实时天气和预报数据的核心接口分别是实时天气http://d1.weather.com.cn/weather_index/{city_code}.html15天预报按月份获取http://d1.weather.com.cn/calendar_new/{year}/{city_code}_{year}{month}.html实时天气接口返回的是JS变量定义格式比如var cityDZ {...}; var dataSK {...}; var dataZS {...};其中dataSK里包含了实时温度、湿度、风向、风力、空气质量等字段。因此解析思路是先通过正则拿到dataSK {...}部分再用json.loads解析。15天预报接口返回的则是JSON数组每一个元素代表一天里面包含日期、最高温度、最低温度、白天天气现象、夜晚天气现象、风力风向等。需要注意月份参数这个接口是按年-月维度返回整月数据需要过滤出未来15天。2.4 请求头、超时与重试的设计公开接口虽然反爬不强但也不能拿到就无脑高频请求。我模拟正常浏览器的访问方式headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: http://www.weather.com.cn/, }同时每个城市请求之间加上time.sleep(random.uniform(0.5, 1.5))随机延时避免出现集中访问。超时统一设置为5秒配合retrying库重试3次。这个配置我实测跑全国300多个城市时全程没有出现过IP被限制的情况。2.5 数据字段说明与存储结构我最终保存的核心字段如下字段名说明来源city城市名称城市代码表city_code城市代码城市代码表temp实时温度摄氏度实时接口dataSKhumidity相对湿度实时接口dataSKwind_dir风向实时接口dataSKwind_level风力等级实时接口dataSKdate预报日期预报接口high最高温度预报接口low最低温度预报接口day_type白天天气现象预报接口night_type夜间天气现象预报接口2.6 爬虫完整代码示例下面是我实际用的爬虫核心代码去掉了日志和部分非关键配置import requests import json import re import time import random BASE_URL http://www.weather.com.cn HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: http://www.weather.com.cn/, } def get_city_code_map(): 获取全国城市代码返回{城市名: 9位代码} city_map {} province_url f{BASE_URL}/data/city3jdata/china.html province_data requests.get(province_url, headersHEADERS, timeout5).json() for prov_code, prov_name in province_data.items(): city_url f{BASE_URL}/data/city3jdata/provshi/{prov_code}.html city_data requests.get(city_url, headersHEADERS, timeout5).json() for city_code, city_name in city_data.items(): full_city_code prov_code city_code 00 city_map[city_name] full_city_code # 如果还想取区县可以继续请求 cityxi 接口 return city_map def fetch_realtime_weather(city_code): 获取实时天气数据 url fhttp://d1.weather.com.cn/weather_index/{city_code}.html resp requests.get(url, headersHEADERS, timeout5) resp.encoding utf-8 match re.search(rvar dataSK (\{.*?\});, resp.text, re.S) if not match: return None return json.loads(match.group(1)) def fetch_forecast(city_code, year, month): 获取月份预报数据 url fhttp://d1.weather.com.cn/calendar_new/{year}/{city_code}_{year}{month:02d}.html resp requests.get(url, headersHEADERS, timeout5) resp.encoding utf-8 return resp.json()使用示例if __name__ __main__: city_map get_city_code_map() # 只演示北京 beijing_code city_map[北京] data fetch_realtime_weather(beijing_code) print(data[temp], data[SD], data[WD], data[WS]) forecast fetch_forecast(beijing_code, 2025, 7) print(forecast[0])需要注意dataSK字段在不同时间段返回的字段名略有差异比如实时湿度有时是SD有时是humidity。写解析逻辑时最好先打印一次返回结果再针对性提取字段不要想当然地按文档写死。3. 数据处理与清洗别让脏数据毁掉可视化3.1 为什么天气数据也需要清洗很多人觉得天气接口返回的是结构化数据不需要清洗直接存就行了。实际上我跑完300多个城市后发现的问题多得超乎想象部分小城市接口返回的字段缺失湿度或风力为空。预报数据中偶尔混入上个月/下个月的数据需要按日期过滤。温度字段出现字符串类型需要转成float才能画图。天气现象同一语义有多种写法比如“多云转晴”和“晴间多云”需要归类。实时接口返回的编码为GBK或UTF-8不固定偶尔出现乱码。如果不做清洗后面画图时就会遇到字符串没法求平均值、空值导致折线断裂、地图上城市名对不上等一堆问题。3.2 清洗流程我的清洗流程分四步字段类型转换将温度、湿度转为数值类型转不了的就标记为NaN。日期过滤只保留未来15天内的数据避免混入过期或超远期的预报。缺失值处理对缺失的数值字段按城市历史平均值填充对缺失的天气现象字段用“未知”填充。归一化映射将天气现象粗粒度归类为“晴”“多云”“阴”“雨”“雪”“风”“雾霾”等大类方便后续统计。归一化映射的代码片段如下def normalize_weather(desc): if not desc: return 未知 if 晴 in desc: return 晴 if 云 in desc: return 多云 if 阴 in desc: return 阴 if 雨 in desc: return 雨 if 雪 in desc: return 雪 if 风 in desc: return 风 if 雾 in desc or 霾 in desc: return 雾霾 return 其他3.3 保存为CSV和Excel清洗完成后我用Pandas统一保存import pandas as pd df pd.DataFrame(all_weather_data) df.to_csv(weather_data.csv, indexFalse, encodingutf-8-sig) # 如果要用Excel需要先安装 openpyxl df.to_excel(weather_data.xlsx, indexFalse)这里有一个使用细节导出CSV时我建议用utf-8-sig编码。如果直接用utf-8用Excel打开时会乱码这个问题在新手项目中出现频率极高。4. 可视化实现从matplotlib曲线图到可交互大屏4.1 两类可视化工具的定位差异在做可视化时我同时使用了matplotlib和pyecharts原因很简单它们定位不同matplotlib适合快速出静态图画折线图、柱状图非常顺手代码量小。pyecharts适合做交互式图表支持地图、Tooltip、数据缩放页面效果更现代适合演示。4.2 matplotlib画温度趋势选了北京、上海、广州三个城市把15天预报中的最高温和最低温画成折线图import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False fig, ax plt.subplots(figsize(10, 5)) for city in [北京, 上海, 广州]: city_df df[df[city] city] ax.plot(city_df[date], city_df[high], labelf{city}最高温) ax.plot(city_df[date], city_df[low], labelf{city}最低温, linestyle--) ax.set_title(主要城市未来15天温度趋势) ax.legend() plt.xticks(rotation45) plt.tight_layout() plt.savefig(temp_trend.png, dpi150) plt.show()4.3 pyecharts画全国温度地图pyecharts画地图时需要先确认对应的地图包。以国内城市地图为例需要安装echarts-countries-js或对应的地图数据包。我使用的是pyecharts 2.x版本全国城市地图用法如下from pyecharts import options as opts from pyecharts.charts import Map city_temp [(北京, 32), (上海, 35), (广州, 34)] map_chart Map() map_chart.add(实时温度, city_temp, maptypechina) map_chart.set_global_opts( title_optsopts.TitleOpts(title全国主要城市实时温度), visualmap_optsopts.VisualMapOpts(min_15, max_40) ) map_chart.render(temp_map.html)需要注意pyecharts的地图和常规字典的键值顺序不同城市名必须和地图数据中的名称严格匹配比如“北京”不能写成“北京市”否则无法高亮显示。4.4 制作可视化大屏为了同时展示多个图表我用pyecharts的Grid或Page将折线图、柱状图和地图组合成一个大屏。这里我采用Grid布局将全国地图放在中间左侧放温度趋势折线图右侧放天气现象统计柱状图。from pyecharts.charts import Grid, Bar, Line grid Grid(init_optsopts.InitOpts(width1600px, height900px, bg_color#0f1f3d)) grid.add(map_chart, grid_optsopts.GridOpts(pos_left15%, pos_right50%)) grid.add(line_chart, grid_optsopts.GridOpts(pos_left50%, pos_right5%)) grid.render(weather_dashboard.html)背景色我用了深蓝色系整体视觉上更像正经的数据大屏。需要注意的是Grid中每个图表的位置需要通过GridOpts精确控制否则多个图表会重叠。还有一种更省事的做法是直接用Page纵向排列但作为大屏演示Grid更严谨。5. 打包exe和实际运行中的避坑经验5.1 为什么需要打包成exe项目做完后我把它打包成了一个独立的exe文件。原因有两个一是方便在没有Python环境的电脑上演示二是把爬虫、清洗、可视化整个流程封装成“一键运行”的产品形态比直接在IDE里跑脚本更有完成度。5.2 pyinstaller打包命令与关键参数我使用的Python环境是3.10打包命令如下pip install pyinstaller pyinstaller -F -w weather_dashboard.py-F打包成单文件适合分发。-w不显示控制台窗口适合给非技术人员运行。但单文件模式下pyecharts的HTML渲染如果有外部JS/CDN资源可能会在无网络环境时加载失败。因此我在项目中引入了pyecharts-assets本地资源并通过jupyter_assets的方式指定为本地路径。如果不需要离线下运行直接引CDN也可以。5.3 三个高频打包坑编码坑打包后运行时日志输出乱码通常是因为控制台编码不是UTF-8。我在代码开头加了sys.stdout.reconfigure(encodingutf-8)。数据文件路径坑如果代码里有读取外部CSV或图片的路径打包后当前工作目录可能和脚本目录不一致导致找不到文件。保险做法是import sys, os base_path getattr(sys, _MEIPASS, os.path.dirname(os.path.abspath(__file__)))动态导入漏包坑pyecharts的部分地图组件是懒加载的pyinstaller不会自动收集到打包后运行到地图时会报ModuleNotFoundError。解决方式是在代码里显式导入所有用到的地图模块或者在spec文件里加上隐藏导入。5.4 定时刷新与性能优化如果想让大屏每隔30分钟自动更新一次数据可以使用schedule库或者简单的while True time.sleep。我在自己做的版本里加入了30分钟刷新逻辑并保留每次抓取的历史数据备份。这里要特别注意内存管理如果连续运行几天DataFrame会不断累积最好定期把旧数据落盘并清空内存否则程序会越来越卡。5.5 合规与频率提醒最后说一句天气数据接口是公开的但也只是为了学习和技术演示。无论用什么数据源都要注意控制请求频率遵守目标网站的服务条款不要把爬虫脚本放到服务器上做高频抓取。做项目练手、搭个知识体系没问题但别去给别人的服务器制造压力。6. 项目扩展方向从天气数据到通用爬虫与数据可视化框架做完了这个项目你会发现它其实是一个可以复用的“数据采集 → 清洗 → 可视化”的骨架。只要替换数据源和解析逻辑就能套用到很多场景换成空气质量指数接口做全国空气质量大屏。换成基金/股票行情接口做自选股实时行情可视化。换成公开的应急避难场所或公共服务设施数据做城市服务地图。我自己后续就在这个框架上扩展了一个空气质量版本结构完全没变只是把天气字段换成了PM2.5、PM10等指标。整个改造过程不到半天说明这套设计对新手扩展是友好的。技术上还有几个可以继续深入的点用APScheduler替代while True做定时任务更稳定。用BeautifulSoup或parsel解析HTML类型的数据而不是硬写正则。用streamlit做一个完整的数据分析交互页面替代静态HTML大屏。把采集结果写入SQLite方便做历史趋势分析。如果看完这篇文章你想动手做的话我的建议是先别急着写代码把城市代码获取、实时天气接口、15天预报接口这三个数据源的含义搞清楚跑通一次requests请求再开始写业务逻辑。这个项目最大的价值不是“写出一段能跑的代码”而是让你通过一个完整链路把Python爬虫、数据清洗和数据可视化这几个技能串在一起。本文还有配套的精品资源点击获取