调用OpenWeatherMap API需规避限流、解析错误、时区混乱和单位混淆:从环境变量读取API密钥,指定units参数防开尔文误判,正确解析嵌套JSON字段,风速换算为km/h,用dt+timezone精准计算本地更新时间。

直接调用公开天气 API(如 OpenWeatherMap)就能拿到实时天气数据,但关键不是“能不能”,而是“怎么避免被限流、字段解析错、时区混乱或单位混淆”。
用 requests 调 OpenWeatherMap API 获取 JSON 数据
OpenWeatherMap 是最常用的免费天气接口,注册后能拿到 appid,每分钟 1000 次调用足够开发调试。别用未授权的 key 或硬编码在代码里——哪怕只是本地脚本,也建议从环境变量读取:
import os<br>import requests<br><br>API_KEY = os.getenv("OWM_API_KEY")<br>city = "Shanghai"<br>url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_KEY}&units=metric"
注意:units=metric 返回摄氏度,units=imperial 是华氏度;漏掉 units 默认是开尔文,数值会是 292.15 这种,容易误判为“温度异常”。
立即学习“Python免费学习笔记(深入)”;
解析 weather 和 main 字段时常见结构陷阱
返回 JSON 看似扁平,但嵌套层级容易看错。比如:
-
data["weather"][0]["main"]是天气主状态("Clouds"、"Rain"),不是data["weather"]["main"](会报TypeError: list indices must be integers) -
data["main"]["temp"]是当前气温,但data["main"]["feels_like"]才是体感温度——很多人直接打印temp就当“真实感受” -
data["wind"]["speed"]单位是 m/s,如果要 km/h 得乘 3.6;没注意单位直接展示,用户会以为风速只有“2”(其实是 7.2 km/h)
把 API 响应转成带格式的终端输出(不用 GUI 库)
想快速验证数据是否正确,没必要上 tkinter 或网页渲染。用字符串拼接+简单对齐更可控:
print(f"{city} 天气 ({data['name']}, {data['sys']['country']}):")<br>print(f"?️ 温度:{data['main']['temp']:.1f}°C (体感 {data['main']['feels_like']:.1f}°C)")<br>print(f"☁️ 天况:{data['weather'][0]['description'].title()}")<br>print(f"? 风速:{data['wind']['speed'] * 3.6:.1f} km/h")<br>print(f"? 湿度:{data['main']['humidity']}%")
这里 data['name'] 和 data['sys']['country'] 用于校验定位是否准确——比如搜 “Beijing”,返回 city name 是 “Beijing” 但 country 是 “CN”,说明没被重定向到其他同名城市;如果返回 “Beijing” + “US”,那大概率是美国宾州的小镇,不是你要的北京。
本地时间显示必须用 data["dt"] + data["timezone"] 计算
API 返回的 dt 是 Unix 时间戳(秒级),但它对应的是服务器时间(UTC),而 timezone 字段才是该城市相对于 UTC 的秒偏移量(比如上海是 28800,即 +8 小时)。别直接用 datetime.fromtimestamp(data["dt"]),那默认按你本机时区解释,部署到服务器可能完全对不上。
正确做法是:
from datetime import datetime, timezone<br>utc_time = datetime.fromtimestamp(data["dt"], tz=timezone.utc)<br>local_time = utc_time.astimezone(timezone(timedelta(seconds=data["timezone"])))<br>print(f"? 更新时间:{local_time.strftime('%Y-%m-%d %H:%M')}")
这个细节一旦忽略,用户看到的“更新时间”可能比实际晚 8 小时,还以为 API 没刷新。


















