はじめに
傘を持たずに出掛けて、午後から雨が降ってしまって困ることありますよね。
天気予報を朝見れば良いのでしょうが、少し面倒です。
というわけで、AWSの無料枠を使って自分への通知用のLINE Botを作ろうと思いました。
朝、天気予報サイトのデータを自動でスクレイピングして、予報が雨なら「今日は傘が必要です」というようなメッセージが配信されるようなイメージです。他にも電車の遅延状況の通知もできたら便利そうです。(既にこのようなサービスはありそうですが。。)
今回の内容
AWSもLine APIもそこまで触ったことがないので、まずは簡単な部分から実装を目指します。
今回の記事では図のようなAWS環境を構築しました。
2つあるLambdaの機能はそれぞれ以下のとおりです。使用言語はPythonです。
- 返信用(reply_message関数):単純なオウム返しの機能
- 配信用(push_message関数):定型文の配信
実装編
LINE Botを作るには、まずLINE Developersコンソールにログインして、チャネルを作る必要があります。チャネルの作り方は以下の公式ドキュメントに書かれています。
今回はMessaging APIを利用する方式にしています。そうするとWebhook URL(LINEプラットフォームからボットにイベントを送信する際の送信先URL)を設定できるようになります。
このWebhook URLに、reply_message関数呼び出し用のAPI GatewayのURLを指定することで、登録ユーザーのチャットに返信できるようになります。
AWS Lambdaの実装
Python SDK
LINE Botの作成用には、以下のようなMessaging APIのSDKがあります。
今回はPythonを使用するため、こちらの公式Python SDKを利用します。
Lambdaで外部パッケージを利用する方法はいくつかあるようですが、今回はLambdaレイヤーを利用する方法を採用しました。レイヤーにzip化したパッケージをアップロードすることで、複数のLambdaで共通してパッケージを利用できるようになります。
Lambdaはレイヤーのpythonディレクトリにあるパッケージを読み込みます。そのため、以下のようなコマンドでzipファイルを作成し、用意したレイヤーにアップロードします。
#pythonディレクトリにパッケージをインストール
$ pip install line-bot-sdk -t ./python
#pythonディレクトリごとzip化(ファイル名は何でも良い)
$ zip -r extra_package.zip ./python/
(補足)開発環境
- Ubuntu 20.04.4 LTS
- Python 3.10.4
- line-bot-sdkパッケージ 2.3.0
- Lambdaランタイム python3.9
reply_message関数
まずは単純なオウム返しの機能を持つreply_message関数を実装します。
事前の準備として、上で用意したレイヤーを参照するようにしておきます。また、以下の環境変数を追加します。どちらもLINE Developersコンソールから値を取得できます。
- CHANNEL_ACCESS_TOKEN:チャネルのアクセストークン(今回はlong-lived版を使用)
- CHANNEL_SECRET:チャネルのシークレット
reply_message関数に登録したソースコードは以下のようになります。テキストメッセージを受信したら、同じテキストを返信する処理を実装しています。
import os
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
# LINE BotのAPI
line_bot_api = LineBotApi(os.environ['CHANNEL_ACCESS_TOKEN'])
# Webhook(メッセージ等のイベント)のハンドラー
handler = WebhookHandler(os.environ['CHANNEL_SECRET'])
def lambda_handler(event, context):
# LINE Platformから送信されるリクエストの署名とボデイ
signature = event['headers']['x-line-signature']
body = event['body']
# ハンドラーにより署名を検証してWebhookを処理する
try:
handler.handle(body, signature)
except InvalidSignatureError:
print("Invalid signature. Please check your channel access token/channel secret.")
return {
'statusCode': 400
}
return {
'statusCode': 200,
}
# ハンドラーにテキスト型メッセージを受信した場合の処理を追加
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
# 受信したメッセージに対して同じテキストを返信
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
(補足)Webhookについて
Webhookというのは、LINE Platformで発生したイベントを他システムに送信する仕組みのことです。今回は、Webhook URLとして指定したreply_message関数(API Gateway経由)にイベントが送信されます。イベントにはLINE Botのフォローや、メッセージ送信などがあります。使用したLINE Bot SDKでは、Webhookハンドラーに対して、デコレータを使ってWebhookイベントに対する処理を実装していきます。
push_message関数
次に定型文を配信する機能を持つpush_message関数を実装します。
reply_message関数と同様に、事前の準備としてレイヤーの参照と、環境変数の登録を行います。
push_message関数に登録したソースコードは以下のようになります。このLambda関数が実行されると"Hello World"というメッセージが自分に対して送信されます。ちなみに、自分のLINEユーザIDはreply_message関数の実行ログなどから確認できます(print関数などでbodyを出力しておくとCloudWatchログから見えます)。
import os
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import LineBotApiError
from linebot.models import TextSendMessage
# LINE BotのAPI
line_bot_api = LineBotApi(os.environ['CHANNEL_ACCESS_TOKEN'])
def lambda_handler(event, context):
# 送信先のLINEユーザーID
user_id = {自分のLINEユーザID}
try:
# メッセージの送信
line_bot_api.push_message(
user_id, TextSendMessage(text='Hello World!'))
except LineBotApiError as e:
# error handle
print("Failure push message.")
return {
'statusCode': 400
}
return {
'statusCode': 200
}
動作の確認
実際に作成したLINE Botを友達登録して動作確認してみました。
送信したテキストメッセージと同じメッセージが返信されています。また、push_message関数を起動すると定型メッセージが配信されています。正しく動いているようです(よかった!)。
おわりに
今回はAWS LambdaとPythonを使って簡単な機能のLINE Botを作ってみました。
今後はもともとの目的だった天気情報のスクレイピングや、DynamoDBを使ってユーザ情報の管理などを試してみたいです。
(続く)