LINE Botを試してみた

Line botを作成するまでの手順をまとめる。
botはpythonで実装した。

LINEの開発概要は以下の解説を参照。
https://developers.line.biz/ja/docs/line-developers-console/overview/#page-title

## Line Developersのアカウントとチャネル作成

以下の手順に従い、Line Developersのアカウントとプロバイダー、チャネルを作成する。

https://qiita.com/nkjm/items/38808bbc97d6927837cd#%E6%89%8B%E9%A0%86

プロバイダーの作成手順は省略。

チャネルは「Messageing API」を選択する。
![スクリーンショット 2021-04-30 10.47.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/12f9823b-660b-2dd5-e411-ce0532f84a26.png)

チャネル作成時の項目は以下のような感じ。
チャネル名は適当に。
業種は個人のお試しでやっているので、大業種：個人、小業種：個人(IT・コンピュータ) にした。

![スクリーンショット 2021-04-30 10.48.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/ce9b66a6-bcbd-05bf-e300-17f175fbee05.png)
![スクリーンショット 2021-04-30 10.50.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/72043a00-9371-a5a9-6458-0359d0c972f9.png)

作成したMessaging APIチャネルの「Messaging API設定」タブのQRコードをLINEアプリで「友だち追加」から読み込むと、LINEに友達追加できる。
![スクリーンショット 2021-04-30 10.59.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/050493f0-f56c-8067-7fb4-8e1c5e20d78b.png)

## 応答メッセージの設定(Line Developers)

簡単なものであれば、Line Developers上で応答メッセージの設定ができる。「Messaging API設定」タブの応答メッセージの「編集」から編集する。
![スクリーンショット 2021-04-30 11.24.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/3e1449c5-b04f-c7df-303c-e5d5ad0c813c.png)

特定のメッセージに対して応答したり、時間帯別での応答も設定できる。
![スクリーンショット 2021-04-30 11.28.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/f6c9f5b6-0725-ffe4-28ce-2a00a1ba3e89.png)

## Webhookを利用した応答メッセージ

