2025年8月11日 星期一

Python 網路爬蟲 爬取現在天氣--python TKinter

 Python 網路爬蟲  爬取現在天氣--python TKinter


https://data.gov.tw/dataset/9176


資料資源欄位
StationName、StationId、DateTime、CoordinateName、CoordinateFormat、StationLatitude、StationLongitude、StationAltitude、CountyName、TownName、CountyCode、TownCode、Weather、Precipitation、WindDirection、WindSpeed、AirTemperature、RelativeHumidity、AirPressure、PeakGustSpeed
檔案格式
JSON
編碼格式
UTF-8
資料量
0
資料資源描述
無人自動站氣象資料


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 的事件主迴圈,保持視窗運行並響應使用者操作


沒有留言:

張貼留言

ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite

 ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite  ESP32 VS Code 程式 ; PlatformIO Project Configuration File ; ;   Build op...