前提
- AWSアカウントを持っている
- AWSの基礎知識
- Pythonの基礎知識
- APIの基礎知識
作ったもの
天気を取得し毎朝7時にLINEに通知するbot!
※ 母が「毎朝天気知りたい」と言っていたので作成することにしました。
技術選定(この記事で学べること)
- 天気を取得し → OpenWeatherMapのAPI
- 毎朝7時に → CloudWatch Events + Lambda
- LINEに通知する → LINE Notify
いざ、実装
実装上、APIキーやアクセストークンの取得が先になるため、説明の順番が前後します。説明の順番は以下の通りです。
- OpenWeatherMapのAPIによる天気の取得
- LINE NotifyによるLINEへの通知
- Lambda関数の作成
- Lambda関数の編集
- CloudWatch Eventsの設定
天気の取得
OpenWeatherMapのAPIの利用には、OpenWeatherMapに登録することで得られるAPIキーが必要!
- **ここ**から登録
- サインインして
API keys
タブでAPIキーを確認 - あとで必要となるのでコピーしておく
LINEへの通知
LINE Notifyの利用には、LINE Notifyにログインすることで得られるアクセストークンが必要!
また、LINE Notifyと友達になっておく必要があります。
(このLINE Notifyからメッセージが送られてくる。)
- LINE Notifyにログインしマイページへ
- ページ下部の
トークンを発行する
からトークンを発行 - あとで必要となるのでコピーしておく
Lambda関数の作成
AWSマネジメントコンソールからLambda
を開き、 関数の作成
→ 一から作成
。
以下のように設定し、関数の作成
。
- 関数名:weather_forecast_LINE_bot
- ランタイム:Python 3.8
- アクセス権限:
AWS ポリシーテンプレートから新しいロールを作成
- ロール名:lambdaLogRole
- ポリシーテンプレート:
基本的な Lambda@Edge のアクセス権限
※ 基本的な Lambda@Edge のアクセス権限
にはCloudWatchへのアクセス権限が含まれていて、これをアタッチしておくことでCloudWatchにログを記録できるようになります。(例えばprint
等の標準出力はCloudWatchにログとして記録されます。)
参考:API Gateway + LambdaでREST API開発を体験しよう [10分で完成編]/Lambda関数の作成
Lambda関数の編集
説明上、先にソースコードをお見せします。ソースコードは以下の通りです。
ソースコード
from bs4 import BeautifulSoup
import datetime as dt
import requests
def send_line_a_(message):
URL = "https://notify-api.line.me/api/notify"
ACCESS_TOKEN = "<コピーしておいたあなた自身のアクセストークン>"
HEADERS = {"Authorization": "Bearer " + ACCESS_TOKEN}
requests.post(
URL,
headers=HEADERS,
params={"message": message},
)
def get_weather_in_(region):
CORE_URL = "http://api.openweathermap.org/data/2.5/weather"
REGION = f"?q={region},jp"
CUSTOM = "&units=metric&lang=ja&mode=xml"
API_KEY = "&appid=<コピーしておいたあなた自身のAPIキー>"
URL = CORE_URL + REGION + CUSTOM + API_KEY
response = requests.get(URL)
return response.text
def utc2jst_and_parse(lastupdate):
timestamp_utc = lastupdate[:10] + " " + lastupdate[11:]
datetime_utc = dt.datetime.strptime(timestamp_utc + "+0000", "%Y-%m-%d %H:%M:%S%z")
datetime_jst = datetime_utc.astimezone(dt.timezone(dt.timedelta(hours=+9)))
timestamp_jst = dt.datetime.strftime(datetime_jst, '%Y-%m-%d %H:%M:%S')
year = timestamp_jst[:4] + "年"
month = timestamp_jst[5:7] + "月"
day = timestamp_jst[8:10] + "日"
hour = timestamp_jst[11:13] + "時"
minute = timestamp_jst[14:16] + "分"
return year + month + day + " " + hour + minute
def parse_of_(weather_data):
soup = BeautifulSoup(weather_data, "html.parser")
city_name = soup.find("city").get("name")
min_temp = soup.find("temperature").get("min")
max_temp = soup.find("temperature").get("max")
clouds = soup.find("clouds").get("name")
weather = soup.find("weather").get("value")
lastupdate = soup.find("lastupdate").get("value")
date = utc2jst_and_parse(lastupdate)
message1 = f"\n{date}\n現在の{city_name}の気象情報を\nお知らせします。"
message2 = f"\n最低気温: {min_temp}度\n最高気温: {max_temp}度"
message3 = f"\n空模様: {clouds}\n天気: {weather}"
return [message1, message2, message3]
def lambda_handler(event, context):
weather_data = get_weather_in_("<気象情報を知りたい場所>")
messages = parse_of_(weather_data)
for message in messages:
send_line_a_(message)
return {"statusCode": 200, "body": {}}
※ <気象情報を知りたい場所>は「 http://bulk.openweathermap.org/sample/city.list.json.gz 」からDLできるJSONに記載がある場所ならどこでも大丈夫です。(世界各地の天気を知れるなんてすごいAPIだなぁ)
さて、Lambdaでは通常、外部ライブラリ(今回でいうbs4
、requests
)のimport
はできません。標準ライブラリ(今回でいうdatetime
)のimport
は問題なく行えます。
Lambdaで外部ライブラリを使用したい場合、外部ライブラリを実行ファイル(lambda_function.py
)と一緒にzipして、アクション ▼
から.zip ファイルをアップロード
をクリックしてアップロードする必要があります。
for_upload
┣━ bs4
┣━ certifi
┣━ chardet
┣━ idna
┣━ urllib3
┣━ requests
┣━ soupsieve
┗━ lambda_function.py
とにかくLambda上でこのようなディレクトリ構造になっていればOKです。
参考:【Python】AWS Lambdaで外部モジュールを使用する
CloudWatch Eventsの設定
AWSマネジメントコンソールからCloudWatch
を開き、 左ペインのイベント
→ 今すぐ始める
から以下のように設定し、詳細の設定
。
- イベントソース:スケジュールでCron式は
0 22 * * ? *
と設定 - ターゲット:
+ ターゲットの追加 *
から先ほど作ったLambda関数(weather_forecast_LINE_bot)を指定
遷移先で以下のように設定し、ルールの作成
。
- 名前:EveryMorning7
- 説明:毎日7時にトリガー
参考:Amazon CloudWatch Events で cron 式を使う場合は時差に気をつける/具体例
完成!
これにて実装完了となります、お疲れ様でした!
ボリュームを抑えるために、ところどころ説明を端折っており、少々分かりづらいかも知れません。
ご感想、ご質問等があればぜひコメントをお寄せください😊