LINEに投稿されたメッセージを外部サーバに転送し、外部サーバで作成した応答をLINEに応答することができる。
外部サーバはHerokuを使用する。Herokuの対応言語は[ここ](https://jp.heroku.com/languages)に記載されてる。

### Herokuでアプリ作成

[Heroku](https://jp.heroku.com/)でアカウントを作成し、ログインする。

Herokuで 「New」→「Create new app」を選択。

![スクリーンショット 2021-04-30 13.05.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/a6bee84f-c094-5ce1-7170-a7295c21fa60.png)

「Create app」を押してApp作成。
App nameはHeroku全体(ログインアカウント内ではない)で一意な名前である必要があるため、既に使われている名前は指定できない。名前にこだわりがなければApp name入力なしで「Create app」を押すと、適当な名前のAppをHerokuが作成してくれる。

![スクリーンショット 2021-04-30 13.03.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/77e5d44a-eae5-1af0-5a29-a498e4f3c002.png)

### Botアプリ実装

PythonでBotアプリを実装する。
なお、LINEでは、Botアプリ向けに[Line bot sdk](https://developers.line.biz/ja/docs/messaging-api/line-bot-sdk/)を提供している。公式のSDKとサードパーティ製SDKがある。Pythonは公式SDKが提供されている。
他に、Webサーバとして[flask](https://flask.palletsprojects.com/)を使用する。

```
$ mkdir line-bot-python
$ cd line-bot-python
$ python --version
Python 3.6.4
$ python -m venv line-bot
$ source line-bot/bin/activate
$ echo line-bot/ > .gitignore
$ pip install flask line-bot-sdk
$ pip freeze > requirements.txt
$ echo python-3.6.13 > runtime.txt
$ echo web: python main.py > Procfile
```

runtime.txtの仕様は[ここ](https://devcenter.heroku.com/ja/articles/python-support#supported-runtimes)を参照。
Procfileの仕様は[ここ](https://devcenter.heroku.com/ja/articles/procfile)を参照。

続いて、Botプログラムを作成。

```main.py
import os

from argparse import ArgumentParser
from logging.config import dictConfig

from flask import Flask, request, abort

from flask.logging import default_handler

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
    UnfollowEvent, FollowEvent, JoinEvent, LeaveEvent,
)

# 標準出力にログ出力することで、Herokuのログに出力する
dictConfig({
    'version': 1,
    'formatters': {'default': {
        'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
    }},
    'handlers': {'consoleHandler': {
        'class': 'logging.StreamHandler',
        'level': 'INFO',
        'formatter': 'default',
        'stream': 'ext://sys.stdout'
    }},
    'root': {
        'level': 'INFO',
        'handlers': ['consoleHandler']
    }
})

app = Flask(__name__)

# 環境変数取得
# LINE Developersで設定されているチャネルアクセストークンとチャネルシークレットを設定
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["CHANNEL_SECRET"]

line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)


@app.route("/callback", methods=['POST'])
def callback():
    """ Webhookからのリクエストの正当性をチェックし、ハンドラに応答処理を移譲する """

    # リクエストヘッダーから署名検証のための値を取得します。
    signature = request.headers['X-Line-Signature']

    # リクエストボディを取得します。
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    # 署名検証で失敗した場合、例外を出す。
    except InvalidSignatureError:
        app.logger.warn("Invalid Signature.")
        abort(400)
    # handleの処理を終えればOK
    return 'OK'


@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    """
    LINEへのテキストメッセージに対して応答を返す

    Parameters
    ----------
    event: MessageEvent
      LINEに送信されたメッセージイベント
    """

    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text="応答です。 " + event.message.text))


if __name__ == "__main__":
    # app.run()
    arg_parser = ArgumentParser(
        usage='Usage: python ' + __file__ + ' [--port <port>] [--help]'
    )
    # Herokuは環境変数PORTのポートで起動したWeb Appの起動を待ち受けるため、そのポート番号でApp起動する
    arg_parser.add_argument('-p', '--port', type=int,
                            default=int(os.environ.get('PORT', 8000)), help='port')
    arg_parser.add_argument('-d', '--debug', default=False, help='debug')
    arg_parser.add_argument('--host', default='0.0.0.0', help='host')
    options = arg_parser.parse_args()

    app.run(debug=options.debug, host=options.host, port=options.port)

```

### Heroku CLIインストール

[ここ](https://devcenter.heroku.com/articles/heroku-command-line)の内容に従い、Heroku CLIをインストールする。
Macでのインストールは以下コマンドで。

```
$ brew tap heroku/brew && brew install heroku
```

### チャネルアクセストークンの設定

チャネルアクセストークンをHerokuの環境変数に設定する。

Line DevelopersのMessaging API設定の、チャネルアクセストークン（長期）の「発行」を押すと、トークンが発行されるので、これをコピーする。

![スクリーンショット 2021-04-30 15.53.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/acc22ab1-86fa-dca1-9bf3-68648035951a.png)

コマンドラインより、以下を実行する。

```
$ heroku config:set CHANNEL_ACCESS_TOKEN=[Line Developersで発行したチャネルアクセストークン] -app=[HerokuでCreate appした名前]
```

### チャネルシークレットの設定

チャネルシークレットをHerokuの環境変数に設定する。

Line Developersのチャネル基本設定の、チャネルシークレットをコピーする。

![スクリーンショット 2021-04-30 16.35.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/b6d0b75f-a0e4-cc06-fa4c-ff3a4cbd6389.png)

コマンドラインより、以下を実行する。

```
$ heroku config:set CHANNEL_SECRET=[Line Developersで発行したチャネルシークレット] -app=[HerokuでCreate appした名前]
```

### Herokuにアップロード

コマンドラインからプログラムをアップロードする。

```
$ heroku login
$ git init
$ heroku git:remote -a [HerokuでCreate appした名前]
$ git add .
$ git commit -am "line bot app"
$ git push heroku master
```


### Webhook設定

Line DevelopersよりWebhookを設定する。
Messaging API設定より、Webhook URLの「編集」を押す。

![スクリーンショット 2021-04-30 16.51.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/4a428d7d-5195-930d-98f0-6ebea434f453.png)

Webhook URLを設定する画面になるので、herokuのURLを指定する。

![スクリーンショット 2021-04-30 16.51.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/c113adee-1e3c-69ba-06af-fb259435b837.png)

URLを設定したら、「検証」を押して、Webhookが動作するかを確認する。
![スクリーンショット 2021-04-30 16.52.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/5115a34a-720e-6637-ef96-5aac669d1c8f.png)

動作する場合は以下のように表示される。
![スクリーンショット 2021-04-30 17.19.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/3a213213-8da4-7d3e-6164-6f7b269f65a7.png)

以下のようなエラーが表示された場合は、コマンドラインから`heloku logs`コマンドを実行するなどして、エラー内容を確認して対処する。
![スクリーンショット 2021-04-30 17.16.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/b22d5d4f-dbbd-efd4-ab5f-ce0e298805f0.png)

確認後、Webhookの利用のスイッチを有効にする。
![スクリーンショット 2021-04-30 17.32.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/a07a1586-e0bf-3179-e139-e8b37c6f360e.png)

設定後、LINEからメッセージ送信すると、Webhookで設定した応答もLINEに返されるようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/b53ca8b3-bd6f-b173-5a80-e68aeec95eac.png)

上記は、LINEの応答メッセージとWebhookが両方返されている。
Webhookのみを有効にする場合は、Line Developersの設定で応答メッセージをオフにする。

![スクリーンショット 2021-04-30 17.34.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6889/ee28c36a-5e75-843f-7fd6-bf5a4228d866.png)


## 参考

https://developers.line.biz/ja/docs/messaging-api/getting-started/

https://developers.line.biz/ja/docs/messaging-api/building-bot/

https://qiita.com/nkjm/items/38808bbc97d6927837cd

https://www.casleyconsulting.co.jp/blog/engineer/3028/

https://github.com/line/line-bot-sdk-python/blob/master/README.rst

https://qiita.com/m_rn/items/9a580d04781b34f64693