目錄

臺灣歷次颱風資料下載

封面圖片為下載的颱風衛星影像,由中央氣象署以 CCU/SSL 製作之衛星水氣雲圖,影像拍攝時間為 2026 年 7 月 11 日 07:10 ,取自中國文化大學大氣與地質科學系天氣圖庫(大氣科學研究與應用資料庫)。

這是一支過去為了下載颱風衛星影像及相關資料而隨手撰寫的小程式,最初的目的是作為影像辨識資料蒐集之用。由於程式撰寫時間較早,其中仍有不少較不成熟的實作方式,因此本文僅作為資料下載流程的紀錄與參考,不深入介紹程式架構與最佳化方法。本文使用的程式語言為 Python 。

提示
本項目程式撰寫於 2024 年 9 月。

尋找資料

在開始下載資料之前,首先需要明確定義資料來源與下載目標。我的目標是蒐集涵蓋臺灣地區的衛星影像,並依據是否有颱風影響,將影像分類為「有颱風」與「無颱風」兩類,以利於後續進行模型訓練時,能夠區分資料的所屬類別。

基於上述需求,我選擇以大氣科學研究與應用資料庫取得衛星影像,並搭配颱風資料庫取得颱風資訊,作為主要資料來源。

大氣科學研究與應用資料庫

大氣科學研究與應用資料庫(ASRAD)目前由中國文化大學大氣科學系維護,提供豐富的大氣觀測與衛星相關資料。依據其網站說明,此資料庫的發展沿革如下。

國科會於 1987 年於國立臺灣大學大氣科學系成立「副熱帶資料庫」,開啟大氣研究資料的收集及服務。 2011 年起由國家實驗研究院颱風洪水研究中心接手經營,並擴充為「大氣水文研究資料庫」。 2018 年轉由中國文化大學大氣科學系承接,並於 2022 年與「太空科學研究資料庫」整併為「大氣科學研究與應用資料庫」。 2023 年 9 月正式納入國家科學及技術委員會核心設施,除擴大服務項目與領域外,也結合多項大氣觀測實驗,持續保存並提供大氣研究資料,以支援國內外大氣科學研究與應用。

此資料庫擁有如衛星雲圖、水氣雲圖、可見光與紅外線影像、雷達回波圖、地面氣象觀測資料、探空資料、數值天氣分析圖、颱風相關圖資等不同類型的氣象與遙測資料,適合應用於天氣分析、颱風研究、氣候研究、影像辨識、大氣科學教學等領域。對於需要建立氣象影像資料集或進行長時間序列分析的研究而言,是相當便利且完整的資料來源。

https://Josh-test-lab.github.io/posts/Historical%20Typhoon%20Data%20Download%20for%20Taiwan/ASRAD.png
大氣科學研究與應用資料庫 - 資料目錄 https://asrad.pccu.edu.tw/catalog/

颱風資料庫

颱風資料庫是由中央氣象署建置與維護,整合歷年西北太平洋颱風相關觀測與分析資料,提供研究人員、政府機關及一般民眾查詢颱風歷史紀錄與相關氣象資訊。其網站說明如下。

颱風資料庫蒐集歷年來北太平洋西部發生之颱風的名稱與編號,將中央氣象署發佈颱風警報期間,所收錄多種氣象資料,以文字或圖表呈現,包括:颱風警報發布概況表、颱風路徑圖、颱風警報單、衛星雲圖、雷達圖、日累積雨量圖、區域雨量圖、斜溫圖、颱風雨量綜合資訊、綜觀天氣圖、各測站氣象要素逐時變化圖、各測站最大平均風與最大陣風長條圖、各測站總雨量長條圖、各測站連續 24 小時累積雨量長條圖、地面資料填圖等產品。如註冊研究用使用者則可更深入的探討包括:颱風路徑資料、氣象測站資料、投落送資料,及重分析資料中之颱風逐時路徑圖、各階段風場圖、各階段氣壓場圖、等產品,以提供查詢。

此資料庫提供完整的颱風事件紀錄,這裡主要使用其中的颱風基本資訊與警報發布時間,作為判斷衛星影像是否受到颱風影響的依據。此外,颱風強度資訊亦用於後續影像分類,將資料區分為「強烈颱風」、「中度颱風」、「輕度颱風」及「無颱風」四類。

https://Josh-test-lab.github.io/posts/Historical%20Typhoon%20Data%20Download%20for%20Taiwan/TD.png
颱風資料庫 - 有發緊報颱風列表 https://rdc28.cwa.gov.tw/TDB/public/warning_typhoon_list/

資料下載

