You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter天气项目API故障求助:OpenWeatherMap调用报KeyError

Tkinter天气项目API问题解决指南

问题概述

用Tkinter开发Python GUI天气项目时,使用OpenWeatherMap API出现KeyError: 'weather'错误,无法正常获取天气数据。

错误信息

Traceback (most recent call last):
  File "C:\Users\Hania\Desktop\ppp\WeatherApp.py", line 53,  in <module>
    condition = response['weather'][0]['main']
KeyError: 'weather'

核心问题分析

你的代码存在几个关键问题,并非单纯API不可用:

  1. API接口调用错误:OpenWeatherMap的/data/3.0/onecall接口需要传入经纬度(lat、lon)参数,而非直接拼接城市名,这会导致请求返回错误响应,自然没有weather字段。
  2. 请求时机错误:API请求代码写在全局作用域,程序启动时就会执行,此时输入框textfield为空,请求的城市参数无效。
  3. 未处理响应错误:没有判断API返回的状态,比如当请求失败时,响应里会包含cod错误码,而非天气数据。
  4. API Key未正确替换:代码里的"my api key"需要替换成你在OpenWeatherMap官网申请的有效密钥。

修复方案

1. 修正API调用逻辑

将API请求移到getWeather函数内,先通过geopy获取城市经纬度,再调用接口;或者改用更适合按城市名查询的/data/2.5/weather接口。以下是完整修复代码:

2. 修正后的完整代码

from tkinter import *
import tkinter as tk
from geopy.geocoders import Nominatim
from tkinter import ttk, messagebox
from timezonefinder import TimezoneFinder
from datetime import datetime
import requests
import pytz
import json


root = Tk()
root.title("Weather")
root.geometry("900x500+300+200")
root.config(bg = "lightgrey")
root.resizable(True, False)

# search box
Search_image = PhotoImage(file = "Copy of search.png")
myimage = Label(image = Search_image)
myimage.place(x = 20, y = 20) 

def getWeather():
    try:
        city = textfield.get().strip()
        if not city:
            messagebox.showwarning("提示", "请输入城市名称")
            return
        
        # 获取时区和当地时间
        geolocator = Nominatim(user_agent = "geopiExercises")
        location = geolocator.geocode(city)
        if not location:
            messagebox.showerror("错误", "未找到该城市")
            return
        
        obj = TimezoneFinder()
        result = obj.timezone_at(lng = location.longitude, lat = location.latitude)
        home = pytz.timezone(result)
        local_time = datetime.now(home)
        current_time = local_time.strftime("%I:%M:%p")
        clock.config(text = current_time)
        name.config(text = "CURRENT TIME")
        
        # 获取天气数据
        api_key = "你的有效API密钥"  # 替换为自己的API Key
        # 使用按城市名查询的weather接口,units=metric直接返回摄氏度
        api = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units=metric"
        json_data = requests.get(api)
        response = json_data.json()
        
        # 检查响应是否成功
        if response.get("cod") != 200:
            messagebox.showerror("错误", response.get("message", "获取天气数据失败"))
            return
        
        # 提取天气数据
        condition = response['weather'][0]['main']
        description = response['weather'][0]['description']
        temp = int(response['main']['temp'])
        pressure = response['main']['pressure']
        humidity = response['main']['humidity']
        wind = response['wind']['speed']
        
        # 更新UI显示
        t.config(text = f"{temp}°")
        c.config(text = f"{condition} | FEELS LIKE {temp}°")
        w.config(text = f"{wind} m/s")
        w2.config(text = f"{humidity} %")
        w3.config(text = description.title())
        w4.config(text = f"{pressure} hPa")
        
    except Exception as e:
        messagebox.showerror("错误", f"程序出错:{str(e)}")

textfield = tk.Entry(root, justify = "center", width = 22,font = ("poppins",25,"bold" ), bg = "#404040", border = 0, fg = "white") 
textfield.place(x = 54, y = 40)
textfield.focus()


Search_icon = PhotoImage(file = "Copy of search_icon.png")
myimage2 = Button(image = Search_icon,borderwidth = 0,cursor = "hand2", bg = "#404040", command = getWeather )
myimage2.place(x = 380, y = 33)


#logo
Logo_image = PhotoImage(file = "logo.png")
myimage3 = Label(image = Logo_image)
myimage3.place(x = 150, y = 100)


# Bottom box
Frame_image = PhotoImage(file = "Copy of box.png")
myimage4 = Label(image = Frame_image)
myimage4.pack(padx = 5, pady = 5, side = BOTTOM)

# time
name = Label(root, font = ("arial",15 , "bold"))
name.place(x = 30, y = 100)
clock = Label(root, font = ("Helvetica", 20,"bold"))
clock.place(x = 30, y = 120)
# Label
label1 = Label(root, text = "WIND", font = ("Helvetica",15,"bold"), fg = "white", bg = "#1ab5ef")
label1.place(x = 120, y = 400)

label2 = Label(root, text = "HUMIDITY", font =  ("Helvetica",15,"bold"), fg = "white", bg = "#1ab5ef")
label2.place(x = 250, y = 400)

label3 = Label(root, text = "CONDITION", font = ("Helvetica",15,"bold"), fg = "white", bg = "#1ab5ef")
label3.place(x = 430, y = 400)

label4 = Label(root, text = "PRESSURE", font = ("Helvetica",15,"bold"), fg = "white", bg = "#1ab5ef")
label4.place(x = 650, y = 400)

t = Label(font = ("arial", 70, "bold"), fg = "#ee666d")
t.place(x = 400, y = 150 )
c = Label(font = ("arial", 15, "bold"))
c.place(x = 400, y = 250 )

w = Label(text = "...", font = ("arial", 20, "bold"), bg = "#1ab5ef")
w.place(x = 130 , y = 430)

w2 = Label(text = "...", font = ("arial", 20, "bold"), bg = "#1ab5ef")
w2.place(x = 280 , y = 430)

w3 = Label(text = "...", font = ("arial", 20, "bold"), bg = "#1ab5ef")
w3.place(x = 450 , y = 430)

w4 = Label(text = "...", font = ("arial", 20, "bold"), bg = "#1ab5ef")
w4.place(x = 670 , y = 430)
root.mainloop()

3. 关键修改点

  • 将天气请求逻辑移入getWeather函数,点击搜索按钮时才执行
  • 使用/data/2.5/weather接口,支持直接按城市名查询,添加units=metric直接获取摄氏度
  • 添加错误处理:判断城市输入、地理编码结果、API响应状态
  • 更新UI元素的动态赋值,原代码中天气数据是全局初始化时赋值,现在改为在获取数据后更新

替代免费API推荐

如果OpenWeatherMap仍有问题,可以尝试以下免费选项:

  • Open-Meteo:无需API密钥,支持经纬度查询天气数据,免费额度充足
  • 和风天气:国内城市数据更准确,免费版提供基础天气查询功能

内容的提问来源于stack exchange,提问作者Hania Asim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 21:57:08