毎日、当日の天気を能動的に調べるのは面倒なので、天気を知らせてくれるSlack Botを作ってみました。
処理の流れは以下のようになっています。
天気予報のWebページを取得 --> 当日の天気予報のスクリーンショットを撮る --> Slackへアップロード
天気予報のAPIから情報を取得・整形してSlackへ通知するようなBotでもよかったのですが、いい感じのAPIがなかったのと、リッチな通知にしたかったのでこのようになりました。
実装からAWS ECSへのデプロイ・スケジューリングまでを技術ごとに分けて、どのように作成したかを説明していこうと思います。
今回は【Slack編】です。
構成
- ① Selenium編
- ② Slack編 <-- いまここ
- ③ Github Actions編
- ④ AWS ECS編
実装
環境
- Python 3.7
- pipenv
- requests 2.22.0
Slack Botの用意
Slack Botをこちらを参考にして用意してください。Botを作成するとBot User OAuth Access Token
が取得できます。今回はこのアクセストークンを使用してSlackへスクショを投稿します。
ソースコード
SlackのAPIを簡単にPythonから利用できるSDKもありますが、スクショした画像をSlackへ送信するだけなので今回は使用しません。
まず、Slack Bot用のACCESS_TOKENとCHANNELは環境変数から取得します。CHANNELの方は特に指定がなければデフォルトでgeneralチャンネルが設定されますが、ACCESS_TOKENは設定が必須となっています。
次に、SlackのファイルアップロードAPIの仕様に合わせてHTTPリクエストを作成します。今回設定したパラメーターは以下の通りです。Slack APIの仕様詳細はこちらを参照してください。
設定項目 | 値 |
---|---|
URL | https://slack.com/api/files.upload |
メソッド | POST |
Content-Type | multipart/form-data |
token | ACCESS_TOKEN |
channel(option) | CHANNEL |
filetype(option) | binary |
requests.postの引数のfilesに{'filename': open(filepath, 'rb')}
を渡してあげると、Content-Typeにmultipart/form-data
が自動的にセットされるのでheaders引数を指定する必要はありません。中でどのように処理されているかはrequests/models.pyとurllib3/filepost.pyを読むと分かります。
最後にファイルのアップロードが成功したかどうかをチェックします。Slackからのレスポンスが{"ok": true}
であればアップロード完了です。{"ok": false, "error": "error_message"}
であればアップロード失敗となるので例外を発生させます。
import os
import sys
import requests
URI = 'https://slack.com/api/files.upload'
CHANNEL = os.getenv('CHANNEL', 'general')
try:
ACCESS_TOKEN = os.environ['ACCESS_TOKEN']
except KeyError:
sys.exit('You need to set evironment variable called "ACCESS_KEY"')
def upload(filepath):
"""upload filepath to slack
Args:
filepath: relative or absolute path of png file
Returns:
True
Exception
"""
try:
files = {'file': open(filepath, 'rb')}
params = {
'token': ACCESS_TOKEN,
'channels': CHANNEL,
'filetype': 'binary',
}
res = requests.post(URI, params=params, files=files, timeout=10)
if not res.ok:
raise Exception(res.error)
return True
except Exception as err:
raise err
if __name__ == '__main__':
try:
filepath = sys.argv[1]
except Exception:
sys.exit('Error: Please specify a filepath')
upload(filepath)
以下のようなコマンドを実行するとSlackへtest.pngがアップロードされます。
$ pipenv run python3 slack.py test.png
終わりに
Selenium編とSlack編で紹介したソースコードはあえて個々で独立して動作するようにしていました。一つのアプリケーションとしての完成形のソースコードはこちらを参照してください。
次は【Github Actions編】です。 Github Actionsを使ってCI/CDを実現する方法を説明します。