はじめに
PythonでSlackのBotを作成する機会があったので、自分のメモも兼ねて、Botユーザ作成〜基本的なやりとりの実装について記載します。
環境
- Ubuntu 16.04.5
- Python 3.5.2
- slackbot 0.5.3
- Slack
- SlackのUIなどはバージョンにより変わる可能性有り
Slack Bot利用の事前準備
Botユーザを作成する
こちらにアクセスし、「Create ap app」をクリックします。
Bot名(チャンネル上で表示される名前ではないです)と追加するワークスペースを指定して「Create App」をクリックします。
Botをユーザとして認識させる
Botをユーザとして認識させるためには、まずBotに権限を設定する必要がある。以下の画像に示す「permission scope」をクリックします。
作成したBotの用途に合わせて権限を選択します。
例えば「メッセージの変更ができるような権限」「メッセージをPinする権限」などです。(今回はAdmin権限で作成)
先ほどの画面に戻ると「Install App to Workspace」が有効化されているので選択し、以下の画像のような画面に遷移するので「Authorize」をクリックします。。
Botのユーザとしての表示名と「Always Show My Bots as Online」をOnに設定します。(必要に応じてアイコンも設定しておく)
# Botの作成
導入部分はこちらの記事を参考にさせていただきました。
slackbotパッケージのインストール
以下のコマンドでslackbotパッケージをインストールします。
$ pip3 install slackbot
Botの初期設定
以下のような構成でファイル/ディレクトリを作成します。
root@ubuntu-xenial:/vagrant_data/slack_bot# tree
.
├── plugins # botで動かすスクリプトを格納するディレクトリ
├── run.py # 実行のトリガーとなるスクリプト
└── slackbot_settings.py # botの設定を記述するファイル
run.pyとslackbot_settings.pyの中身はそれぞれ以下のようになっています。
# coding: utf-8
from slackbot.bot import Bot
def main():
bot = Bot()
bot.run()
if __name__ == "__main__":
print('starting slackbot')
main()
# coding: utf-8
# SlackのAPIを利用するためのトークン
# Botの設定ページから「OAuth & Permissions」のページに遷移し、
# 「Bot User OAuth Access Token」をコピーして貼り付ける
API_TOKEN = "*****************************"
# 対応するメッセージがなかった場合に反応するメッセージ
DEFAULT_REPLY = "I dont't understand you."
# Botが実行するスクリプトを配置するディレクトリパスのリスト
PLUGINS = ['plugins']
Botの起動
run.py
を実行してBotを起動します。
root@ubuntu-xenial:/vagrant_data/slack_bot# python3.5 run.py
starting slackbot

Botスクリプトの実装
特定の単語に反応するようにする
Botの基本です。Botといえば、何かしら命令してその処理を行わせるものですが、その命令を読み取るための仕組みがこちらになります。
pluginsディレクトリの下に、Botが実行するスクリプト hello.py
(名前はなんでも良い) と空ファイルの __init__.py
を作成してください。 __init__py
が存在しないと動かない点に注意してください。
root@ubuntu-xenial:/vagrant_data/slack_bot# tree
.
├── plugins
│ ├── hello.py
│ ├── __init__.py
〜以下略〜
# coding: utf-8
from slackbot.bot import respond_to
@respond_to('Hello')
def reply_hello(message):
message.reply('Hello')

メッセージを変数として受け取る
受け取りたいメッセージが固定の文字列だけとは限らないと思います。
その場合、渡すメッセージを変数として定義し、その内容に応じて処理をさせる、ということもできます。
respond_toの中で ()
で囲んだ部分が変数となり、関数の引数で定義した変数名で参照することができます。以下の例では、 .*
で何かしらの文字列を読み取り、それを変数 arg
に格納しています。
@respond_to('(.*)')
def reply_hello(message, arg):
message.reply(arg)

以下のように、変数は複数個別々に定義することも可能です。
例えばコマンドとオプションを別々に渡す、というような状況で使えます。
@respond_to('(.*) (.*)')
def reply_hello(message, arg1, arg2):
message.reply(arg1 + ': ' + arg2)

メッセージを正規表現で表す
反応するメッセージは正規表現で表すことも可能です。
詳しくはPythonの正規表現を参照してください。
下記の例だと [a-zA-Z]
はアルファベットの文字列、 \s
はスペースを表します。
@respond_to('[a-zA-Z]\sうさぎ')
def reply_hello(message):
message.reply('どうしたの?')

記号を含むメッセージに反応させる
変数を別々に渡すことで、コマンドとオプションのように読み取ることができる、と書きましたが、記号はそのままでは読んでくれません。
記号を使うときは \
でエスケープが必要になります。
下記の例ではハイフンをエスケープ (\-
) しており、何かしらの文字 + スペース + ハイフン付きのアルファベットに反応します。
@respond_to('(.*)\s(\-[a-zA-Z])')
def reply_hello(message, command, arg):
message.reply(command + ' ' + arg + 'ですね')

前の発言にスタンプをつける
slackといえばスタンプです!スタンプがつくと嬉しいと思うので、Botにスタンプを押してもらいましょう。
@respond_to('(スライムベス|スライム)')
def reply_hello(message, name):
if name == 'スライムベス':
message.react('slimebess')
elif name == 'スライム':
message.react('slime')

ファイルを添付する
何か処理をし、その結果のログやファイルなどをファイルとして取得する…みたいな処理もさせることができます。
以下の例では get_file ~~~.txt
にマッチするメッセージを送ると、ファイルが返ってくるという仕組みです。
@respond_to('get_file\s([a-zA-Z]*\.txt)')
def reply_hello(message, file_name):
# fname: slack上で表示するファイル名
# fpath: ファイルが置いてあるパス
# initial_comment: slack上で表示するコメント
message.channel.upload_file(fname=file_name, fpath=file_name, initial_comment=file_name + 'です')

メッセージを整形する
Botからのメッセージを整形することができます。
使えるパラメータはこちらを参照してください。
@respond_to('usagi')
def reply_hello(message):
attachments = [
{
"color": "#3104B4",
"fields": [
{
"title": "場所",
"value": "東京駅"
},
{
"title": "時間",
"value": "19:00"
}
],
"footer": "usagi-san",
"footer_icon": "https://pics.prcm.jp/db36726f85742/67433428/jpeg/67433428.jpeg"
}
]
message.send_webapi('集合場所', json.dumps(attachments))

short
をつけることで、以下のように横に並べて表示することもできます。
@respond_to('usagi help')
def reply_hello(message):
attachments = [
{
'color': "#FF8000",
'fields': [
{'title': "コマンド", 'value': "usagi help", 'short': True},
{'title': "説明", 'value': "ヘルプを表示します", 'short': True},
]
}
]
message.send_webapi('コマンド一覧', json.dumps(attachments))

おわりに
本記事ではPythonでslackのBotを作成する方法を記載しました。
このようにメッセージを渡し、そこから他のAPIと連携してJenkinsのジョブのビルドしたり、AWSのAPI Gatewayを叩いたりできます。
使っていく中でまた何かあれば、追記(もしくは別の記事にて)しようと思います。
また「こういう使い方は便利だよ」とか「こういう風に書いた方が良いよ」みたいな指摘も大歓迎です。