通過 Github Action 實現定時推送天氣預報
偶然間,看到 GitHub Actions 教程:定時發送天氣郵件 – 阮一峰的網路日誌 這篇文章,沒錯,這個正好能打發自己的折騰之心,也能通過程式碼給生活引入一些變化。
還是在這裡簡單記錄一下實現過程吧。
第一步 獲取天氣預報出現問題
按照阮一峰的教程走,一開始使用了 wttr 的結果作為數據來源,也在 文檔 上研究了很久,最終的結果總是不盡如人意。
最終展現到郵件上的結果如下:
從上面就可以看出一些問題:
- 展示到郵件中的是一個 HTML 頁面,白色的背景使得結果展示不理想
- 默認返回的結果比較多,根據配置做調整之後返回的結果又比較少,結果不盡如人意
- 從頁面上看返回的都是不太好理解的單位,不能讓人一眼就能理解
- ……
其實還有很多問題,最主要的原因還是其 API 的結果更符合國外的理解,而不適合我用。
第二步 尋找新的數據來源
通過在網上尋找,最終找到了一個 墨跡天氣 的 API 作為數據來源,雖然沒有找到出處,但是暫時還可用。
其返回的結果是一個 JSON 對象,可根據自己的需求去組裝。下面是返回的示例:
{
"code": 0,
"msg": "操作成功",
"data": {
"total": 7,
"sourceName": "墨跡天氣",
"list": [
{
"city": "廣州",
"lastUpdateTime": "2022-10-13 08:55:08",
"date": "2022-10-13",
"weather": "晴",
"temp": 20.0,
"humidity": "35%",
"wind": "東北風3級",
"pm25": 29.0,
"pm10": 43.0,
"low": 20.0,
"high": 30.0,
"airData": "43",
"airQuality": "優",
"dateLong": 1665590400000,
"weatherType": 0,
"windLevel": 3,
"province": "廣東"
},
{
"city": "廣州",
"lastUpdateTime": "2022-10-13 08:00:00",
"date": "2022-10-14",
"weather": "晴",
"humidity": "未知",
"wind": "微風",
"pm25": 0.0,
"low": 21.0,
"high": 30.0,
"airData": "80",
"airQuality": "良",
"dateLong": 1665676800000,
"weatherType": 0,
"windLevel": 1,
"province": "廣東"
},
{
"city": "廣州",
"lastUpdateTime": "2022-10-13 08:00:00",
"date": "2022-10-15",
"weather": "晴",
"humidity": "未知",
"wind": "北風",
"pm25": 0.0,
"low": 21.0,
"high": 31.0,
"airData": "80",
"airQuality": "良",
"dateLong": 1665763200000,
"weatherType": 0,
"windLevel": 3,
"province": "廣東"
},
{
"city": "廣州",
"lastUpdateTime": "2022-10-13 08:00:00",
"date": "2022-10-16",
"weather": "多雲",
"humidity": "未知",
"wind": "北風",
"pm25": 0.0,
"low": 22.0,
"high": 32.0,
"airData": "70",
"airQuality": "良",
"dateLong": 1665849600000,
"weatherType": 1,
"windLevel": 4,
"province": "廣東"
}
],
"logoUrl": "//iflycar.hfdn.openstorage.cn/xfypicture/dev/logo/moji.png"
}
}
根據上述的返回結果,簡單組裝了一個自己想要的結果:
位置:廣東-廣州 今天:2022-10-11
當前:15.0°C 最低:15.0°C 最高:26.0°C
空氣品質:優 濕度:29%
風向:東北風4級 PM2.5:17.0
位置:廣西-桂林 今天:2022-10-11
當前:11.0°C 最低:11.0°C 最高:25.0°C
空氣品質:優 濕度:30%
風向:北風5級 PM2.5:23.0
實際上是非常簡陋的,但卻也暫時夠用了,後續有相關的需求再加內容上去。
第三步 通過腳本簡化
解決了數據來源和展示文本之後,其實已經是解決了需求端的問題,然後來到程式設計師的實現端。
現在,我們先將需求做拆解,落實到程式上應該有以下工作要做:
- 通過 API 獲取到數據來源,組裝成推送的文本格式
- 定時觸發,可以通過 Github Action 白嫖
- 發送郵件,可以通過 QQ 郵箱白嫖
上述工作中的第一步,我最終是選擇使用 Python 對其腳本化,程式碼如下:
import sys
import requests
def generate_weather_text(weather: dict) -> str:
ret = [
f'位置:{weather.get("province")}-{weather.get("city")} 今天:{weather.get("date")}',
f'當前:{weather.get("temp")}°C 最低:{weather.get("low")}°C 最高:{weather.get("high")}°C',
f'空氣品質:{weather.get("airQuality")} 濕度:{weather.get("humidity")}',
f'風向:{weather.get("wind")} PM2.5:{weather.get("pm25")}',
]
return '\n'.join(ret)
def get_weather(city: str) -> dict:
url = '//autodev.openspeech.cn/csp/api/v2.1/weather'
params = {
'openId': 'aiuicus',
'clientType': 'android',
'sign': 'android',
'city': city,
}
res = requests.get(url, params=params).json()
return res['data']['list'][0]
def get_weather_text(city: str) -> str:
weather = get_weather(city)
return generate_weather_text(weather)
if __name__ == '__main__':
if len(sys.argv) >= 2:
ret = [get_weather_text(_) for _ in sys.argv[1:]]
print('\n\n'.join(ret))
else:
print('請求參數錯誤')
第四步 配置 Github Action
Github Action 的配置文件趨同於阮一峰的教程,下面是這個配置文件的一些解釋。
定時觸發
name: "天氣預報"
on:
push:
schedule:
# 需要減 8 個小時
- cron: "0 23 * * *"
這裡比較好理解,name
是名稱,on
是觸發的時機,push
是我們提交程式碼到 Github 時觸發,schedule
是定時觸發,需要注意的時候,定時觸發的時間需要減掉 8 個小時,其遵循國際標準時間而不是北京時間。
運行流程
runs-on: ubuntu-latest
steps:
- name: "切換程式碼"
uses: actions/checkout@v3
進入到 jobs
運行流程中,runs-on
指定運行環境是最新的 Ubuntu 即可,actions/checkout@v3
用作從程式碼倉庫獲取程式碼。
獲取時間
- name: "獲取時間"
run: echo "WEATHER_REPORT_DATE=$(TZ=':Asia/Shanghai' date '+%Y-%m-%d %T')" >> $GITHUB_ENV
直接通過 Linux 命令獲取當前時間,然後轉換成北京時間,這個時間主要是用於後續寫入到郵件的標題當中。
在這裡,通過 echo "{environment_variable_name}={value}" >> $GITHUB_ENV
的方式寫入環境變數,在後續的步驟中都可以訪問到這個環境變數。
執行腳本
- uses: actions/setup-python@v4
with:
python-version: "3.10"
- run: pip install -r requirements.txt
- name: "獲取天氣結果"
run: 'echo "$(python open_api/weather.py 廣州 桂林)" > output.txt'
這裡有兩個步驟,一個是指定 Python 的運行環境並且安裝好相關的依賴,第二個是執行 Python 的腳本獲取結果。
在這裡,為了方便將腳本的執行結果給到後續的步驟,選擇將執行結果寫入到一個文件當中。當然,選擇怎樣的方式主要看自己。
發送郵件
- name: "發送郵件"
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.qq.com
server_port: 465
username: ${{ secrets.SENDER_USER }}
password: ${{ secrets.SENDER_PASSWORD }}
subject: 天氣預報 - ${{env.WEATHER_REPORT_DATE}}
from: GitHub Actions
to: [email protected]
body: file://output.txt
按照阮一峰的腳本,使用 Send email · Actions 發送郵件,和其不同的就是相關的配置。
當然,也可以通過將發送郵件直接寫入到 Python 腳本當中,它們各有自己的優勢。
使用 GIthub Action 發送郵件更易懂,只需要填寫配置即可,也可以將腳本和發送郵件解耦。
使用 Python 發送郵件可以省下 Github Action 的步驟,直接通過腳本一步到位,耦合就比較高。
總結
通過這一次的嘗試,使用 Github Action 實現了自動化及定時,也是為以後實現自己的自動化做鋪墊。本篇文章的源碼可以通過 GitHub – fatedeity/weather-action 訪問。
生命在於折騰,看似無用的一次嘗試,希望能給自己帶來美好的未來。