プログラムの概要
LINE BOTの最も簡単な例として、オウム返しをするシンプルなBOTを作成します。オウム返しBOTはLINE公式でサンプルとして公開されており、そのサンプルを実際のサーバー上で動作させるために少し改良を加えコードについて解説します。
PythonによるLINE BOTの開発
LINE BOTをPythonで開発するときには、LINE公式から公開されているLINE Messaging API SDK for Python(line-bot-sdk-python)という外部ライブラリを利用するのが便利です。
このライブラリは、FlaskやDjangoなどのWebフレームワークと組み合わせて使うのが基本です。ただし、LINE BOTはそれらのWebフレームワークの知識がなくても開発が行える簡単なものです。当サイトのLINE BOTの記事でもFlaskを合わせて利用しますが、Flaskの知識がなくても理解できるように解説を行っています。
なお、当サイトではFlaskの解説も行っているので、興味があれば参考にしてください。
外部ライブラリなので、インストールも忘れずにしておきましょう。
pip install line-bot-sdk
pip install flask
オウム返しのサンプルコード
先ほどのLINE Messaging API SDK for PythonのGithubページのトップにサンプルコードが公開されているので、まずはそれを見てみましょう。
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
app = Flask(__name__)
line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
if __name__ == "__main__":
app.run()
上のコードはサンプルコードをそのまま貼り付けたものです。 このままでもローカル環境では動作しますが、実際にサーバーで動かす際にはいくつか問題があるので、改良を加えるとともに各コードの解説を行います。
サンプルプログラムを改良
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
import os
まずファイルの読み書きやOS関連の操作を行うための標準ライブラリであるosを13行目に追記してインポートします。
app = Flask(__name__)
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]
line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)
次に、LINE BOTに接続する際の認証に利用するアクセストークンとチャンネルシークレットの設定部分を追記・修正します。
元のコードの'YOUR_CHANNEL_ACCESS_TOKEN', 'YOUR_CHANNEL_SECRET'の部分にそのままアクセストークン・チャンネルシークレットの文字列を入れても動作します。しかし、プログラムに直接認証情報を書くのはセキュリティ上良くないので、環境変数に認証情報を設定し、os.environによって環境変数を取得するコードを17~18行目に追記します。
20~21行目の引数を文字列から変数に変更するのも忘れないでください。
app = Flask(__name__)
15行目では、FlaskというWebフレームワーク内で定義されているクラス(Flask)のインスタンスを作成し、変数appに代入しています。コードの意味は、クラスについて理解していないとよくわからないと思われるので、まだ入門者でよく理解できていない方は最初に書く決まり文句だと思っておけばいいでしょう。
@app.route("/")
def hello_world():
return "hello world!"
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
次に27行目の@app.route("/callback", methods=['POST'])の文の上に、23~25行目の@app.route("/")から始まる3行を追加します。
この3行は、サーバーのトップページにアクセスすると「hello, world!」という文章を表示するプログラムです。あってもなくても問題ありませんが、コード上に致命的なエラーがないか、サーバーが正常に稼働しているか等、手っ取り早く動作確認する際には有用となります。テストとして入れるものなので実際に稼働させる際は省いてください。
27行目からの部分は、LINEからのリクエストを受信して認証関係のチェックを行う場所とだけ理解しておけばいいかと思います。サンプルプログラムから変更する必要はありません。
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
ここはLINE BOTの応答が書かれている部分です。実際にLINE BOTを開発する際にはこの部分にコードを書いていくことになります。
サンプルでは、ユーザーからテキストメッセージを受信するとそのテキストをそのままオウム返しするという意味のコードになっています。
45行目の@handler.add(MessageEvent, message=TextMessage)はテキストメッセージを受け取った場合、という意味になります。
その次の行で定義した関数 (関数名は任意) 内に、テキストメッセージを受け取った場合の処理を書いていく決まりとなっています。
@handler.addから始まる部分はif...elif文のようなイメージで場合分けして書くもので、例えば画像メッセージを受け取った場合の処理を分けたいなら、
@handler.add(MessageEvent, message=TextMessage)
def function1(event):
...
@handler.add(MessageEvent, message=ImageMessage)
def function2(event):
...
と、別に書く必要があります。テキストも画像もまとめて処理をしたいなら
@handler.add(MessageEvent, message=(TextMessage, ImageMessage))
def function1(event):
...
と書くことができます。
47行目のline_bot_api.reply_message()はLINE BOTから返信を行うメソッドであり、第一引数をevent.reply_token、第二引数をTextSendMessage(text=msg)と指定することにより変数msgをテキストとして返信するという意味になります。
なお、第一引数に指定するのはBOTからの返信先を特定するIDのようなものであり、メッセージを送信したユーザーに返信するときはevent.reply_tokenと指定します。
画像をLINEから返信したいというような場合は、
line_bot_api.reply_message(event.reply_token,ImageSendMessage())
と、TextSendMessageではなくImageSendMessageを利用します。
なお、テキストではなく画像関係の処理を行いたいときなど、サンプルコード以上の機能を利用したい場合には、
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage, ImageMessage, ImageSendMessage
)
などと冒頭のimport文に追記する必要がある点を忘れないようにしましょう。
今回の49行目のtext=で指定されているevent.message.textは、ユーザーから送られたメッセージという意味です。
他にもevent.message.typeでメッセージタイプ(今回は"text"、画像なら"image")、event.message.idでメッセージIDを取得することなどができます。
if __name__ == "__main__":
port = int(os.getenv("PORT"))
app.run(host="0.0.0.0", port=port)
最後にFlaskの動作部分です。サンプルのままだとホスト名やポート番号が指定されていないのでサーバー上で動作させることができません。
そこでホスト名を「0.0.0.0」と設定し、ポート番号をos.getenv()により環境変数から取得します。
ポート番号を直接書くコードも他のサイトやブログ記事で見受けられますが、Herokuをサーバーとして利用する場合には、ポート番号が動的に割り当てられるので、このように書かないと動作しないことがあります。
コードのまとめ
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
import os
app = Flask(__name__)
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]
line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)
@app.route("/")
def hello_world():
return "hello world!"
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
if __name__ == "__main__":
port = int(os.getenv("PORT"))
app.run(host="0.0.0.0", port=port)
改良したサンプルコードのまとめです。このままコピペすればオウム返しするLINE BOTになりますし、どんなLINE BOTを作る際にもこのコードをもとにプログラムを書いていくことになる基本のコードです。
LINE Messaging APIの詳細解説
LINE Messaging APIを利用したLINE BOTは様々な機能をつけることができます。
noteでは、各機能の詳細解説をしておりますので、ぜひご覧ください。