Python3の勉強がてらSlackbotを作ってみた

#はじめに
タイトル通りですが、Pythonの勉強がてらSlack用のBotを作ってみました。
他の方々が記事で書いているので、自分の備忘で残すレベルになります。
Slackの登録方法、Botを使い始めるまで、Herokuの使い方は記載していません。
ソースコードを載せているので、ソースコードの書き方などでお作法的に間違っていることがあれば、指摘してください。

#仕様

ぐるなびAPIを利用して、slackで検索ワードを入力してヒットしたURLを返します。
「ご飯　品川　焼き鳥」と打つと、品川の焼き鳥屋っぽい店のURLを返します。

#環境などなど

* [Slack](https://slack.com)
* [Heroku](https://www.heroku.com)
* Python3.6.0
* [lins05/slackbot](https://github.com/lins05/slackbot)

#構成

slackbot/
　├ plugins/
　│　└ slackbot_restapi.py
　│　└ restapi.py
　│　└ gnaviapi.py
　│　
　└ run.py
　└ slackbot_settings.py
　└ Procfile（Heroku用ファイル）
　└ runtime.txt（Heroku用ファイル）

#実装
##run.py と slackbot_settings.py

```Python:run.py
"""Slack Bot Program."""
# coding: utf-8

from slackbot.bot import Bot

def main():
    """
    Slackbot
    """
    bot = Bot()
    bot.run()

if __name__ == '__main__':
    main()
```

```Python:slackbot_settings.py
"""
Configuration file for slackbot
"""
API_TOKEN = 'YOUR_API_TOKEN'

DEFAULT_REPLY = '何言ってんの？'

PLUGINS = ['plugins']
```

[ここ](https://github.com/lins05/slackbot)に書いてある通りです。 
run.pyを実行すれば、Slackbotは動き出します。

##slackbot_restapi.py

```Python:plugins/slackbot_restapi.py
"""
Plugin Program
"""
from requests.exceptions import RequestException
from slackbot.bot import listen_to
from plugins.gnaviapi import GnaviApi

@listen_to('ご飯')
def search_restraunt(message):
    """
        受信メッセージを元にぐるなびを検索してURLを返す
    """
    gnavi = GnaviApi('https://api.gnavi.co.jp/RestSearchAPI/20150630/')
    key = 'YOUR_API_KEY'

    search_word = message.body['text'].split()

    if len(search_word) == 3:
        params = {
            'keyid': key,
            'format': 'json',
            'address': search_word[1],
            'freeword': search_word[2]
        }
        try:
            gnavi.api_request(params)
            for rest_url in gnavi.url_list():
                message.send(rest_url)
        except RequestException:
            message.send('ぐるなびに繋がんなかったから、後でまた探してくれ・・・( ´Д`)y━･~~')
            return
        except Exception as other:
            message.send(''.join(other.args))
            return
    else:
        message.send('↓こんな感じで検索してほしい・・・(￣Д￣)ﾉ')
        message.send('ご飯　場所　キーワード（文字はスペース区切り）')
        message.send('例）ご飯　品川　焼き鳥')

```

Slackで打ち込まれた内容を拾って処理します。
ここで微妙にハマったのは、Slackで入力されたMessageの拾い方がわからなかったことです。
ちょいちょい調べたところ、

message.body['text']

で取得できることがわかりました。
拾ったメッセージをsplit()で分割して、場所とフリーワードをAPIのパラメータとして使います。

##restapi.py と gnaviapi.py

Pythonのクラスと継承の勉強で作ってみました。
restapi.pyでは、Requestを投げてResponseを持っとくだけのクラスです。
gnaviapi.pyでは、ResponseからURLのみのリストを作成して返すメソッドを追加しています。
リスト内包表記って便利ですよねー。なんか新鮮でした。


```Python:plugins/restapi.py
"""
REST API CLASS
"""
# -*- coding: utf-8 -*-
import requests
from requests.exceptions import RequestException

class RestApi():
    """
    REST API CLASS
    """
    def __init__(self, url):
        self.url = url
        self.response_data = None

    def api_request(self, search_dict):
        """
        API呼び出し
        """
        try:
            self.response_data = requests.get(self.url, params=search_dict)
        except RequestException:
            raise Exception('APIアクセスに失敗しました')

```

```Python:plugins/gnaviapi.py
"""
ぐるなびAPI
"""
# -*- coding: utf-8 -*-
from plugins.restapi import RestApi

class GnaviApi(RestApi):
    """
    ぐるなびAPI用クラス
    """
    def __init__(self, url):
        super().__init__(url)

    def url_list(self):
        """
        ResponseからレストランURLのリストを作って返す。
        """
        json_data = self.response_data.json()
        if 'error' in json_data:
            raise Exception('そのキーワードじゃ見つかんなかった・・・(´・ω・｀)')

        return [rest_data['url'] for rest_data in json_data['rest']]

```

#実行結果

こんな感じです。

<img width="599" alt="スクリーンショット 2017-05-16 1.45.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/99926/3969db59-04df-ca5f-5392-b6df32054206.png">


#終わりに
ATNDやdots.など他のAPIで検索できるように、拡張は簡単にできそうです。
pythonで実装するよりも、Herokuの使い方に四苦八苦していた時間の方が長かった気がしますw