いろいろなサービスを使ってLINEbotを作ろう【ngrok編】


概要

LINEbotのバックエンドをさまざまなサービスを利用して作ってみようというシリーズです。
第1弾はngrokを利用します。
また今回の記事に限り、導入編としてLINE Developersへの登録などの手順も記載に含めます。

そのほかのサービスを利用した構築については、以下を参照ください。

  • 第1弾:ngrok ※本記事
  • 第2弾:Heroku
  • 第3弾:Google CloudFunctions ※近日更新
  • 第4弾:Google Cloud Run
  • 第5弾:Google Kubernetes Engine
  • 第6弾:AWS Lambda (予定)

前提

  • LINEのアカウントを持っている
  • ローカルでPythonが実行可能な状態である

全体像

LINE Developers準備

2020/10時点でのキャプチャ・手順です。今後、変更が出る可能性がある点はご留意ください。

ログイン

Messaging APIを利用するため、まずはLINE Developersへアカウント登録をしましょう。
まず、こちらへアクセスし、右上のログインボタンを押下します。
次の画面では、「LINEアカウントでログイン」を押下します。
すると以下のような画面が表示されるので、LINEに登録しているメールアドレス・パスワードを入力するか、QRコードをスキャンするかのいずれかの方法でログインをします。成功すれば、コンソールのホーム画面へ遷移します。

Channel作成

ホーム画面にProvidersというセクションがあるので、横の「Create」ボタンを押下し、Provider name欄に任意の名称を入力します。
※作成に失敗するケースは、名称に問題があるので、適宜変更をしてみてください。

Providerのホーム画面へ遷移するので、「Create a Messaging API Channel」ブロックを押下します。

情報の入力画面に遷移するので、以下を入力します(必要最低限の項目のみ記載)。

  • Channel icon:アイコン、必須ではないけれど白アイコンは寂しいので、なんでもよいから設定しておきたい
  • Channel name:チャンネルの名前、任意の名称でOK
  • Channel description:チャンネルの説明、「LINE Bot練習用」などでOK
  • Category:チャンネルのカテゴリ、なんでもよいが困ったら「個人」
  • Subcategory:チャンネルのサブカテゴリ、なんでもよいが困ったら「個人(その他)」
  • 最下部の規約リンクを確認、チェックボックスをONにする(2箇所)

Channel SecretとChannel Access Tokenの発行

バックエンドで利用するので、この段階で発行しておきます。
なお、この2つの値は他人に知られないように慎重に保管するようにしてください。

  • Channel Secret

Basic settingsタブのChannel secret部分の文字列です。こちらはチャンネルを作成した段階で発行されています。

  • Channel Access Token

Messaging APIタブ最下部のChannel access token部分の文字列です。こちらはデフォルトでは発行されていないので、「Issue」ボタンを押下して生成しましょう。

友だち登録

Messaging APIタブにQRコードがあるので、LINEアプリでスキャンして友だち登録しておきましょう。

バックエンドサーバの構築

ソースコード

line-bot-sdk-pythonのコードをコピーして、ローカルにapp.pyという名前で保存します。
そして、以下のようにシークレット情報を設定します。

  • YOUR_CHANNEL_SECRETと書かれている部分(L16)をChannel secretで取得した文字列に置き換える
  • YOUR_CHANNEL_ACCESS_TOKENと書かれている部分(L15)をChannel access tokenで取得した文字列に置き換える
app.py
# 例
line_bot_api = LineBotApi('YXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXZGG==') # こっちが長い方の文字列
handler = WebhookHandler('fxxxxxxxxxxxxxxxxxxxxx')

※本編ではローカルでのみ起動することを想定しているため、ソースコードにベタ書きしますが、アンチパターンである点ご注意ください。

ライブラリインストール

ソースコードはライブラリを利用しているので、ライブラリのインストールが必要です。ターミナルで次のコマンドを実行します。

Terminal
pip install Flask line-bot-sdk

ngrokのインストール

ngrokとは一言でいうと、ローカルで起動しているプロセスへインターネットを介して外部からアクセスできるようにサービスです。なにより、httpsでの公開エンドポイントが用意される点が非常に大きいです。(WebhookURLはhttpsである必要がある)

MacOSの場合は1つめのHomebrewでインストールすることをおすすめします。そのほかは2つめのコマンドでインストールします。

MacOSの場合

Terminal
brew cask install ngrok

その他の場合

Terminal
wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
unzip ngrok-stable-linux-amd64.zip
mv ngrok /usr/local/bin/ngrok

インストール確認

