5
5

More than 3 years have passed since last update.

【Lambda】毎朝天気を教えてくれるLINEBot!【サーバーレス】

Last updated at Posted at 2020-06-14

前提

  • AWSアカウントを持っている
  • AWSの基礎知識
  • Pythonの基礎知識
  • APIの基礎知識

作ったもの

天気を取得し毎朝7時にLINEに通知するbot!
※ 母が「毎朝天気知りたい」と言っていたので作成することにしました。

weather_forecast_LINE_bot.png
※ テスト中の画像

技術選定(この記事で学べること)

  • 天気を取得し → OpenWeatherMapのAPI
  • 毎朝7時に → CloudWatch Events + Lambda
  • LINEに通知する → LINE Notify

いざ、実装

実装上、APIキーやアクセストークンの取得が先になるため、説明の順番が前後します。説明の順番は以下の通りです。

  1. OpenWeatherMapのAPIによる天気の取得
  2. LINE NotifyによるLINEへの通知
  3. Lambda関数の作成
  4. Lambda関数の編集
  5. CloudWatch Eventsの設定

天気の取得

OpenWeatherMapのAPIの利用には、OpenWeatherMapに登録することで得られるAPIキーが必要!

  1. ここから登録
  2. サインインしてAPI keysタブでAPIキーを確認
  3. あとで必要となるのでコピーしておく

参考:無料お天気APIで簡単スクレイピング

LINEへの通知

LINE Notifyの利用には、LINE Notifyにログインすることで得られるアクセストークンが必要!

また、LINE Notifyと友達になっておく必要があります。
(このLINE Notifyからメッセージが送られてくる。)

  1. LINE Notifyにログインしマイページへ
  2. ページ下部のトークンを発行するからトークンを発行
  3. あとで必要となるのでコピーしておく

参考:PythonでLINEにメッセージを送る

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関数の編集

説明上、先にソースコードをお見せします。ソースコードは以下の通りです。

ソースコード
lambda_function.py
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では通常、外部ライブラリ(今回でいうbs4requests)の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 式を使う場合は時差に気をつける/具体例

完成!

これにて実装完了となります、お疲れ様でした!
ボリュームを抑えるために、ところどころ説明を端折っており、少々分かりづらいかも知れません。
ご感想、ご質問等があればぜひコメントをお寄せください😊

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5