新闻详情

新闻详情

首页 / 资讯中心 / 详情

中国天气网天气数据获取:城市代码与公开接口详解

发布时间:2026/9/25 6:33:18来源:尧图网络
中国天气网天气数据获取:城市代码与公开接口详解
简介面向需要对接中国天气网API的开发者这份基于VS2008的C#示例工程演示了从构造HTTP请求、解析JSON/XML响应到界面展示的完整流程适用于学习Web API调用与.NET桌面开发。压缩包共34个文件包含9个cs源码文件、配置文件及项目工程sln/csproj另有编译生成的exe/dll与PDB调试文件整体约259KB结构紧凑适合直接打开学习。已有2308人浏览学习。通过源码可掌握HttpWebRequest发起请求、JavaScriptSerializer解析天气数据、注册API密钥及异常处理等关键细节同时附带Windows窗体界面示例方便理解数据绑定与控件显示。对于刚接触API集成或想在VS2008环境快速跑通天气数据读取的初学者有直接参考价值。1. 中国天气网获取天气数据到底在拿什么城市代码、公开接口和最小脚本很多人想给运维大屏、智能家居或自动化工单加一个天气数据源第一反应是去爬中国天气网的网页把 HTML 里的温度抠出来结果被结构变化折腾一上午。实际上中国天气网有一套公开的 JSON 接口输入城市代码就能拿到实况和预报关键不在逆向也不在爬虫而在“城市代码体系”和“接口返回格式”这两件事上。本文把这套获取方案拆成四步找代码、选接口、写脚本、落地排错。新手能在一个小时内把第一个城市的实况数据拉下来熟手可以跳过基础部分直接去看第 4 章的接口边界和第 5 章的落库校验。2. 先把数据源的地基打牢城市代码、两种公开接口与返回字段2.1 城市代码101 开头的 9 位 ID 怎么解读去哪里查中国天气网的接口不认城市名只认城市 ID。北京是 101010100朝阳区是 101010300上海是 101020100。这套编码是 9 位数字前 3 位固定 101后面每 2 位分别代表省、市、区县。换城市时只替换 ID脚本逻辑完全不用动这是整个采集体系的地基。ID 选错后面所有数据全是错的所以第一步必须把 ID 搞准。找 ID 的常见做法不是去翻天气正文页而是利用中国天气网首页的城市导航数据。首页底部有全国城市列表HTML 里的链接带 9 位数字 ID。另一个办法是看浏览器开发者工具里的网络请求城市分组接口通常以.xml或.json结尾返回的就是 ID 和城市名的对应关系。下面这段脚本用正则从首页 HTML 里把所有城市 ID 和名称成对抠出来再按名字过滤import re import requests city_name 朝阳 resp requests.get( https://www.weather.com.cn/, headers{User-Agent: Mozilla/5.0}, timeout10, ) # 首页城市导航里的链接形如 http://www.weather.com.cn/weather/101010300.shtml pattern re.compile( rhref(?:https?://www\.weather\.com\.cn)?/weather/(\d{9})\.shtml[^]*([^])/a ) matches pattern.findall(resp.text) for city_id, name in matches: if city_name in name: print(city_id, name)这段代码的逻辑是先请求首页再用正则把“9 位数字 ID 城市名”成对提取出来最后按传入的城市名做模糊过滤。参数说明正则里的\d{9}严格匹配 9 位数字避免把页面里其他数字当城市 ID[^]匹配链接文本里的城市名timeout10给首页请求留足响应时间。这套方案的边界是首页导航通常只给到地级市县区一级要再点进市级页面去拿。如果你手里已经有一份别人整理的“城市代码对照表”也建议先用下一步的接口验证一下再大批量使用网上流传的不少表格代码和区县对不上。2.2 两种公开接口实况接口与天气指数接口选哪个取决于用途城市 ID 拿到以后要面对的是接口选择。中国天气网对外用得最多的有两类接口路径都在d1.weather.com.cn下。第一类是实况接口路径为/sk_2d/{city_id}.html返回当前温度、湿度、风向风力和天气现象适合做大屏当前天气、联动预警、空调联动这些场景。第二类是天气指数接口路径为/weather_index/{city_id}.html除了当天实况外还有 3 到 7 天预报、生活指数、空气质量等字段适合做日报推送和趋势分析。两个接口的返回都不是纯 JSON而是形如var dataSK { ... };的 JavaScript 赋值语句解析前要先截掉等号前的部分。二者对请求头的要求也不同后者校验更严格缺少 UA 或 Referer 时容易拿不到完整字段。下面用表格把两类接口的差异列一下方便按场景选型对比项实况接口sk_2d天气指数接口weather_index返回内容当前温度、湿度、风向、风力、天气现象实况 3 到 7 天预报 生活指数数据量小几十个字段大几百个字段请求头要求带浏览器 UA 即可需要 UA 和 Referer部分参数来自首页更新频率约 30 到 60 分钟一次每天几次夜间有维护窗口适合场景轮询频率高的自动化联动日报、定时推送、数据积累接口返回字段也有必要先看懂。以实况接口为例核心字段包括temp当前温度、humidity相对湿度、wind风向风力描述、time数据发布时间、name城市名、id城市 ID。预报接口里则是temp1、temp2、temp3分别代表今明后三天的温度区间weather是天气现象ptime是预报发布时间。字段名在不同接口版本里偶尔会变写解析脚本时不要假设字段永远存在取不到就用默认值兜住。2.3 为什么不建议直接爬网页 HTML三个现实原因可能有人会问既然接口还要处理赋值语句和请求头为什么不干脆用 BeautifulSoup 解析天气详情页这里有一个血泪经验网页结构改版频率太高。中国天气网的详情页从表格布局改成 div 布局又改成现在的模块化结构每次改版爬虫的选择器就要跟着改一遍维护成本远高于接口方案。网页里还混着一堆广告和推荐模块解析出来的文本经常夹带无关内容清洗起来很费劲。更重要的是数据时效性。详情页的 HTML 是服务端渲染的里面写死的温度和接口返回的实况数据有时间差凌晨时段页面可能还是昨天的旧值而实况接口至少在字段里给了time可以自己做时效校验。基于这三点凡是需要长期采集或定时轮询的场景统一走 JSON 接口只是想临时看一眼某个城市今天冷不冷那就直接开浏览器不必写代码。3. 用 Python 拉取中国天气网天气数据从最小请求到批量采集3.1 最小请求脚本先确认网络通、编码对、返回什么接口选好、城市 ID 备齐之后就可以写第一个请求。我一般会先写一个最小脚本只打印返回内容不急着解析字段。这样能把网络、编码、返回格式三个变量分开排查避免一上来就是解析报错分不清是哪一步出了问题。import requests city_id 101010300 # 北京朝阳 url fhttps://d1.weather.com.cn/sk_2d/{city_id}.html headers { User-Agent: ( Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 ), Referer: https://www.weather.com.cn/, } resp requests.get(url, headersheaders, timeout8) print(resp.status_code) print(resp.text[:300])这段代码做了三件事拼出实况接口 URL带上浏览器 UA 和 Referer打印状态码和前 300 个字符。参数说明city_id是城市代码换成你自己的目标城市timeout8给慢响应留余量默认的 3 秒在接口波动时很容易误判超时resp.text[:300]只打印前 300 字符既能确认返回格式又不会被完整内容刷屏。正常情况打印出来是这样一行var dataSK {name:朝阳,id:101010300,temp:16,humidity:22%,wind:北风2级,...};如果看到的是一段 HTML 或者“系统繁忙”之类的提示先检查请求头里的 UA 是否被改成了默认的python-requests/2.x那基本会被反爬拦截。如果中文变成乱码原因多半是编码识别错误这一步先确认现象第 4 章的 4.1 会专门讲。3.2 把var dataSK {...}变成干净的 JSON截取与解析的防御写法确认接口连通后下一步就是把返回的赋值语句转成 Python 字典。sk_2d接口的返回文本结构是var dataSK { ... };标准做法是找到第一个等号取等号后面到结尾的内容去掉结尾的分号再交给json.loads。但接口偶尔会在返回前加空格或注释所以解析代码要写得稍微防御一点import json import requests def parse_weather(text: str) - dict: # 找到第一个等号等号后面才是JSON主体 pos text.find() if pos -1: raise ValueError(f未找到JSON主体: {text[:80]}) json_str text[pos 1 :].strip().rstrip(;).strip() # 部分接口返回的是单引号JSON需要先转成双引号 if json_str.startswith({): return json.loads(json_str) raise ValueError(f返回格式异常: {text[:80]}) resp requests.get(https://d1.weather.com.cn/sk_2d/101010300.html, headersheaders, timeout8) data parse_weather(resp.text) print(data.get(name), data.get(temp), data.get(time))这里的核心逻辑在parse_weather先定位等号把等号后的内容剥出来.strip().rstrip(;).strip()是为了同时处理尾部空格、分号和行尾换行符。参数说明data.get()而不是data[]取值因为接口偶尔会缺字段用get缺省返回None不至于一个 KeyError 打挂整个任务。这段代码还有一个隐藏细节部分历史接口返回的是单引号 JSON直接json.loads会报Expecting property name enclosed in double quotes。遇到这种情况简单粗暴的做法是json_str.replace(, \)再解析但要注意温度值里的℃不受影响实践证明这个替换用在天气数据上是安全的。如果替换后仍然报错就把原始文本打印出来看是不是服务器插入了调试信息。3.3 批量采集多个城市循环、限速与失败跳过单城市跑通后真实场景往往是一批城市要一起采。比如监控华北地区十几个城市的天气做一个区域告警大屏这时就要写批量循环。批量采集有三件事必须做好控制请求频率、失败不中断、记录失败项。接口没有公开的频率说明但从实际表现看每秒一次连续打几百个请求会触发临时限制个人项目把间隔控制在 1 到 2 秒就够用。import time import json import requests CITY_IDS [101010100, 101010300, 101020100, 101280101] # 北京、朝阳、上海、广州 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/122.0.0.0, Referer: https://www.weather.com.cn/, } results {} failed [] for cid in CITY_IDS: url fhttps://d1.weather.com.cn/sk_2d/{cid}.html try: resp requests.get(url, headersheaders, timeout8) if resp.status_code ! 200: failed.append((cid, fHTTP {resp.status_code})) continue data parse_weather(resp.text) results[cid] { name: data.get(name), temp: data.get(temp), time: data.get(time), } print(f{cid} {data.get(name)} {data.get(temp)}℃) except Exception as exc: failed.append((cid, repr(exc))) time.sleep(1.5) # 限速每个城市间隔1.5秒 print(失败列表:, failed)这段代码的容错思路是单个城市失败只记录到failed列表不影响后续城市采集。time.sleep(1.5)是最关键的参数把它调成 0 会明显增加被限制的概率调成 5 又会让大批量采集变得很慢1.5 秒是我试下来比较中庸的值。parse_weather在第 3.2 节定义过业务里可以把这段封装成一个weather_client.py模块请求头、超时、解析逻辑都收敛在一个文件里。批量采集还有一个容易忽略的点尽早打印进度。上面代码里每次成功都输出一行这样脚本挂在后台时你能从日志里看到卡在哪个城市。真实翻车现场往往是某个城市的接口突然返回 403如果没有打印进度你会以为脚本死循环了实际上只是那一个城市的请求被拦。4. 中国天气网接口避坑与排查五个容易翻车的点4.1 返回乱码中文变成问号或锟斤拷现象resp.text打印出来中文全是乱码或者输出一串“锟斤拷”。用print(resp.encoding)看到的可能是ISO-8859-1或None。原因中国天气网的老接口和部分页面返回的是 GBK 或 GB2312 编码而 requests 默认按照响应头里的charset解码响应头没声明charset时requests 会退化成ISO-8859-1中文自然就废了。解决在读取text前强制指定编码优先用resp.encoding utf-8试一遍如果还是乱码再改成gbk。更省事的办法是用resp.apparent_encoding让 requests 根据字节内容猜编码但这个方法在大文本上有点慢接口场景直接手动指定就行。4.2 请求被拒403 或返回“访问过于频繁”现象浏览器打开接口地址一切正常脚本一请求就 403或者返回一段“系统繁忙请稍后再试”的 HTML。原因服务器对请求头做了校验默认的python-requests/2.xUA 会被直接拦掉有些路径还会校验 Referer。解决请求头里带上完整的 Chrome UA并加上Referer: https://www.weather.com.cn/。这是最低成本的解决办法九成 403 都是这么救回来的。如果加了 UA 还不行检查一下是不是局域网出口 IP 被前面跑死的脚本打进了临时黑名单等十几分钟再试。4.3 接口时好时坏同一个脚本隔一段时间就超时现象脚本挂成定时任务后发现凌晨和午后容易超时重试一次又好了。原因d1.weather.com.cn背后不止一台服务器个别节点负载高时会丢请求另外长时间高频访问同一个域名防火墙会针对 IP 做临时限速。解决两件事一是把timeout从 3 秒加到 8 秒给慢响应留余量二是在脚本里加一次重试第一次超时就 sleep 2 秒再试一次连续两次失败才记录失败。用requests.Session()复用 TCP 连接也能减少握手次数对降低被限速的概率有帮助。4.4 城市 ID 没错但返回的永远是省城的数据现象想查山东青岛接口返回的name却是济南。原因城市 ID 搞错了。中国天气网的 ID 是 9 位后面 6 位里省级占 2 位、市级占 2 位、区县占 2 位某个数字写错就可能指向同省另一个城市。还有一种情况是网上流传的 ID 对照表和实际接口不一致比如把“青岛”的 ID 记成了“济南”。解决代码里别只打印temp务必同时打印name和id第一次跑全量城市时人工抽查几个点。像“朝阳”这种重名城市北京有、辽宁也有一定要在数据源里带上省份否则 ID 对不上语义。4.5 凌晨数据不更新实况停留在几小时前现象白天采集一切正常凌晨 1 点跑任务时发现time字段停在昨天晚上 10 点温度一条直线。原因实况数据在夜间有维护窗口部分站点的更新会延迟到凌晨 2 点以后。这不是脚本问题是数据源本身的时效边界。解决采集任务里加一个时效校验解析出time后和当前时间做差超过 2 小时就标记为“旧数据”不要拿旧值去触发告警。与其采一条脏数据不如漏采一次让下一次正常采集去覆盖。5. 进阶把天气采集做成定时落库的小系统单城市、单次采集跑通只是开始实际使用中要让数据产生价值至少得做到“定时采 能回溯”。我常用的做法是 SQLite 落库配合系统 crontab 调度三十行代码就能攒下三个月的历史数据后面做温度趋势、夜间低温告警都有据可查。表结构不需要复杂核心就是城市 ID、采集时间、温度、天气现象几个字段CREATE TABLE weather_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, city_id TEXT NOT NULL, city_name TEXT, temp TEXT, weather TEXT, fetch_time TEXT DEFAULT (datetime(now, localtime)) );插入逻辑很简单解析完字段后直接INSERT不需要 ORM。要注意的是把崩溃概率降到最低写入用executemany批量插避免每条都开事务定时任务里把输出重定向到日志文件方便事后查失败原因。crontab 配置大概是*/30 * * * * cd /path/to/project python3 fetch_weather.py weather.log 21解释一下为什么用 crontab 而不是脚本里while True sleepcrond 由系统托管脚本崩溃后下一个周期会自动拉起进程挂了也能自愈而 Python 里自己写的死循环一崩就彻底停摆还得靠外部看门狗。crontab 的另一个好处是天然支持“每 30 分钟整点触发”便于和数据库里的fetch_time对齐。取数据时的校验技巧是插入前把接口的time字段和本地时间做差超过 2 小时就当旧数据处理宁可少采一次也不脏库。这套方案我跑过几个月最深的教训是不要迷信任何一次成功请求接口字段会变、节点会挂、城市 ID 会选错解析脚本里多做一层get兜底、采集日志里多打印一个name都是给自己留后悔药。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

