进阶向:自动化天气查询工具(API调用)

发布于:2025-08-03 ⋅ 阅读:(13) ⋅ 点赞:(0)

自动化天气查询工具(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 requests

api_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 datetime

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")

完整代码实现

将上述所有功能整合,形成完整的天气查询工具。代码结构清晰,包含错误处理、用户交互和数据持久化等完整功能。

import requests
import json
from datetime import datetime

def 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 None

def display_weather(data, city):
    if not data:
        return
    
    temperature = data["main"]["temp"] - 273.15
    humidity = 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":
            break
            
        weather_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.15
            save_history(city, temp_c)
        else:
            print("无法获取该城市的天气数据,请检查城市名称是否正确")

if __name__ == "__main__":
    main()

部署和使用

完成代码编写后,可以将其保存为.py文件(如weather_app.py),通过命令行运行:

python weather_app.py

程序启动后会提示输入城市名称,输入后即可查看该城市的实时天气信息。查询历史会自动保存到同目录下的weather_history.json文件中。

进阶学习方向

掌握了基础天气查询工具的开发后,可以考虑以下进阶方向:

  1. 开发图形用户界面(GUI),使用Tkinter或PyQt等库
  2. 将应用部署为Web服务,使用Flask或Django框架
  3. 添加天气预报功能,查询多天预报数据
  4. 实现异常天气提醒功能
  5. 开发手机APP版本,使用Kivy等跨平台框架
完整源码
import requests
import json
from datetime import datetime

def 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 None

def 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.15
    temp_min = main_data["temp_min"] - 273.15
    temp_max = main_data["temp_max"] - 273.15
    humidity = 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("感谢使用天气查询工具,再见!")
            break
            
        if user_input.lower() == "history":
            show_history()
            continue
            
        if not user_input:
            continue
            
        weather_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。

使用前请注意:

  1. 请确保将代码中的"你的API密钥"替换为实际的OpenWeatherMap API密钥
  2. 建议在开发环境下测试后再部署到生产环境
  3. API有调用频率限制,免费版每分钟60次,每小时1000次
  4. 如需获取历史天气数据,需要订阅付费计划

示例请求格式:

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"