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

自动化天气查询工具(API调用)完全指南

天气数据是日常生活中经常需要查询的信息之一。本教程将介绍如何使用Python编写一个自动化天气查询工具,通过调用开放的天气API获取实时天气数据。这个工具适合完全不懂编程的新手学习,将从最基础的环境搭建讲起,逐步实现完整的天气查询功能。

环境准备

在开始编写代码之前,需要确保计算机上已经安装了Python环境。Python是一种简单易学的编程语言,非常适合新手入门。可以从Python官网下载最新版本,安装过程保持默认选项即可。

安装完成后,打开命令提示符或终端,输入python --version检查是否安装成功。为了管理项目依赖,还需要安装pip工具,它是Python的包管理器。多数情况下,Python安装时会自动包含pip。

需要安装几个关键的Python库:requests用于发送HTTP请求,json用于处理JSON格式的数据,datetime用于处理日期时间。这些库可以通过以下命令安装:

bash 复制代码
pip install requests
获取API密钥

大多数天气数据服务都需要API密钥才能访问。OpenWeatherMap是一个提供免费天气API的服务,注册账户后可以获得免费的API密钥。访问OpenWeatherMap官网,完成注册流程,在个人仪表板中可以找到API密钥。

免费版的API有一定的调用限制,但对于个人学习和测试完全够用。API密钥是一个长字符串,需要妥善保管,不要直接暴露在公开的代码中。

基本API调用

理解HTTP请求是使用API的核心。API通常通过HTTP协议提供数据,最常见的请求方式是GET。请求需要包含必要的参数,如位置信息、API密钥等。

使用requests库发送GET请求非常简单:

python 复制代码
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数据包含丰富的天气信息,需要从中提取关键数据展示给用户。典型的天气数据包括温度、湿度、天气状况、风速等。

温度数据默认使用开尔文单位,需要转换为更常用的摄氏度:

python 复制代码
temperature = data["main"]["temp"] - 273.15
humidity = data["main"]["humidity"]
weather_desc = data["weather"][0]["description"]
wind_speed = data["wind"]["speed"]

数据解析后可以格式化为更友好的输出:

python 复制代码
print(f"当前天气: {weather_desc}")
print(f"温度: {temperature:.1f}°C")
print(f"湿度: {humidity}%")
print(f"风速: {wind_speed}m/s")
添加用户交互

基本的天气查询功能实现后,可以增加用户交互使工具更实用。使用input函数让用户输入要查询的城市:

python 复制代码
city = input("请输入要查询的城市名称: ")

为了处理用户输入可能导致的错误,如城市不存在或API请求失败,需要添加异常处理:

python 复制代码
try:
    response = requests.get(url)
    response.raise_for_status()
    data = response.json()
except requests.exceptions.RequestException as e:
    print(f"获取天气数据失败: {e}")
    exit()
美化输出格式

原始的控制台输出比较简陋,可以通过添加分隔线和颜色来改善显示效果。虽然控制台本身不支持富文本,但可以使用ANSI颜色代码:

python 复制代码
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")
扩展功能

基础功能完成后,可以考虑添加更多实用功能。例如,查询多个城市的天气、保存查询历史、设置温度单位等。

多城市查询可以通过循环实现:

python 复制代码
cities = ["北京", "上海", "广州"]
for city in cities:
    # 查询每个城市的天气
    ...

添加历史记录功能需要将每次查询的结果保存到文件或数据库中。简单的文件存储实现:

python 复制代码
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")
完整代码实现

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

python 复制代码
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),通过命令行运行:

bash 复制代码
python weather_app.py

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

进阶学习方向

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

  1. 开发图形用户界面(GUI),使用Tkinter或PyQt等库
  2. 将应用部署为Web服务,使用Flask或Django框架
  3. 添加天气预报功能,查询多天预报数据
  4. 实现异常天气提醒功能
  5. 开发手机APP版本,使用Kivy等跨平台框架
完整源码
python 复制代码
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. 如需获取历史天气数据,需要订阅付费计划

示例请求格式:

python 复制代码
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"
相关推荐
荣--18 小时前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森19 小时前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜1 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB2 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode4 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220705 天前
如何搭建本地yum源(上)
运维
大树887 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠7 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质8 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工8 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信