這邊使用 Python 撰寫下載程式,透過 requests 套件向網站發送 HTTP 請求,取得衛星影像與颱風資料。相較於手動逐筆下載,程式化下載能大幅提升效率,也能方便後續進行大量資料蒐集與自動化處理。

衛星雲圖

由於 ASRAD 將衛星影像依照固定的目錄結構與檔名規則儲存,因此只要根據日期與時間組合出對應的網址,即可取得指定時間的衛星影像。此處以臺灣地區的彩色水氣雲圖(Water Vapor Color Satellite Image)作為資料來源,下載後以原始檔名儲存。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
### import module
import os
import requests
import raise_error_type

### function
# from ASRAD get Taiwan's water vapor color satellite image
# the result is an .jpg image 
def get_taiwan_water_vapor_color_satellite_image(year: str = '2024', month: str = '09', day: str = '05', hour: str = '00', minute: str = '00'):
    filename = year + month + day + '_' + hour + minute + '.PCCU.WVP.jpg'
    url = f'https://asrad.pccu.edu.tw/catalog/pccu/{year}/{month}/{day}/{filename}'
    response = requests.get(url)

    save_dir = 'water_vapor_color_satellite_image'
    if not os.path.exists(save_dir):
        os.mkdir(save_dir)
    if response.status_code == 200:
        file_path = f'{save_dir}\\{filename}'
        with open(file = file_path, mode = 'wb') as jpg_file:
            jpg_file.write(response.content)
        print(f'Successful download \"{file_path}\".')
    else:
        raise raise_error_type.ResponseError(f'request failed with status code {response.status_code}')

颱風資料

由颱風資料庫網站,可以看到其颱風清單的資料獲取 API ,由於網站資料是以 JSON 格式回傳,因此下載完成後可直接轉換成 Python 物件,方便後續分析與處理。

程式共實作兩個函式。第一個 get_taiwan_warning_typhon_data() 用來取得臺灣地區歷年曾發布海上或陸上颱風警報的颱風列表;第二個 get_northwest_pacific_typhon_data() 則取得西北太平洋所有颱風資料。兩者皆透過 HTTP POST 請求向中央氣象署取得資料,並將 JSON 回傳內容解析後提供程式使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
### import module
import requests
import json
import raise_error_type

### function
# from CWA get Taiwan's warning typhoon list
# the result is a json 
def get_taiwan_warning_typhon_data():
    url = 'https://rdc28.cwa.gov.tw/TDB/public/warning_typhoon_list/get_warning_typhoon'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Mobile Safari/537.36',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'X-Requested-With': 'XMLHttpRequest'
    }
    response = requests.post(url, headers = headers, data = {'year': 'all'})

    if response.status_code == 200:
        decoded_content = response.content.decode('utf-8-sig') # decode by 'utf-8-sig'
        data = json.loads(decoded_content)
        return(data)
    else:
        raise raise_error_type.ResponseError(f'request failed with status code {response.status_code}')

# from CWA get northwest Pacific's typhoon list
# the result is a json 
def get_northwest_pacific_typhon_data():
    url = 'https://rdc28.cwa.gov.tw/TDB/public/typhoon_list/get_typhoon'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Mobile Safari/537.36',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'X-Requested-With': 'XMLHttpRequest'
    }
    response = requests.post(url, headers = headers, data = {'year': 'all'})

    if response.status_code == 200:
        decoded_content = response.content.decode('utf-8-sig') # decode by 'utf-8-sig'
        data = json.loads(decoded_content)
        return(data)
    else:
        raise raise_error_type.ResponseError(f'request failed with status code {response.status_code}')

下載與分類

完成前述兩項資料下載函式後,即可開始進行資料的批次下載與分類。

get_newest_taiwan_warning_typhon() 會先檢查本機是否已存在當日下載的颱風警報資料,若存在則直接讀取;若不存在,便呼叫前述 API 下載最新資料,並轉存為 CSV 檔,以減少重複下載相同資料所造成的時間與網路資源浪費。

download_satellite_image() 負責批次下載衛星影像,會先建立指定起始日期至目前時間之間的每分鐘時間序列,再依序呼叫衛星影像下載函式,嘗試取得每一個時間點的影像。由於並非所有時間都存在對應的衛星影像,因此程式利用例外處理機制略過不存在的影像,確保整個下載流程能夠持續執行。

最後,程式逐一讀取所有下載完成的衛星影像,根據檔名中的拍攝時間與颱風警報發布期間進行比對。若影像時間落在某次颱風警報期間,便依據該颱風的最大強度將影像移動至對應「強烈颱風」、「中度颱風」、「輕度颱風」資料夾;若未符合任何颱風警報期間,則歸類至「無颱風」資料夾。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
### import module
import os
import datetime
import pandas as pd
import raise_error_type
from tqdm import tqdm
import shutil # move file