GaN栅极驱动基础:从参数窗口到电路设计的成败细节 2026/9/25 7:13:40

GaN栅极驱动基础:从参数窗口到电路设计的成败细节

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
MQTT服务器搭建实战:协议理解与跨平台部署 2026/9/25 7:13:08

MQTT服务器搭建实战:协议理解与跨平台部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Excel被保护单元格不支持此功能?一文读懂解锁与防护 2026/9/25 7:13:01

Excel被保护单元格不支持此功能?一文读懂解锁与防护

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
cuDF libcudf 类型分发器(utility_dispatcher)深度解析:从 `type_id` 到编译期 C++ 类型的运行时分发机制 2026/9/25 7:12:55

cuDF libcudf 类型分发器(utility_dispatcher)深度解析:从 `type_id` 到编译期 C++ 类型的运行时分发机制

数据分析数据工程机器学习 【免费下载链接】cudf cuDF - GPU DataFrame Library 项目地址: https://gitcode.com/gh_mirrors/cu/cudf 点击查看 免费下载 导读 本文围绕 libcudf 的 utility_dispatcher Doxygen 文档组(即 Type Dispatcher)…

阅读更多 →
XAgent 数据结构详解:TaskSearchTree 任务搜索树的实现原理与实战 2026/9/25 7:12:42

XAgent 数据结构详解:TaskSearchTree 任务搜索树的实现原理与实战

AI Agent大模型后端任务调度 【免费下载链接】XAgent An Autonomous LLM Agent for Complex Task Solving 项目地址: https://gitcode.com/gh_mirrors/xa/XAgent 点击查看 免费下载 TaskSearchTree 是 XAgent 内部用于组织"复杂任务求解过程"的核心树状数…

阅读更多 →
C#上位机温室监控系统:串口Modbus通信与数据联动实战 2026/9/25 7:12:36

C#上位机温室监控系统:串口Modbus通信与数据联动实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