正しくインストールされているか確認しておきましょう。ngrokコマンドを実行し、下のような表示が出ていれば問題ありません。
停止する際はCtrl + Cを入力します。

Terminal
ngrok http 80

実行結果

Terminal
ngrok by @inconshreveable                                                                                                                                                                          (Ctrl+C to quit)

Session Status                online                                                                                                                                                                               
Session Expires               7 hours, 59 minutes                                                                                                                                                                  
Version                       2.3.35                                                                                                                                                                               
Region                        United States (us)                                                                                                                                                                   
Web Interface                 http://127.0.0.1:4040                                                                                                                                                                
Forwarding                    http://a9e65703bdfa.ngrok.io -> http://localhost:80                                                                                                                                  
Forwarding                    https://a9e65703bdfa.ngrok.io -> http://localhost:80                                                                                                                                 

Connections                   ttl     opn     rt1     rt5     p50     p90                                                                                                                                          
                              0       0       0.00    0.00    0.00    0.00 

オウム返しさせる

では、いよいよサーバを立ち上げて、メッセージがオウム返しされるところを確認しましょう。

バックエンドサーバの起動

ターミナルで以下のコマンドを実行します。
なお、Pythonのファイル名がapp.pyではない場合は、環境変数FLASK_APPにそのファイル名を設定する必要があります。

Terminal
flask run --reload --port 8080

# 以下のように表示されていれば、起動状態
* Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)

現在の状態を図にすると以下となります。

サーバの外部公開

別のターミナルを起動して、以下のコマンドを実行します。
そして、Forwardingと書かれている行のhttpsで始まる側のURLをコピーします。

Terminal
ngrok http 8080

Forwarding    http://e5e58099a87e.ngrok.io -> http://localhost:8080                     
Forwarding    https://e5e58099a87e.ngrok.io -> http://localhost:8080 # こっち

現在の状態を図にすると以下となります。

WebhookURLの設定

ここで一度LINE Developersの画面に戻ります。
Messaging APIタブのWebhook URLの部分に「先程コピーしたURL + /callback」を入力します。

また、上記画像のEditボタンから応答設定画面へ遷移し、次のように設定してください。

  • 応答メッセージ:OFF
  • Webhook:ON

これでLINEへメッセージを送るとngrokエンドポイントを経由し、ローカルで起動しているサーバへリクエストが飛ぶようになりました。

メッセージを送る

友だち登録しておいたBotで実際にメッセージを送ってみましょう。同じメッセージが返ってくれば成功です!!

注意点

ngrokは起動するたびに異なるエンドポイントを発行するため、一度終了したのちに再度起動した場合はLINE DevelopersのWebhookURLもあわせて修正する必要があります。

ステップアップ

ソースコードについての解説は省きましたが、sdkのソースコードではテキストメッセージのオウム返しをするのみでした。
ステップアップとして挙動を変更する以下の2例を課題的に記載しておきますので、よろしければチャレンジしてみてください。

1. 常に「メッセージありがとう!」と返事をするようにする

こたえ

handle_message関数のtextで指定している値が返事の内容となります。
もともとのソースではevent.message.textが設定されており、このevent.message.textというものはこちらが送信したメッセージの内容なのでオウム返しとなっていたわけですね。
つまりはtextに「メッセージありがとう!」と設定すればよいです。

app.py
def handle_message(event):
    line_bot_api.reply_message(
        event.reply_token,
-        TextSendMessage(text=event.message.text))
+        TextSendMessage(text='メッセージありがとう!'))

2. スタンプを送ったら、「かわいいスタンプだね」と返事するようにする

こたえ

なぜテキストメッセージだけがハンドリングされているかというと、@handler.add(MessageEvent, message=TextMessage)のデコレータで、WebhookHandlerに「TextMessage種別のメッセージイベントが来た場合は、handle_message関数の処理を行う」というようにしているためです。
これと同じ要領でスタンプ種別(StickerMessage)のイベントを処理する関数を追加すればよいです。

app.py
+ @handler.add(MessageEvent, message=StickerMessage)
+ def handle_sticker_message(event):
+     line_bot_api.reply_message(
+         event.reply_token,
+         TextSendMessage(text='かわいいスタンプだね'))

ほかにどのようなイベント種別・メッセージ種別があるのかはAPI仕様を見ると良いでしょう。

おわりに

ローカルで手軽に動作確認ができる点は非常によいと思います。
しかしながら、ずっとローカルで起動している必要があったり、起動するたびにWebhookURLを設定し直すのはメンドウですよね。
クラウドサービスを用いてサーバ起動することでこの手のメンドウは解決することが可能ですので、次回以降触れていきたいと思います。