pythonでスプレッドシートとSlackを連携させてBOTを作ってみる１/２(python+gspread+slackbot)

わざわざ検索をするまでもないけど気になった事とかってありますよね。

最近はpythonの学習を始めていて、どうせなら普段使いしているSlackと連携させてBOTを作って、自分があらかじめスプレッドシートに書いた単語をSlack上で入力したらその意味を返してくれるようにしようと考えました。

##やりたいこと

* pythonをスプレッドシート(データベースとして用いる)と連携させて、まずは単体で動作させる

* その後、Slackbotライブラリを導入し、BOTに向かって送信した単語に対応する意味を返してもらう

* Slack上で単語の登録、一覧の出力、削除を可能にする(次の記事で書きます)

##準備

[こちらのページ](https://tanuhack.com/operate-spreadsheet/#i-5)を大いに参考にして、pythonのプログラム上からスプレッドシートを開くところまで実装します。

```python:test.py
import gspread
import json

from oauth2client.service_account import ServiceAccountCredentials 
scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']

credentials = ServiceAccountCredentials.from_json_keyfile_name('ダウンロードしたJSONファイル名.json', scope)

gc = gspread.authorize(credentials)

SPREADSHEET_KEY = 'スプレッドシートキー'

worksheet = gc.open_by_key(SPREADSHEET_KEY).sheet1#この行まで書いていきます。
```

続きを書いていきます。

```python:test.py
values_list = worksheet.col_values(1) #シートの1列目をリストとして取得

search_word = input('調べたい単語を入力: ')


# 検索した単語と、全件検索したリストを比較し、値があればTrue,無ければFalseを返す
tof = search_word in values_list #tof...適当な変数
if tof == True:
  cells = worksheet.find(search_word)  # 入力結果に一致する座標を取得
  val = worksheet.cell(cells.row, cells.col+1).value  # 座標を調整し、説明欄を取得
  print('詳細：', val)  # 説明欄を出力
else:
  print('詳細を出力できませんでした。')
```

入力された値を比較するところは、gspreadのライブラリにもっとスマートな関数があるかと思って調べていたんですが、どうにも返り値がうまくいかず...仕方なくin演算子を使っています。もっと良い方法があれば教えてください。

##動かしてみる

スプレッドシートの中身を用意します。
![スプレッドシートの中身](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/710497/f7376756-e97b-d32b-9444-bdf6acce2bd5.png)

```
$ py test.py
調べたい単語を入力： ミッキー
詳細： ハハッ
```

できました。

##Slackと連携させる

実装前に悩んでいたことは、
* input関数をSlack側でどのようにするのか
* レスポンスはどのように書くのか

このあたりです。

###ディレクトリ構成

[こちら](https://baystream.jp/tech_blog/article/21)の記事を大いに参考にし、実装します。先ほど動かしたtest.pyはあっても無くても平気です。

##コードを書く

```python:run.py
# -*- coding: utf-8 -*-
from slackbot.bot import Bot
                                                         
def main():
    bot = Bot()
    bot.run()
                                                         
if __name__ == "__main__":
    print('start slackbot')
    main()
```

```python:slackbot_setting.py
# -*- coding: utf-8 -*-
                                                         
API_TOKEN = "xxxx-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx"
                                                         
# デフォルトの返事
DEFAULT_REPLY = "「検索：」と入力してから文字を入力してください。"
                                                         
# 機能追加のコードを書いたファイルが置いてあるディレクトリ名と合わせます
PLUGINS = ['plugins']
```

```python:my_mentions.py
# -*- coding: utf-8 -*-
import json
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import re
from slackbot.bot import respond_to     # @botname: で反応するデコーダ
from slackbot.bot import listen_to      # チャネル内発言で反応するデコーダ
from slackbot.bot import default_reply  # 該当する応答がない場合に反応するデコーダ

scope = ['https://spreadsheets.google.com/feeds',
         'https://www.googleapis.com/auth/drive']


credentials = ServiceAccountCredentials.from_json_keyfile_name(
    'ダウンロードしたJSONファイル名.json', scope)


#OAuth2の資格情報を使用してGoogle APIにログインします。
gc = gspread.authorize(credentials)

#共有設定したスプレッドシートキーを変数[SPREADSHEET_KEY]に格納する。
SPREADSHEET_KEY = 'スプレッドシートキー'

#ここから先がスプレッドシートの操作内容です。#####################################
#共有設定したスプレッドシートのシート1を開く
worksheet = gc.open_by_key(SPREADSHEET_KEY).sheet1

values_list = worksheet.col_values(1)


@respond_to('検索：(.*)')
def mention_func(message, search_word):
  tof = search_word in values_list
  if tof == True:
    cells = worksheet.find(search_word)  # 入力結果に一致する座標を取得
    val = worksheet.cell(cells.row, cells.col+1).value  # 座標を調整し、説明欄を取得
    message.reply('結果: {0}'.format(val))  # メンション
  else:
    message.reply('検索しましたが、見つかりませんでした。')  # メンション

@listen_to('アプリ名とか適当に決める')
def listen_func(message):
    message.reply('御用があれば、「@アプリ名 検索：」と入力したあと、任意の文字を検索してください。')                       # メンション
```

respond_to()は、アプリをチャンネル内でメンションしてメッセージを送信したときの動作を記述するものです。
「.*」とすることで、任意の文字列を受け付けてBOT側に渡します。今回の場合は、「検索："任意の文字列"」とSlack側に送信することで、その単語に一致するものがあるかスプレッドシートを検索し、あれば意味を返してくれます。

ここを変更すれば、かなり応用が効きそうな感じがします。

ちなみにlisten_to()は、メンションをせずにメッセージを送信したときの動作を記述するものです。

run.pyを実行すると、SlackBOTが起動してくれます。

しかしこのままだと、BOTを起動するために毎回run.pyを実行しなければなりませんので、私の場合はアプリケーションをherokuにデプロイして、常に応答してくれるようにしています。

##さいごに
実装し終わってから、別にローカルファイルと紐づけても良いしその方が安全かも？とか思ったりしたので、そのうち書き換えるかもしれません。
とりあえず、Slackbotにおけるメッセージの送信と受信という基本がわかったので、ここをどんどん変更して登録・削除などを実装していきます([次の記事はこちらです](https://qiita.com/KScookie/items/2e6fc4eedc25755c1faa))。