はじめに
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
![スクリーンショット_2018-10-26_20_22_47.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F113160%2F069d4743-5bdc-172a-87d5-9da2285173ec.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=3afe9959df0cfaedd01e9faf2f7a163b)
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')
![スクリーンショット_2018-10-26_20_43_52.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F113160%2Fd9975449-d90a-a2f6-9fc2-6d83081c001f.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=1342325e545ba6b8cc194aaabe780d88)
メッセージを変数として受け取る
受け取りたいメッセージが固定の文字列だけとは限らないと思います。
その場合、渡すメッセージを変数として定義し、その内容に応じて処理をさせる、ということもできます。
respond_toの中で ()
で囲んだ部分が変数となり、関数の引数で定義した変数名で参照することができます。以下の例では、 .*
で何かしらの文字列を読み取り、それを変数 arg
に格納しています。
@respond_to('(.*)')
def reply_hello(message, arg):
message.reply(arg)
![スクリーンショット_2018-10-26_22_32_02.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F113160%2Fe518b430-45b5-b417-f277-493afb17db4e.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=f1dfec08e9560a2b64cd1d281726c1e0)
以下のように、変数は複数個別々に定義することも可能です。
例えばコマンドとオプションを別々に渡す、というような状況で使えます。
@respond_to('(.*) (.*)')
def reply_hello(message, arg1, arg2):
message.reply(arg1 + ': ' + arg2)
![スクリーンショット_2018-10-26_22_37_33.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F113160%2F59d62b4f-b259-0dc0-2f74-5fbec594b254.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=bc0bce27da9718657b90391e30d5f625)
メッセージを正規表現で表す
反応するメッセージは正規表現で表すことも可能です。
詳しくはPythonの正規表現を参照してください。
下記の例だと [a-zA-Z]
はアルファベットの文字列、 \s
はスペースを表します。
@respond_to('[a-zA-Z]\sうさぎ')
def reply_hello(message):
message.reply('どうしたの?')
![スクリーンショット_2018-10-26_22_44_40.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F113160%2F2ea93557-1cad-9bb6-48cd-f84daaf66dbe.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=004020730df1b7d56b03a0367c2db290)
記号を含むメッセージに反応させる
変数を別々に渡すことで、コマンドとオプションのように読み取ることができる、と書きましたが、記号はそのままでは読んでくれません。
記号を使うときは \
でエスケープが必要になります。
下記の例ではハイフンをエスケープ (\-
) しており、何かしらの文字 + スペース + ハイフン付きのアルファベットに反応します。
@respond_to('(.*)\s(\-[a-zA-Z])')
def reply_hello(message, command, arg):
message.reply(command + ' ' + arg + 'ですね')
![スクリーンショット_2018-10-26_22_53_53.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F113160%2F63c39a47-523e-5a62-63eb-bac61cb339bc.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=8cdd78994896a403681eb96b6a681ccf)
前の発言にスタンプをつける
slackといえばスタンプです!スタンプがつくと嬉しいと思うので、Botにスタンプを押してもらいましょう。
@respond_to('(スライムベス|スライム)')
def reply_hello(message, name):
if name == 'スライムベス':
message.react('slimebess')
elif name == 'スライム':
message.react('slime')
![スクリーンショット_2018-10-27_0_46_06.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F113160%2F357eb231-aa89-2059-03ab-b25ce6835268.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=3b654aca0201e76c49733ae46f254600)
ファイルを添付する
何か処理をし、その結果のログやファイルなどをファイルとして取得する…みたいな処理もさせることができます。
以下の例では 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 + 'です')
![スクリーンショット_2018-10-26_23_21_15.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F113160%2F1b7e9684-96c1-3904-4fa6-b33c489461c2.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=e5232ca8d745f56da7ddd314e330153b)
メッセージを整形する
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))
![スクリーンショット_2018-10-27_0_12_15.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F113160%2F75ee6940-9e04-43ae-7d5e-7145f4dc3c7c.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=c650940dfe0f0f8aac474dcb5e01ff09)
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))
![スクリーンショット_2018-10-27_1_18_20.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F113160%2F3a9055fc-d214-8fc9-5251-be6f8332f8a4.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=547a1cb77a53d07edb10e909064d276d)
おわりに
本記事ではPythonでslackのBotを作成する方法を記載しました。
このようにメッセージを渡し、そこから他のAPIと連携してJenkinsのジョブのビルドしたり、AWSのAPI Gatewayを叩いたりできます。
使っていく中でまた何かあれば、追記(もしくは別の記事にて)しようと思います。
また「こういう使い方は便利だよ」とか「こういう風に書いた方が良いよ」みたいな指摘も大歓迎です。