サーバーで長時間動くpythonプログラムが処理終了したのを、他のPCで通知を受け取って感知したいと思いました。pythonプログラムからSlackに通知が投げれればできそう。
実現したいこと
- pythonプログラムからSlackにメッセージを投げつける
- 作業用PCでメッセージを受け取る
Slack側の設定
クライアントからSlackにメッセージを投げつける前に、Slack側でメッセージを受け取る準備が必要です。
slackではslack appによって機能追加をしていきます。外部と通知をやり取りするのも、Webhookのアプリを追加することで実現しています。今回はslackの外部から通知を受け取る機能が必要なので、Incomming Webhookをインストールします。
- Slackでアカウントを作ってログインする
- アカウントの設定の中でIncomming Webhookというslack appを追加する
slackの公式サイトでも方法が案内されています。
slack appの追加
まずslackクライアントで「Slackをブラウズする」→「App」をクリックします。
Appを検索する画面になったら「webhook」で検索します。すると「Incoming Webhooks」というのが見つかるので、「追加」ボタンをクリックします。
「追加」ボタンをクリックするとブラウザが立ち上がってslack app directoryの画面が表示されるので、ここで「Slackに追加」ボタンをクリックします。
次に、どのチャネルで通知を受け付けるかを設定する画面になります。いずれかのチャネルを選択して、「Incoming Webhookインテグレーションの追加」ボタンをクリックします。
最後に追加が完了画面となります。ここで「Webhook URL」が表示されるので、メモっておきます。後ほどプログラム側からこのURLに対してHTTPリクエストを送信することでメッセージを送ることになります。
更に下の方には、curl
コマンドを使ってメッセージを送る例も表示されているので、これもメモっておきます。
これでslack側のセットアップは完了です。
メッセージを送ってみる
メッセージを送る方法
slackでWebhookの設定をしたときに表示された例のようにcurl
コマンドで送信してもいいですが、今回pythonプログラムの終了を通知したいという要件があります。
できたらpythonプログラムの中からメッセージ送信を指示したい。subprocess
関数でcurl
コマンドを起動してもいいんでしょうけど、pythonにはhttpリクエストを送信する関数も標準装備してるので、今回は直接httpリクエストを送る方法でやってみます。
pythonで送信する場合
ちょろっと関数で作って見ようと思います。
Incoming Webhookの設定画面に表示されていたcurl
コマンドの例は、
curl -X POST --data-urlencode "payload={\"channel\": \"#general\", \"username\": \"webhookbot\", \"text\": \"これは webhookbot という名のボットから #general に投稿されています。\", \"icon_emoji\": \":ghost:\"}" https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxxxxxx
というものでした。
import urllib import json def slackmsg(text="",url="",channel="#general",username="webhookbot",icon_emoji=":ghost:"): payload = { "channel":channel, "username":username, "text":text, "icon_emoji":icon_emoji } headerdata = { "Content-Type": "application/json" } try: req = urllib.request.Request(url,data=json.dumps(payload).encode(),method="POST",headers=headerdata) with urllib.request.urlopen(req) as response: status = response.getcode() except urllib.error.URLError as e: print(e.reason)
要は、
- 固定のリクエストヘッダーを付けて
- データ部にjson形式でメッセージをわたして
- POSTリクエストで
- 指定されたurlにリクエストを送信する。
これでメッセージを送信できます。
httpリクエストはurllib
のrequest.Request()
という関数で行いますが、ハマったのはその引数。
The supported object types include bytes, file-like objects, and iterables of bytes-like objects.
https://docs.python.org/ja/3.9/library/urllib.request.html#module-urllib.request
公式のマニュアルは肝心なところが未訳っぽくて英語になってますが、data引数の型がstr型ではだめで、バイト列に変換する必要があるみたい。
なので、data=json.dumps(payload)
ではなくdata=json.dumps(payload).encode()
とする必要があります。
slackmsg("これは webhookbot という名のボットから #general に投稿されています。","https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxxxxxx")
という感じで、メッセージ送信成功😃