### function
def get_newest_taiwan_warning_typhon(): # it will return a csv file path
    filename = 'warning_typhon_list_' + f'{datetime.datetime.now().strftime("%Y-%m-%d")}' + '.csv'
    #filename = f'{datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S")}' + '.csv'

    # check whether the newest warning typhoon list exists
    if os.path.exists(filename):
        print(f'The newest Taiwan\'s warning typhoon list has exist at \"{filename}\".')
        return filename
    else:
        print(f'Did not find the newest Taiwan\'s warning typhoon list, using crawler method and downloading.')
        # download data form CWA by using crawler method
        warning_typhon = get_taiwan_warning_typhon_data() # it is a json file
        warning_typhon = pd.DataFrame(warning_typhon)

        # save the list to file
        warning_typhon.to_csv(filename, index = False, encoding = 'utf-8')
        print(f'The newest Taiwan\'s warning typhoon list has save at \"{filename}\".')
        return filename

def download_satellite_image():
    # generate date range
    start_date = '2026-07-09'
    end_date = datetime.datetime.today()
    date_range = pd.date_range(start = start_date, end = end_date, freq = 'min')

    # download image
    for date in date_range:
        year = str(date.year)
        month = format(date.month)
        day = format(date.day)
        hour = format(date.hour)
        minute = format(date.minute)
        try:
            get_taiwan_water_vapor_color_satellite_image(
                year = year,
                month = month,
                day = day,
                hour = hour,
                minute = minute
            )
        except raise_error_type.ResponseError as error:
            print(f'Skipped as raise_error_type.ResponseError:{error}')

def format(i):
    return str(i) if i > 9 else str(f'0{i}')

### main program
## warning tyhoon list
path = get_newest_taiwan_warning_typhon()
warning_typhoon = pd.read_csv(path, encoding='utf-8')
warning_typhoon.dropna(subset = ['max_intensity', 'sea_start_datetime', 'sea_end_datetime'], inplace = True)

## satellite image download
download_satellite_image()

# make classify folders
for dir in ['強烈颱風', '中度颱風', '輕度颱風', '無颱風']:
    if not os.path.exists(dir):
        os.makedirs(dir)

# define a mapping of intensity to folder names
intensity_folders = {
    's': '強烈颱風',
    'm': '中度颱風',
    'w': '輕度颱風'
}

# classify images
for img in tqdm(os.listdir('water_vapor_color_satellite_image')): # classify from each image
    img_path = os.path.join('water_vapor_color_satellite_image', img)
    if os.path.isfile(img_path): # check if it is a file
        img_time = datetime.datetime.strptime(img[0:13], '%Y%m%d_%H%M') # change str to time
        for row in warning_typhoon.itertuples():
            sea_start = datetime.datetime.strptime(row.sea_start_datetime, '%Y-%m-%d %H:%M:%S')
            sea_end = datetime.datetime.strptime(row.sea_end_datetime, '%Y-%m-%d %H:%M:%S')
            intensity = row.max_intensity
            if sea_start <= img_time <= sea_end:
                # determine the folder based on intensity
                folder_name = intensity_folders.get(intensity)
                new_img_path = os.path.join(folder_name, img)
                shutil.move(img_path, new_img_path) # move the image to the new folder
                break
            else:
                new_img_path = os.path.join('無颱風', img)
                shutil.move(img_path, new_img_path)
                break

print('Successful download and classify all images.')
input('Press any key to continue...')

結語

雖然本程式最初僅作為影像辨識研究前期的自動化下載與資料蒐集工具,程式架構與錯誤處理仍有許多可以改善之處,例如加入更完善的下載重試機制、資料快取、平行化下載以及更精確的颱風影響範圍判斷等。然而,透過此流程可以快速建立具標籤的氣象影像資料集,作為後續影像分類、深度學習模型訓練或其他大氣科學應用的基礎。

氣象資料通常具有高度的時間與空間連續性,若能有效結合自動化資料蒐集技術與人工智慧方法,將有助於從大量歷史觀測資料中發掘更多潛在資訊。本篇文章主要記錄資料取得與整理的方法,希望能提供需要進行氣象影像分析或相關研究者一個簡單的資料處理參考。

參考資料

警告
本文最後更新時間為 2026年07月17日,文中內容可能已經過時,敬請留意。若出現內容錯誤、圖片失效等問題,歡迎留言指正。