[python] プログラミング初心者向けのslackbot入門

# はじめに
チャットツールとして日々利用者が増えているslackですが、そんなslackのbotを自分で作成することができるのはご存知でしょうか。
この記事では、slackbotに関する知識が０の人でも作成できるように、開発手順を詳しく＆分かりやすく書いていこうと思います。
既にslackbot作成に関する記事は多く公開されているのですが、これから自作slackbotの投稿をいくつか書いていきたいと考えており、どうせなら作り方も自分で書いてしまえという事で投稿させていただきました。他の投稿に負けないくらい分かりやすい記事にしていくつもりです。

# Abstract
* Slackbotの**アカウントを作成**
* Slackbotの**API**を取得
* ローカルで**Slackbotを動かしてみる**(おみくじ実装)

最終的な完成品はGithubに公開しておきます。
これから投稿する予定の機能もまとめてココに公開する予定ですので、使ってみたい方はコチラを使ってください。
https://github.com/chocode/Qiita-bot
ただし、dotenvを使ってトークンを.envに記述しているので、cloneする際はご注意ください(詳しくは後述)

# Slackbot用のアカウントを作成
ここまで**Slackbot**と書きましたが、この記事で紹介するSlackbotは良く見かけるコレではありません。
![63f21d24-s.png](https://qiita-image-store.s3.amazonaws.com/0/197878/285dcd23-f242-bfae-09cf-23c34fe769f6.png)

コイツをカスタマイズ出来る機能もSlackにはあるのですが、今回は**自作したBot**を動かしていきます。
自作Botを利用すれば、pythonで出来ることは大抵出来ます。もっと具体的に言えば、後述するslackbotライブラリを使えば、pythonのコードの中に**slackへの投稿やリアクション**を行う処理を組み込むことが出来ます。
また、作成したBotはUserとして登録されるため、Botに好きな名前を付けたりアイコンを変えたりすることができます。
自分の好きなアイコン・名前のBotに、会話やスケジューリング、今日の天気を聞いたりエアコンを点けてもらったりなど、様々なことが出来るようになる訳です。妄想が捗りますね。

それでは、実際にBotをUserとして登録する手順について説明していきます。

まずはBotを登録して、Botを動かすためのAPIを取得する必要があります。
正直、**API取得が一番多くの人が詰まるポイント**だと思いますので、なるべく丁寧に書いていこうと思います。

## [1] Botを作成
Botsのインストールまでの手順
1. workspaceのサイドメニュー(画面左上の∨をクリック)から**Slack をカスタマイズ**を選択
2. 左側のメニューから**App 管理**へ
3. **App directoryを参照する**をクリック
4. 検索バーに**Bots**と入力して、Botsのページに飛ぶ
5. **設定を追加**をクリック

この画面まで辿りつけていれば成功
<img width="1134" alt="スクリーンショット 2018-07-18 13.38.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/197878/4f78e399-2ac5-8cca-c504-c95ef5ade75f.png">

もしあなたがワークスペースへのApp追加権限がない場合は、オーナーにリクエストを送って許可してもらう必要があります。
リクエストは**インストールをリクエスト**というボタンから送ることができます。
Botsをインストール出来ない場合は、残念ながら今回の作り方ではBotを作成できません。どうしてもBotを作りたい場合は、自分専用のワークスペースを作成しましょう。

最後に、Botの名前を入力すれば、Botの作成が完了します。

## [2] Botの設定
Botの作成が完了すると、App directoryの**カスタムインテグレーション/Bots/(Botsの設定画面)**が表示されます。
この画面は何度も利用することになるので、覚えておきましょう。
Botのアイコンや名前もここから設定することが出来ます。使用したいキャラなどが居れば、設定しておきましょう。

この設定画面の**インテグレーションの設定**にある**APIトークン**がBotのAPIです。これはBot作成時に**必須**ですので、控えておいてください。
また、外部に漏れるとBotを乗っ取られる可能性がありますので、公開は厳禁です。Githubにそのまま載せたりすると、Slackから直接お叱りのメールが飛んできます。
Githubに公開したい場合は、dotenvを使うなりしてトークンを隠しましょう。詳しいやり方は後述します。

# slackbotライブラリの導入
今回はpythonの**slackbot**というライブラリを使用します。早速導入しましょう。

```
$ pip install slackbot
```

ちなみにpythonは3系で動かしてください。2系では上手く動きませんでした……

# ローカルでSlackbotを動かしてみる
slackbotを動かすには、以下のような構成が必要です。

※ この記事に書かれている構成とコードを一部変更して引用しています。こちらも詳しく丁寧に書かれた良記事ですので、とても参考になると思います。
https://qiita.com/sukesuke/items/1ac92251def87357fdf6

```
slackbot         　　　　　# rootディレクトリ。ディレクトリ名はなんでも良い
├─ run.py       　　　　　 # ボットを起動するプログラム
├─ slackbot_settings.py   # botに関する設定を書くファイル
└─ plugins                # botの機能はこのディレクトリに追加する
   ├─ __init__.py         # モジュールを示すためのファイル。
   └─ omikuji.py          # おみくじ機能のプログラム
```

Slackbotを作るだけなら上記の構成で問題ないのですが、今回はGithubなどに公開することも考えて、Botのトークンを.envファイルに退避させることにします。

```
slackbot         　　　　　# rootディレクトリ。ディレクトリ名はなんでも良い
├─ run.py       　　　　　 # ボットを起動するプログラム
├─ slackbot_settings.py  # botに関する設定を書くファイル
├─ .env       　　　　　   # APIトークンを書く隠しファイル
├─ .gitignore       　　  # Gitに上げる際に追跡対象から外すファイルを指定する
└─ plugins                # botの機能はこのディレクトリに追加する
   ├─ __init__.py         # モジュールを示すためのファイル。
   └─ omikuji.py          # おみくじ機能のプログラム
```

今回はトークンをcommitから隠す為にdotenvを利用するので、事前に導入しておいてください。

```
pip install python-dotenv
```

各プログラムの中身は以下の通り

```run.py
from slackbot.bot import Bot
def main():
    bot = Bot()
    bot.run()

if __name__ == "__main__":
    print("Botを起動しました")    # Bot起動時に表示されるメッセージ
    main()
```

```slackbot_settings.py
import os
from os.path import join, dirname
from dotenv import load_dotenv

# .envを読み込む
env_path = join(dirname(__file__), '.env')
load_dotenv(env_path)

# .envからbotアカウントのトークンを取得
API_TOKEN= os.environ.get("API_TOKEN")

# このBotが行う処理が見つからなかった時に返すメッセージ
DEFAULT_REPLY = "応答に失敗しました"

# プラグインスクリプトを置いてあるサブディレクトリ名
PLUGINS = ['plugins']
```

```/.env
# Botsの設定画面(カスタムインテグレーション内)にあるAPIトークンをここに設定する
API_TOKEN = "xxxx-xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx"
```

```/.gitignore
/.env
```

``` __init__.py
```

**__init__.py**は空のままでOK

# omikuji.py
いよいよBotの機能を実装していきます。今回は練習として簡単なおみくじ機能を作成しましょう。

### 機能要件
* リプライで「おみくじ」と送られた時に、おみくじを引いた結果を返してくれる
* おみくじの内容は、大吉・中吉・吉・凶・大凶の５種類
* 全て等間隔だとあまりに芸が無いので、それぞれ生起確率を10%・25%・30%・25%・10%とする

具体的な実装方法は、[上で紹介した記事](https://qiita.com/sukesuke/items/1ac92251def87357fdf6)で詳しく紹介されています。
今回は「おみくじ」とリプライを送られたときに行う処理なので、**@respond_to**を使用します。
respond_toで指定されたワードを含むリプライをBotに対して行った時、その下で定義されている関数が実行されます。
respond_toはリプライ限定ですので、**普通の投稿には反応しません**。(Direct Messageなら自動でリプライと認識されますが)
普通の投稿にも反応させたい場合は**@listen_to**を使用してください。listen_toを使用する場合はimportするのをお忘れなく。

実際におみくじ機能を~~適当に~~実装してみたコードを、以下で紹介します。

```omikuji.py
from slackbot.bot import respond_to
from slackbot.bot import default_reply
import random

@respond_to("おみくじ")
def kuji(message):
	# おみくじの中身と、生起確率
	fortune = ["大吉", "中吉", "吉", "凶", "大凶"]
	kakuritu = [10, 25, 30, 25, 10]

	rnd = random.randint(1, sum(kakuritu))
	val = 0
	hit = 0

	for i in range(0, len(fortune)-1):
		val += kakuritu[i-1]
		if rnd <= val and hit == 0:
			hit = i

	message.reply("今日の運勢は 【" + fortune[hit] + "】 です。")

@default_reply()
def error_func(message):
	message.reply("コマンドを間違えてませんか？？")

```

関数中に**message.reply()**を使用することで、Botに指定の文言でリプライを返させることが出来ます。リプライではなく通常の投稿を行う場合は**message.send()**を使ってください。
また、**@defalut_reply**はエラーメッセージです。Botに対してリプライを行なった際、行う処理が見つからなかった場合に実行されます。デバッグ用に追加しておきましょう。


# Slackbot、起動
ここまで書けば、あとは起動するのみです。
コンソールでrun.pyがあるディレクトリまで移動したあと、run.pyを実行してみてください。

```
$ python run.py
Botを起動しました
```

Botの起動を確認したあとは、実際におみくじが使えるか試してみましょう。(チャンネルで動かす場合は、Botをチャンネルに招待してください)
上手くいけばこんな感じに動いてくれます。

<img width="542" alt="スクリーンショット 2018-08-25 0.29.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/197878/5ba5c1d2-b344-1366-6153-f7fb0c3dc698.png">

上手く動いてくれましたね。
respond_toは、対象となるワードが**含まれているか**で判定されるので、「おみくじ引いて」でも反応します。
このように、軽いpythonの知識とslackbotライブラリがあれば、簡単にBotを作成することが出来ます。もっと手を加えれば定時処理や画像検索なども実装できる為、色々試してみてください。

ちなみに、このままでは当然Control+CやログアウトなどでBotは停止します。実際にBotとして運用するには、自前鯖やherokuなどで常駐化させてください。

# おわりに
今回は、自作Bot紹介の足がかりとしてslackbotの作り方を紹介させていただきました。なるべく丁寧に書いたつもりですので、多くのslackbot入門者の助けになれば幸いです。
slackbotを使って出来ることは色々ある為、プログラミングや自作Bot入門のネタとしてもオススメだと思いますので、是非試してみてください。
次回の記事では、定時処理とスクレイピングの一例として、今日の天気を知らせてくれる機能を紹介したいと思いますので、よろしくお願いいたします。