Python 網路爬蟲 爬取現在天氣--python TKinter
https://data.gov.tw/dataset/9176
import tkinter as tk # 導入 tkinter 庫,用於建立 GUI 介面
from tkinter import ttk, messagebox, filedialog # 從 tkinter 導入 ttk(主題套件)、messagebox(訊息視窗)和 filedialog(檔案對話框)
import requests # 導入 requests 庫,用於發送 HTTP 請求
# --- 變數定義 ---
# API 網址,此為中央氣象署提供的範例授權碼。實際應用需替換成您自己的授權碼。
URL = "https://opendata.cwa.gov.tw/fileapi/v1/opendataapi/O-A0001-001?Authorization=rdec-key-123-45678-011121314&format=JSON"
# --- 函數定義 ---
def fetch_weather_data():
"""從中央氣象署 API 取得即時天氣觀測資料"""
try:
response = requests.get(URL) # 向 API 網址發送 GET 請求
response.raise_for_status() # 如果 HTTP 請求失敗(例如 404, 500),則引發錯誤
data = response.json() # 將 JSON 格式的回應轉換成 Python 字典
weather_data = [] # 建立一個空列表,用於存放處理後的觀測資料
# 根據提供的 JSON 結構,安全地修正資料解析路徑
cwa_data = data.get('cwaopendata', {}) # 嘗試取得 'cwaopendata' 鍵,若無則回傳空字典
dataset = cwa_data.get('dataset', {}) # 嘗試取得 'dataset' 鍵,若無則回傳空字典
locations = dataset.get('Station', []) # 嘗試取得 'Station' 鍵,若無則回傳空列表
if not locations: # 檢查 locations 列表是否為空
messagebox.showwarning("警告", "API 回應中未找到天氣觀測資料。") # 彈出警告視窗
return [] # 回傳空列表
for loc in locations: # 遍歷 locations 列表中的每個觀測站字典
station_name = loc.get('StationName', 'N/A') # 取得測站名稱,若無則為 'N/A'
geo_info = loc.get('GeoInfo', {}) # 取得地理資訊字典
county_name = geo_info.get('CountyName', 'N/A') # 取得縣市名稱
town_name = geo_info.get('TownName', 'N/A') # 取得行政區名稱
weather_elements = loc.get('WeatherElement', {}) # 取得氣象元素字典
air_temp = weather_elements.get('AirTemperature', 'N/A') # 取得氣溫
relative_humidity_raw = weather_elements.get('RelativeHumidity', 'N/A') # 取得相對濕度(原始值)
weather = weather_elements.get('Weather', 'N/A') # 取得天氣現象
wind_speed = weather_elements.get('WindSpeed', 'N/A') # 取得風速
air_pressure = weather_elements.get('AirPressure', 'N/A') # 取得氣壓
# 轉換並處理無效值
if relative_humidity_raw not in ('N/A', '-99'):
# 原始值已是百分比,直接格式化為字串
relative_humidity = f"{float(relative_humidity_raw):.2f}%"
else:
relative_humidity = 'N/A'
air_temp = f"{air_temp}°C" if air_temp not in ('N/A', '-99') else 'N/A' # 格式化氣溫
air_pressure = f"{air_pressure} hPa" if air_pressure not in ('N/A', '-99') else 'N/A' # 格式化氣壓
wind_speed = f"{wind_speed} m/s" if wind_speed not in ('N/A', '-99') else 'N/A' # 格式化風速
# 將處理後的資料組合成一個元組
weather_data.append((
station_name, county_name, town_name, air_temp, relative_humidity, weather, wind_speed, air_pressure
))
return weather_data # 回傳包含所有觀測站資料的列表
except requests.exceptions.RequestException as e:
# 如果請求過程中發生任何錯誤,顯示錯誤訊息
messagebox.showerror("錯誤", f"無法連線到 API,請檢查網路連線或 API 狀態。\n錯誤訊息: {e}")
return []
except Exception as e:
# 捕捉所有其他可能發生的錯誤(例如 JSON 解析錯誤),並顯示錯誤訊息
messagebox.showerror("錯誤", f"解析 API 資料失敗,請檢查資料結構。\n錯誤訊息: {e}")
return []
def create_treeview():
"""建立並設定 Treeview 元件"""
tree_frame = ttk.Frame(root) # 建立一個 ttk.Frame 作為 Treeview 的容器
tree_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True) # 將框架打包
columns = ('StationName', 'CountyName', 'TownName', 'AirTemperature', 'RelativeHumidity', 'Weather', 'WindSpeed', 'AirPressure')
global tree # 宣告 tree 為全域變數,以便在其他函數中使用
tree = ttk.Treeview(tree_frame, columns=columns, show='headings') # 建立 Treeview
# 設定表格標題
tree.heading('StationName', text='測站地點')
tree.heading('CountyName', text='城市')
tree.heading('TownName', text='行政區')
tree.heading('AirTemperature', text='氣溫')
tree.heading('RelativeHumidity', text='相對濕度')
tree.heading('Weather', text='天氣現象')
tree.heading('WindSpeed', text='風速')
tree.heading('AirPressure', text='氣壓')
# 設定表格欄位寬度
tree.column('StationName', width=120)
tree.column('CountyName', width=80)
tree.column('TownName', width=100)
tree.column('AirTemperature', width=80)
tree.column('RelativeHumidity', width=100)
tree.column('Weather', width=100)
tree.column('WindSpeed', width=80)
tree.column('AirPressure', width=80)
# 新增捲軸
scrollbar = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL, command=tree.yview)
tree.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y")
tree.pack(fill="both", expand=True)
return tree # 回傳建立好的 Treeview 元件
def update_treeview():
"""獲取資料並更新 Treeview"""
for item in tree.get_children():
tree.delete(item) # 清空舊資料
data = fetch_weather_data() # 呼叫 fetch_weather_data 獲取新資料
if data: # 檢查是否有資料
for row in data:
tree.insert('', 'end', values=row) # 將每一行新資料插入表格
if not data:
messagebox.showwarning("警告", "目前無可顯示的觀測資料。")
# --- 程式主體 ---
root = tk.Tk() # 建立主視窗物件
root.title("即時天氣觀測") # 設定視窗標題
root.geometry("1000x600") # 設定視窗大小
button_frame = ttk.Frame(root) # 建立一個框架來放置按鈕
button_frame.pack(pady=5) # 打包框架
update_button = ttk.Button(button_frame, text="獲取資料並更新", command=update_treeview) # 建立更新按鈕,點擊時執行 update_treeview 函數
update_button.pack(padx=5) # 打包按鈕
tree = create_treeview() # 建立 Treeview 來顯示資料
update_treeview() # 程式啟動時自動載入資料
root.mainloop() # 啟動 Tkinter 的事件主迴圈,保持視窗運行並響應使用者操作

沒有留言:
張貼留言