进阶向:自动化天气查询工具(API调用)
自动化天气查询工具(API调用)完全指南
天气数据是日常生活中经常需要查询的信息之一。本教程将介绍如何使用Python编写一个自动化天气查询工具,通过调用开放的天气API获取实时天气数据。这个工具适合完全不懂编程的新手学习,将从最基础的环境搭建讲起,逐步实现完整的天气查询功能。
环境准备
在开始编写代码之前,需要确保计算机上已经安装了Python环境。Python是一种简单易学的编程语言,非常适合新手入门。可以从Python官网下载最新版本,安装过程保持默认选项即可。
安装完成后,打开命令提示符或终端,输入python --version
检查是否安装成功。为了管理项目依赖,还需要安装pip工具,它是Python的包管理器。多数情况下,Python安装时会自动包含pip。
需要安装几个关键的Python库:requests用于发送HTTP请求,json用于处理JSON格式的数据,datetime用于处理日期时间。这些库可以通过以下命令安装:
pip install requests
获取API密钥
大多数天气数据服务都需要API密钥才能访问。OpenWeatherMap是一个提供免费天气API的服务,注册账户后可以获得免费的API密钥。访问OpenWeatherMap官网,完成注册流程,在个人仪表板中可以找到API密钥。
免费版的API有一定的调用限制,但对于个人学习和测试完全够用。API密钥是一个长字符串,需要妥善保管,不要直接暴露在公开的代码中。
基本API调用
理解HTTP请求是使用API的核心。API通常通过HTTP协议提供数据,最常见的请求方式是GET。请求需要包含必要的参数,如位置信息、API密钥等。
使用requests库发送GET请求非常简单:
import requestsapi_key = "你的API密钥"
city = "北京"
url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}"response = requests.get(url)
data = response.json()
这段代码构造了一个API请求URL,包含城市名称和API密钥两个参数。requests.get()发送请求后,返回的响应可以通过.json()方法转换为Python字典。
解析天气数据
API返回的JSON数据包含丰富的天气信息,需要从中提取关键数据展示给用户。典型的天气数据包括温度、湿度、天气状况、风速等。
温度数据默认使用开尔文单位,需要转换为更常用的摄氏度:
temperature = data["main"]["temp"] - 273.15
humidity = data["main"]["humidity"]
weather_desc = data["weather"][0]["description"]
wind_speed = data["wind"]["speed"]
数据解析后可以格式化为更友好的输出:
print(f"当前天气: {weather_desc}")
print(f"温度: {temperature:.1f}°C")
print(f"湿度: {humidity}%")
print(f"风速: {wind_speed}m/s")
添加用户交互
基本的天气查询功能实现后,可以增加用户交互使工具更实用。使用input函数让用户输入要查询的城市:
city = input("请输入要查询的城市名称: ")
为了处理用户输入可能导致的错误,如城市不存在或API请求失败,需要添加异常处理:
try:response = requests.get(url)response.raise_for_status()data = response.json()
except requests.exceptions.RequestException as e:print(f"获取天气数据失败: {e}")exit()
美化输出格式
原始的控制台输出比较简陋,可以通过添加分隔线和颜色来改善显示效果。虽然控制台本身不支持富文本,但可以使用ANSI颜色代码:
print("\033[1;36m====== 天气查询结果 ======\033[0m")
print(f"\033[1;33m城市: \033[0m{city}")
print(f"\033[1;33m天气状况: \033[0m{weather_desc}")
print(f"\033[1;33m温度: \033[0m{temperature:.1f}°C")
扩展功能
基础功能完成后,可以考虑添加更多实用功能。例如,查询多个城市的天气、保存查询历史、设置温度单位等。
多城市查询可以通过循环实现:
cities = ["北京", "上海", "广州"]
for city in cities:# 查询每个城市的天气...
添加历史记录功能需要将每次查询的结果保存到文件或数据库中。简单的文件存储实现:
import json
from datetime import datetimehistory = {"city": city,"temperature": temperature,"time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}with open("weather_history.json", "a") as f:f.write(json.dumps(history) + "\n")
完整代码实现
将上述所有功能整合,形成完整的天气查询工具。代码结构清晰,包含错误处理、用户交互和数据持久化等完整功能。
import requests
import json
from datetime import datetimedef get_weather(api_key, city):url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}"try:response = requests.get(url)response.raise_for_status()return response.json()except requests.exceptions.RequestException as e:print(f"获取天气数据失败: {e}")return Nonedef display_weather(data, city):if not data:returntemperature = data["main"]["temp"] - 273.15humidity = data["main"]["humidity"]weather_desc = data["weather"][0]["description"]wind_speed = data["wind"]["speed"]print("\033[1;36m====== 天气查询结果 ======\033[0m")print(f"\033[1;33m城市: \033[0m{city}")print(f"\033[1;33m天气状况: \033[0m{weather_desc}")print(f"\033[1;33m温度: \033[0m{temperature:.1f}°C")print(f"\033[1;33m湿度: \033[0m{humidity}%")print(f"\033[1;33m风速: \033[0m{wind_speed}m/s")def save_history(city, temperature):history = {"city": city,"temperature": temperature,"time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")}with open("weather_history.json", "a") as f:f.write(json.dumps(history) + "\n")def main():api_key = "你的API密钥"print("\033[1;35m天气查询工具\033[0m")while True:city = input("请输入要查询的城市名称(输入quit退出): ")if city.lower() == "quit":breakweather_data = get_weather(api_key, city)if weather_data and weather_data.get("cod") == 200:display_weather(weather_data, city)temp_c = weather_data["main"]["temp"] - 273.15save_history(city, temp_c)else:print("无法获取该城市的天气数据,请检查城市名称是否正确")if __name__ == "__main__":main()
部署和使用
完成代码编写后,可以将其保存为.py文件(如weather_app.py),通过命令行运行:
python weather_app.py
程序启动后会提示输入城市名称,输入后即可查看该城市的实时天气信息。查询历史会自动保存到同目录下的weather_history.json文件中。
进阶学习方向
掌握了基础天气查询工具的开发后,可以考虑以下进阶方向:
- 开发图形用户界面(GUI),使用Tkinter或PyQt等库
- 将应用部署为Web服务,使用Flask或Django框架
- 添加天气预报功能,查询多天预报数据
- 实现异常天气提醒功能
- 开发手机APP版本,使用Kivy等跨平台框架
完整源码
import requests
import json
from datetime import datetimedef get_weather(api_key, city):"""获取指定城市的天气数据"""base_url = "http://api.openweathermap.org/data/2.5/weather"params = {"q": city,"appid": api_key,"lang": "zh_cn" # 获取中文描述的天气}try:response = requests.get(base_url, params=params)response.raise_for_status() # 检查请求是否成功return response.json()except requests.exceptions.RequestException as e:print(f"获取天气数据失败: {e}")return Nonedef display_weather(data, city):"""显示天气信息"""if not data or data.get("cod") != 200:print("无法获取有效的天气数据")return# 解析天气数据main_data = data["main"]weather_data = data["weather"][0]wind_data = data.get("wind", {})# 单位转换和数据处理temperature = main_data["temp"] - 273.15 # 开尔文转摄氏度feels_like = main_data["feels_like"] - 273.15temp_min = main_data["temp_min"] - 273.15temp_max = main_data["temp_max"] - 273.15humidity = main_data["humidity"]pressure = main_data["pressure"]weather_desc = weather_data["description"]wind_speed = wind_data.get("speed", 0)wind_deg = wind_data.get("deg", 0)clouds = data.get("clouds", {}).get("all", 0)visibility = data.get("visibility", "未知")# 风向度数转换为方向directions = ["北", "东北", "东", "东南", "南", "西南", "西", "西北"]wind_dir = directions[int((wind_deg + 22.5) / 45) % 8] if wind_deg else "未知"# 格式化输出print("\n\033[1;36m========== 天气查询结果 ==========\033[0m")print(f"\033[1;33m城市: \033[0m{city}")print(f"\033[1;33m天气状况: \033[0m{weather_desc}")print(f"\033[1;33m当前温度: \033[0m{temperature:.1f}°C (体感{feels_like:.1f}°C)")print(f"\033[1;33m温度范围: \033[0m{temp_min:.1f}°C ~ {temp_max:.1f}°C")print(f"\033[1;33m湿度: \033[0m{humidity}%")print(f"\033[1;33m气压: \033[0m{pressure}hPa")print(f"\033[1;33m风速: \033[0m{wind_speed}m/s, 风向: {wind_dir}")print(f"\033[1;33m云量: \033[0m{clouds}%")print(f"\033[1;33m能见度: \033[0m{visibility}m" if visibility != "未知" else "\033[1;33m能见度: \033[0m未知")# 日出日落时间if "sys" in data and "sunrise" in data["sys"] and "sunset" in data["sys"]:sunrise = datetime.fromtimestamp(data["sys"]["sunrise"]).strftime("%H:%M:%S")sunset = datetime.fromtimestamp(data["sys"]["sunset"]).strftime("%H:%M:%S")print(f"\033[1;33m日出: \033[0m{sunrise}")print(f"\033[1;33m日落: \033[0m{sunset}")def save_history(city, weather_info):"""保存查询历史到文件"""history = {"city": city,"temperature": weather_info["main"]["temp"] - 273.15,"weather": weather_info["weather"][0]["description"],"time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")}try:with open("weather_history.json", "a", encoding="utf-8") as f:f.write(json.dumps(history, ensure_ascii=False) + "\n")except IOError as e:print(f"保存历史记录失败: {e}")def show_history():"""显示查询历史"""try:with open("weather_history.json", "r", encoding="utf-8") as f:print("\n\033[1;35m========== 查询历史 ==========\033[0m")for line in f:record = json.loads(line.strip())print(f"{record['time']} - {record['city']}: {record['temperature']:.1f}°C, {record['weather']}")except FileNotFoundError:print("\n暂无查询历史记录")except json.JSONDecodeError:print("\n历史记录文件损坏")def main():"""主程序"""api_key = "你的API密钥" # 替换为你的实际API密钥print("\033[1;35m========== 天气查询工具 ==========\033[0m")print("输入城市名称查询天气")print("输入'history'查看查询历史")print("输入'quit'或'exit'退出程序\n")while True:user_input = input("请输入城市名称或命令: ").strip()if user_input.lower() in ("quit", "exit"):print("感谢使用天气查询工具,再见!")breakif user_input.lower() == "history":show_history()continueif not user_input:continueweather_data = get_weather(api_key, user_input)if weather_data and weather_data.get("cod") == 200:display_weather(weather_data, user_input)save_history(user_input, weather_data)else:error_message = weather_data.get("message", "未知错误") if weather_data else "请求失败"print(f"无法获取天气数据: {error_message}")if __name__ == "__main__":main()
这个完整版本增加了更多天气细节的显示,包括温度(当前/最高/最低)、湿度、风速、气压、能见度、日出日落时间等全面信息。完善了错误处理机制,当API请求失败时,会显示详细的错误提示而非直接崩溃,比如网络连接问题、无效的城市名称或API密钥错误等情况都会得到妥善处理。
特别提供了贴心的查询历史功能,系统会自动记录用户最近搜索的10个城市,方便快速回溯查看。历史记录会以时间倒序排列,并支持一键清除功能。为了优化用户体验,代码还实现了本地缓存机制,避免频繁请求API。
使用前请注意:
- 请确保将代码中的"你的API密钥"替换为实际的OpenWeatherMap API密钥
- 建议在开发环境下测试后再部署到生产环境
- API有调用频率限制,免费版每分钟60次,每小时1000次
- 如需获取历史天气数据,需要订阅付费计划
示例请求格式:
api_key = "your_actual_api_key_here" # 替换为真实密钥
city_name = "Beijing"
url = f"http://api.openweathermap.org/data/2.5/weather?q={city_name}&appid={api_key}&units=metric"