简介
python天气查询小程序是一份面向python初学者的入门代码示例,适合希望快速掌握网络请求、api数据解析和命令行交互的开发者。资源以天气api调用为核心,完整演示了requests库发送get请求、json模块解析返回的温度/湿度/风速等字段、sys.argv接收命令行参数并切换查询城市等关键操作,也含有简单的错误处理思路,能够帮助读者理解一个请求-解析-展示闭环的完整结构。压缩包共2个文件,包含一个tq.py主程序和一个cityindex.db城市索引数据库,整体大小仅31kb,结构简明,便于直接运行、逐行拆解和二次修改。目前已有459人学习下载。通过学习该小程序,读者既能获得可直接使用的天气查询工具源码,也能对照城市索引数据库的设计,掌握本地数据与在线接口的联动方式,练习用python封装可复用函数,为后续编写更复杂的爬虫或信息服务工具打下基础。 写python天气查询小程序这件事,其实比大多数人想象的要简单得多。你不需要注册什么复杂的服务,也不用申请一堆密钥,把核心代码控制在几十行以内,就能在命令行里用中文查全球任意城市的实时天气。这篇文章我直接把完整思路、代码、运行方式、扩展方向以及我踩过的坑一次讲清楚,适合刚学完python基础语法、想找个练手项目的人,也适合想快速做一个内部小工具的开发朋友。
1. 项目思路拆解:天气数据从哪来,程序怎么组织
1.1 先搞清楚“python小程序”是哪一种形态
很多朋友看到“小程序”两个字,第一反应是微信小程序,会问是不是要用javascript和wxml写前端。这里需要先厘清概念。用python写的“天气查询小程序”,在我理解里通常是两种形态:一种是纯命令行/桌面的小工具,你输入城市名,它把天气打印出来;另一种是给微信小程序做后端接口,小程序前端用微信自带的语法写,python用flask或fastapi提供一个天气查询api。
这两种形态本身不冲突。核心的天气获取逻辑,也就是“给一个城市名,返回结构化天气数据”这部分,完全用python实现,而且可以复用到两种场景里。所以这篇博文我优先讲清楚这个最核心的部分,它既是独立可用的命令行工具,也能很轻松改造成http接口。
我见过不少新手一上来就纠结“到底要不要学前端”,结果卡在环境配置上。我的建议是先做命令行版本,把请求、解析、异常处理这三个基本功练扎实,再谈网页化和小程序化。底层能力一旦具备了,换个壳是非常快的事情。
1.2 免费天气api选型对比
天气数据肯定不能自己造,必须借助现成的天气服务接口。做这个项目时我对比了几个常见的免费方案,这里直接给结论。
| api服务 | 是否需要注册key | 返回格式 | 中文支持 | 免费额度 | 适合场景 |
|---|---|---|---|---|---|
| wttr.in | 不需要 | json/文本/png | 支持, lang=zh | 无严格限制 | 个人工具、快速演示 |
| 和风天气 | 需要 | json | 支持 | 每日几千次 | 真实小程序后端 |
| 高德天气 | 需要 | json | 支持 | 每日有限额 | 国内项目 |
| openweathermap | 需要 | json | 普通支持 | 每分钟60次 | 海外项目 |
日常做练手项目会首选wttr.in,因为它不需要注册、不需要key,直接通过url就能拿到全球城市的天气,而且支持中文输出。这一点对新手极其友好,意味着你把代码拿过去就能直接跑,不需要额外申请任何账号。和风天气和高德天气虽然在国内环境更稳定,但注册、鉴权、配额这些前置步骤会劝退很多刚开始接触项目的人。
wttr.in背后用的是openweathermap等气象数据源,覆盖全球范围,城市名可以直接用中文,比如 https://wttr.in/北京?format=j1&lang=zh 。 format=j1 表示返回完整的json格式, lang=zh 把天气描述转换成中文。这个组合是我实测下来最稳定的请求参数。
1.3 技术栈与目录结构
这个项目的依赖非常简单,主要就两个:python 3.8以上的解释器,以及 requests 库。标准库里的 urllib 也能发http请求,但写法啰嗦,异常处理也不如 requests 顺手,所以我选择后者。
整个项目我建议就一个文件搞定,不需要建包,不需要拆分模块。这种小工具的核心价值在于“跑得起来”,目录结构越简单越好。如果你后续要扩展成后端服务,再拆成 weather_client.py 和 api.py 也不迟。
weather_cli/
├── weather.py # 主程序,包含请求与解析逻辑
└── requirements.txt # 内容就一行:requests
我在本地一般用虚拟环境,避免把全局python环境搞乱,但其实这个项目只有一个第三方库,直接装在全局环境也没问题。这个选择很个人化,不必过度设计。
2. 核心代码实现:requests请求加json解析
2.1 环境准备与依赖安装
开始之前先确认python环境没问题。在终端里运行下面两条命令,看到版本号就说明环境ok。
python --version pip --version
然后安装 requests 库,顺手把依赖清单也写好:
pip install requests echo "requests" > requirements.txt
有些朋友在windows上会遇到 python 命令找不到的情况,多半是安装python时没勾选“add python to path”。这个很简单,重新运行python安装包,勾上对应选项再装一遍即可。另外,装了anaconda的朋友直接用conda环境也可以,不需要额外配置。
2.2 完整代码展示
下面这段代码是整个天气查询小程序的核心,我在实际使用中反复改过几版,保留了最精简可靠的逻辑:
import requests
import sys
from urllib.parse import quote
def get_weather(city: str) -> dict:
"""请求天气接口,返回解析后的json字典"""
url = f"https://wttr.in/{quote(city)}?format=j1&lang=zh"
try:
resp = requests.get(url, timeout=10)
resp.raise_for_status()
return resp.json()
except requests.timeout:
print("[错误] 请求超时,请检查网络后重试")
except requests.requestexception as e:
print(f"[错误] 请求失败: {e}")
return {}
def format_current(current: dict) -> str:
"""格式化当前天气信息"""
temp = current["temp_c"]
feels = current["feelslikec"]
humidity = current["humidity"]
wind = current["windspeedkmph"]
desc = current["lang_zh"][0]["value"] if "lang_zh" in current else current["weatherdesc"][0]["value"]
return (
f"当前温度: {temp}°c\n"
f"体感温度: {feels}°c\n"
f"天气状况: {desc}\n"
f"相对湿度: {humidity}%\n"
f"风速: {wind} km/h"
)
def format_forecast(weather: list) -> str:
"""格式化未来三天预报"""
lines = ["\n未来三天预报:"]
for day in weather[:3]:
date = day["date"]
mintemp = day["mintempc"]
maxtemp = day["maxtempc"]
desc = day["hourly"][0]["lang_zh"][0]["value"] if "lang_zh" in day["hourly"][0] else day["hourly"][0]["weatherdesc"][0]["value"]
lines.append(f"{date}: {desc}, {mintemp}°c ~ {maxtemp}°c")
return "\n".join(lines)
def main():
if len(sys.argv) > 1:
city = " ".join(sys.argv[1:])
else:
city = input("请输入城市名: ").strip()
if not city:
print("城市名不能为空")
return
data = get_weather(city)
if not data:
return
current = data["current_condition"][0]
print(f"\n{city} 实时天气:")
print(format_current(current))
print(format_forecast(data["weather"]))
if __name__ == "__main__":
main()
你可能会注意到我用了 urllib.parse.quote 对城市名做url编码,这是个细节但很关键。直接拼url遇到中文城市名会出问题,encode之后才能保证请求正确。
2.3 关键逻辑为什么这么写
get_weather 函数里的 timeout=10 不是随便写的。如果不设超时,程序在网络异常时可能卡住很久,用户会觉得像死机。我实测正常请求一般在1到2秒内返回,设置10秒很合理,既能应对慢网络,又不会让用户等太久。
raise_for_status() 的作用是检查http状态码,遇到404、500之类的错误直接抛异常,避免拿到一个错误页面后继续解析导致更隐蔽的报错。这一步看起来简单,但能帮你省掉大量排查问题的时间。
解析部分用到了wttr.in返回的两个核心字段: current_condition 是当前天气, weather 是未来多天预报。实际接口返回的结构比我这里展示的要复杂,有很多冗余字段,我只挑了最常用的五个维度:温度、体感、天气描述、湿度、风速。天气描述字段里有个坑,默认返回英文,只有加了 lang=zh 才会返回 lang_zh 数组。我在代码里做了兼容,万一某天接口调整,没有 lang_zh 就回退到英文描述。
3. 实操运行与功能扩展
3.1 第一次运行:交互式与命令行参数
代码写完后,运行方式有两种。第一种是直接执行然后输入城市名:
python weather.py
程序会提示“请输入城市名”,输入“北京”或“上海”回车,几秒后就能看到输出。第二种是带命令行参数直接查:
python weather.py 北京 python weather.py new york
输出效果大致长这样:
北京 实时天气:
当前温度: 18°c
体感温度: 18°c
天气状况: 晴
相对湿度: 23%
风速: 11 km/h
未来三天预报:
2025-01-05: 晴, -4°c ~ 6°c
2025-01-06: 多云, -3°c ~ 7°c
2025-01-07: 阴, -2°c ~ 5°c
我平时使用更习惯带参数的方式,因为可以配合别名直接敲 tq 北京 这样简短的命令。在linux或macos的shell配置里加一行 alias tq='python3 ~/weather_cli/weather.py' ,终端直接输 tq 北京 就出结果,非常顺手。
3.2 扩展一:多城市连续查询
命令行版本满足日常查询没问题,但如果你想一次看多个城市,可以写一个简易的批量模式。思路很简单,把命令行参数当成多个城市名进行遍历:
def main():
cities = sys.argv[1:] or [input("请输入城市名: ").strip()]
for city in cities:
data = get_weather(city)
if data:
current = data["current_condition"][0]
print(f"\n{city} 实时天气:")
print(format_current(current))
print(format_forecast(data["weather"]))
这个版本需要注意,城市名如果有空格,比如“new york”,命令行传入时要加引号: python weather.py "new york" 。否则会被拆成两个参数,请求自然报错。
3.3 扩展二:做成一个简易http接口
如果你的最终目的是给微信小程序或网页前端做后端服务,改动也不复杂。用一个轻量级web框架包一层就行,我常用的是flask,因为足够简单:
from flask import flask, jsonify, request
from weather import get_weather, format_current, format_forecast
app = flask(__name__)
@app.route("/weather")
def weather():
city = request.args.get("city", "")
if not city:
return jsonify({"error": "city parameter is required"}), 400
data = get_weather(city)
if not data:
return jsonify({"error": "failed to fetch weather"}), 502
current = data["current_condition"][0]
return jsonify({
"city": city,
"current": format_current(current),
"forecast": format_forecast(data["weather"])
})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
这样前端只需要请求 /weather?city=北京 就能拿到格式化好的内容。这里我在自己的实践中发现, format_current 返回的是带换行的纯文本,如果前端要做自定义ui,更好的做法是直接返回原始json字段,比如 temp_c 、 humidity 这些,让前端去渲染。上面的代码只是为了快速演示,生产环境不要这么干,把原始数据透传给前端才是更合理的做法。
如果你确实要做微信小程序前端,需要知道微信小程序不能用python直接写,前端只能用微信自家的wxml、wxss和javascript。python能做的是后端api服务,以及处理一些数据清洗逻辑。支付功能这块需要申请商户资质,和python脚本本身关系不大,等后端服务稳定之后再考虑也不迟。
4. 常见问题与排查技巧实录
4.1 新手最容易踩的五个坑
第一个坑是windows控制台输出中文乱码。这个问题不是代码的问题,是控制台编码问题。python 3在windows上默认输出编码是gbk,而终端环境有时候是utf-8,导致中文字符显示成乱码。我踩过之后习惯在运行命令前加一句 chcp 65001 切换到utf-8代码页,或者用python 3.7以上版本直接加 -x utf8 参数:
python -x utf8 weather.py 北京
第二个坑是城市名不存在时程序没有友好提示。wttr.in对不存在的城市名通常会返回一个空结果或默认城市的数据,所以最好在 parse 之前做一层校验。实际开发中我还没有找到特别完美的兜底策略,主要靠判断返回数据里 current_condition 数组是否为空。你可以参考这个思路加一层判断,提示“城市不存在或无法解析”。
第三个坑是频繁请求被限流。免费接口虽然不需要key,但也有合理的请求频率限制。我之前写了个循环脚本连续查询几十个城市,结果中间开始大量超时。后来给每个请求之间加了 sleep(1) ,问题就解决了。自己用没问题,但别拿免费接口 做压力测试。
第四个坑是 requests 库的ssl证书报错。有些公司的内网环境会拦截证书,导致 requests.get 直接抛 sslerror 。如果只是个人学习用,可以在请求时加 verify=false 跳过证书校验,但会有安全提示,局域网环境里这是可以接受的。生产环境千万不要这么做。
第五个坑是代码里直接硬编码了接口地址,导致后期接口变更或需要切换数据源时,要改的地方太多。虽然这个项目很小,但建议还是把请求地址定义成常量,放在文件顶部。想换天气服务商的时候只需要改一行。
4.2 问题速查表与排查思路
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 中文城市名报错或返回空 | url未编码 | 用 urllib.parse.quote 处理城市名 |
| 输出中文乱码 | 控制台编码不对 | chcp 65001 或 python -x utf8 |
| 请求超时 | 网络问题或接口限流 | 增加 timeout 参数,请求间隔1秒 |
| 城市查不到 | 城市名拼写或用词不标准 | 尝试拼音、英文名或附近大城市 |
提示 modulenotfounderror | 未安装 requests | pip install requests |
排查这类问题我有一个固定的思路:先用curl直接请求接口,验证接口本身出没出问题。比如执行:
curl "https://wttr.in/北京?format=j1&lang=zh"
如果curl能正常返回json,说明接口没问题,问题就在python代码;如果curl也超时或报错,那就要先解决网络环境问题。这个方法帮我定位过大量“代码看起来没问题但就是跑不通”的诡异问题,强烈建议你也试试。
4.3 一点个人体会
做这个项目我最大的感受是,很多人学python卡在“学了语法不知道写什么”。天气查询小程序恰好是语法知识覆盖比较全面的小项目,字符串、字典、列表、函数、异常处理、第三方库、api调用全都能练到。而且它的正反馈特别快,你写完代码马上就能查询到真实的数据,这种成就感是纯刷练习题得不到的。
我现在把这段代码配合系统别名用了一两年,查天气基本不打开天气app了。后来又在 format_current 里加了一条 紫外线强度 的提示,出门前扫一眼心里有数。你完全可以根据自己的需求往里面加参数,wttr.in返回的数据里还有气压、能见度、云量、降雨概率等几十个字段,探索的过程本身就是学习。
到此这篇关于python调用天气api编写一个天气查询小程序的文章就介绍到这了,更多相关python天气查询内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论