氣象機器人 (3) - 天氣預報和空氣品質
延續「氣象機器人 (2) - 目前氣象資訊」文章,這篇教學會讓 LINE 氣象機器人串接天氣預報和空氣品質資訊,只要使用 LINE 預設的功能提供地址,就能回傳該地址的天氣預報和空氣品質資訊。
參考:
爬取天氣預報資訊
參考「爬取天氣預報」教學,從氣象資料開放平臺裡,找到「一般天氣預報-今明36小時天氣預報」資料集複製 JSON 網址。
資料連結 ( 需要登入才看得到 JSON 連結 )
此外,本篇教學更會進一步取得鄉鎮行政區的天氣預報資料,從氣象資料開放平臺的「預報」分類中,搜尋「2天天氣」,可以看到每個資料集的代碼,屆時會透過這些代碼,取得對應的 JSON 檔案 ( 因為除了代碼,其他網址都相同 )
建立 forecast 函式,函式包含一個 address 參數,負責承接 LINE 收到的地址資訊,程式相關重點如下:
- 設定一個變數 json_api,用字典的方式儲存鄉鎮行政區的代碼,key 是縣市名稱。
- 先抓取主要縣市的氣象預報資料,抓到資料後組合成文字,取代原本 msg 變數的內容。
- 再抓取鄉鎮行政區的氣象預報資料,如果沒有資料就可以使用縣市預報資料。
# 氣象預報函式
def forecast(address):
area_list = {}
# 將主要縣市個別的 JSON 代碼列出
json_api = {"宜蘭縣":"F-D0047-001","桃園市":"F-D0047-005","新竹縣":"F-D0047-009","苗栗縣":"F-D0047-013",
"彰化縣":"F-D0047-017","南投縣":"F-D0047-021","雲林縣":"F-D0047-025","嘉義縣":"F-D0047-029",
"屏東縣":"F-D0047-033","臺東縣":"F-D0047-037","花蓮縣":"F-D0047-041","澎湖縣":"F-D0047-045",
"基隆市":"F-D0047-049","新竹市":"F-D0047-053","嘉義市":"F-D0047-057","臺北市":"F-D0047-061",
"高雄市":"F-D0047-065","新北市":"F-D0047-069","臺中市":"F-D0047-073","臺南市":"F-D0047-077",
"連江縣":"F-D0047-081","金門縣":"F-D0047-085"}
msg = '找不到天氣預報資訊。' # 預設回傳訊息
try:
code = '你的氣象開放平台授權碼'
url = f'https://opendata.cwb.gov.tw/fileapi/v1/opendataapi/F-C0032-001?Authorization={code}&downloadType=WEB&format=JSON'
f_data = requests.get(url) # 取得主要縣市預報資料
f_data_json = f_data.json() # json 格式化訊息內容
location = f_data_json['cwbopendata']['dataset']['location'] # 取得縣市的預報內容
for i in location:
city = i['locationName'] # 縣市名稱
wx8 = i['weatherElement'][0]['time'][0]['parameter']['parameterName'] # 天氣現象
mint8 = i['weatherElement'][1]['time'][0]['parameter']['parameterName'] # 最低溫
maxt8 = i['weatherElement'][2]['time'][0]['parameter']['parameterName'] # 最高溫
ci8 = i['weatherElement'][2]['time'][0]['parameter']['parameterName'] # 舒適度
pop8 = i['weatherElement'][2]['time'][0]['parameter']['parameterName'] # 降雨機率
area_list[city] = f'未來 8 小時{wx8},最高溫 {maxt8} 度,最低溫 {mint8} 度,降雨機率 {pop8} %' # 組合成回傳的訊息,存在以縣市名稱為 key 的字典檔裡
for i in area_list:
if i in address: # 如果使用者的地址包含縣市名稱
msg = area_list[i] # 將 msg 換成對應的預報資訊
# 將進一步的預報網址換成對應的預報網址
url = f'https://opendata.cwb.gov.tw/api/v1/rest/datastore/{json_api[i]}?Authorization={code}&elementName=WeatherDescription'
f_data = requests.get(url) # 取得主要縣市裡各個區域鄉鎮的氣象預報
f_data_json = f_data.json() # json 格式化訊息內容
location = f_data_json['records']['locations'][0]['location'] # 取得預報內容
break
for i in location:
city = i['locationName'] # 取得縣市名稱
wd = i['weatherElement'][0]['time'][1]['elementValue'][0]['value'] # 綜合描述
if city in address: # 如果使用者的地址包含鄉鎮區域名稱
msg = f'未來八小時天氣{wd}' # 將 msg 換成對應的預報資訊
break
return msg # 回傳 msg
except:
return msg # 如果取資料有發生錯誤,直接回傳 msg
修改收到地址資訊後,reply 的訊息內容:
reply_message(f'{address}\n\n{current_weather(address)}\n\n{forecast(address)}', reply_token, access_token)
完成後重新執行,設定新的 ngrok 網址為 Webhook,驗證成功後 ( 有時因為快取的緣故,需要重新產生兩次才會正常運作 ),LINE 裡面傳送地址資訊,Colab 裡就會看到該地址的即時天氣資訊。
爬取空氣品質資訊
參考「爬取空氣品質指標 ( AQI )」教學,從政府資料開放平臺裡,找到「空氣品質指標 ( AQI ) 」資料集複製 JSON 網址。
- 空氣品質指標 ( AQI ) :https://data.gov.tw/dataset/40448
- JSON API:檔案連結
建立 aqi 函式,函式包含一個 address 參數,負責承接 LINE 收到的地址資訊,程式相關重點如下:
- 先抓取主要縣市的空氣品質資料,抓到資料後組合成文字,取代原本 msg 變數的內容。
- 再抓取鄉鎮行政區的空氣品質資料,如果沒有資料就可以使用縣市空氣品質資料。
- 因為資料內容有些沒有空氣品質的描述,要自己用 if else 判斷後產生對應的文字。
# 空氣品質函式
def aqi(address):
city_list, site_list ={}, {}
msg = '找不到空氣品質資訊。'
try:
# 2022/12 時氣象局有修改了 API 內容,將部份大小寫混合全改成小寫,因此程式碼也跟著修正
url = 'https://data.epa.gov.tw/api/v2/aqx_p_432?api_key=e8dd42e6-9b8b-43f8-991e-b3dee723a52d&limit=1000&sort=ImportDate%20desc&format=JSON'
a_data = requests.get(url) # 使用 get 方法透過空氣品質指標 API 取得內容
a_data_json = a_data.json() # json 格式化訊息內容
for i in a_data_json['records']: # 依序取出 records 內容的每個項目
city = i['county'] # 取出縣市名稱
if city not in city_list:
city_list[city]=[] # 以縣市名稱為 key,準備存入串列資料
site = i['sitename'] # 取出鄉鎮區域名稱
aqi = int(i['aqi']) # 取得 AQI 數值
status = i['status'] # 取得空氣品質狀態
site_list[site] = {'aqi':aqi, 'status':status} # 記錄鄉鎮區域空氣品質
city_list[city].append(aqi) # 將各個縣市裡的鄉鎮區域空氣 aqi 數值,以串列方式放入縣市名稱的變數裡
for i in city_list:
if i in address: # 如果地址裡包含縣市名稱的 key,就直接使用對應的內容
# 參考 https://airtw.epa.gov.tw/cht/Information/Standard/AirQualityIndicator.aspx
aqi_val = round(statistics.mean(city_list[i]),0) # 計算平均數值,如果找不到鄉鎮區域,就使用縣市的平均值
aqi_status = '' # 手動判斷對應的空氣品質說明文字
if aqi_val<=50: aqi_status = '良好'
elif aqi_val>50 and aqi_val<=100: aqi_status = '普通'
elif aqi_val>100 and aqi_val<=150: aqi_status = '對敏感族群不健康'
elif aqi_val>150 and aqi_val<=200: aqi_status = '對所有族群不健康'
elif aqi_val>200 and aqi_val<=300: aqi_status = '非常不健康'
else: aqi_status = '危害'
msg = f'空氣品質{aqi_status} ( AQI {aqi_val} )。' # 定義回傳的訊息
break
for i in site_list:
if i in address: # 如果地址裡包含鄉鎮區域名稱的 key,就直接使用對應的內容
msg = f'空氣品質{site_list[i]["status"]} ( AQI {site_list[i]["aqi"]} )。'
break
return msg # 回傳 msg
except:
return msg # 如果取資料有發生錯誤,直接回傳 msg
修改收到地址資訊後,reply 的訊息內容:
reply_message(f'{address}\n\n{current_weather(address)}\n\n{aqi(address)}\n\n{forecast(address)}', reply_token, access_token)
小結
到這個步驟,已經完成了一個 LINE 的氣象機器人,最後只需要加入圖文選單,提升使用者體驗就可以囉~
- 完整範例程式下載:line-bot-weather.py
繼續閱讀:
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~