1. はじめに
本記事は【Python/AWS】の第1回として、
AWSのサービスを利用した一連のデータ分析の初回となります。
私自身、AWSのサービスを触るのは初めてなので、
細かい説明など不足する点はあるかと思いますが、
大まかな流れをこちらで解説していきたいと思います。
5回ほどに分けて投稿していく予定ですが、
分析の全体像は以下のようになります。
全体の分析目的は前回の分析から継続/発展して、
「Splatoon3」におけるコンテンツのユーザー満足度調査 です。
収集したデータから項目ごとに感情分析を行い、
ポジティブ/ネガティブの値を可視化することが最終目的です。
▼前回の記事はこちら▼
1-1. 本記事の概要と目標
初回のテーマは「AWS Lambdaの活用」ということで、
前回トピック分析でも利用したTwitterAPIと組み合わせ、
天気予報を自動ツイートしてくれる仕組みを作ります。
使用するサービスとそれぞれの役割は以下の通りです。
Aystem Maneger: TwitterAPIのkeyなどを安全に保管するために使用
Watch Cloud: Lambdaを実行するタイミングをコントロールするために使用
AWS Lambda: Pythonスクリプトを実行するためのサービス
OpenWeatherMap: 天気に関わる情報を取得できるAPI(AWSサービスではない)
なお本記事ではAWSの登録方法や、
サービス利用に必要な初期設定は取り上げていません。
必要に応じて以下の記事を参考にして下さい。
▼AWSへの登録/IAMロールの作成▼
1-2. 自動実行の流れ
自動実行の順番、流れとしては以下の通りです。
1.Watch Cloudにて毎朝8:00にトリガー
2.Lambdaのスクリプト内で以下を実行
3.System Managerで保管していたTwitterAPIを取得
4.OpenWeatherMapから天気情報を取得
5.取得した天気情報を文章に含めて自動ツイート
2. 実装
大まかなと説明の流れとして、
1.TwitterAPIのkeyをssmに保管
2.Lambda_functionの作成
3.Lambdaへのデプロイ
4.テスト
5.cloud watchの設定
の5段階に分けて確認をしていきます。
2-1.ssmにパラメータを保管
TwitterAPIのkeyやtokenは情報漏れが怖いため、
"Systems Manager"の"parameter store"を使用します。
なお自分がparameter storeを使用した際、
bearer_tokenの文字列が長すぎたためか、
全てを一つにまとめるとうまくいきませんでした。
そのためbearer_tokenのみ、単体で保管しているという状況です。
▼ssm利用時に参考にしたリンク▼
2-2.Lambda_functionの作成
まずは以下がコードの全体像となっています。
import sys
# tweepyをインストールしたディレクトリ相対パスを指定する
sys.path.append('./python_package')
# coding: UTF-8
import json
import tweepy
import boto3
import datetime
from pyowm.owm import OWM
from pyowm.utils.config import get_default_config
from statistics import mode
ssm = boto3.client('ssm', "ap-northeast-1")
weekday_dict = {0:"月曜日", 1:"火曜日", 2:"水曜日", 3:"木曜日", 4:"金曜日", 5:"土曜日", 6:"日曜日"}
def lambda_handler(event, context):
response = ssm.get_parameters(Names=["/credentials/twitter"], WithDecryption=True)
params = json.loads(response['Parameters'][0]['Value'])
bearer_res = ssm.get_parameters(Names=["bearer_token"], WithDecryption=True)
client = tweepy.Client(consumer_key = params["consumer_key"],
consumer_secret = params["consumer_secret"],
access_token = params["access_token"],
access_token_secret = params["access_token_secret"],
bearer_token = bearer_res["Parameters"][0]["Value"]) #文字列が長いとjsonファイルの読み込みでエラーになるため
t_delta = datetime.timedelta(hours=9)
JTS = datetime.timezone(t_delta, "JTS")
now = datetime.datetime.now(JTS)
weekd = weekday_dict[datetime.datetime.weekday(now)]
today = now.strftime("%m/%d") + "(" + weekd[0] + ")"
config_dict = get_default_config()
config_dict["language"] = "ja"
owm = OWM("自分のAPIkey", config_dict)
mgr = owm.weather_manager()
w = mgr.weather_at_place("Tokyo,JP").weather
temp = w.temperature("celsius")["temp_max"]
forecast = mgr.forecast_at_place("Tokyo,JP", "3h").forecast
status_list = []
for weather in forecast.weathers[2:7]:
status_list.append(weather.detailed_status)
today_w = mode(status_list)
tweet_text = "{}\n天気は{}予報で、最高気温予想は{}だそうです。\n今日も一日頑張りましょう。(from lambda)".format(today,today_w, temp)
client.create_tweet(text=tweet_text)
天気予報をツイートするだけなので
とても短い簡単なコードになっています。
コードの流れとしては
1.ssmからtwtterAPIのキーを取得
2.OpenWeatherMapから天気予報情報を取得
3.定型文に取得した情報を含めてツイート
といった具合になっています。
またLambdaを使用する際のルールとして、
lambda_hundler
を必ず定義する必要があります。
これはLambdaが実行される際に最初に実行される関数です。
コードはこの中に含めて書いていきます。
2-2-1.ssmからキーを取得
ssm = boto3.client('ssm', "ap-northeast-1")
response = ssm.get_parameters(Names=["/credentials/twitter"], WithDecryption=True)
params = json.loads(response['Parameters'][0]['Value'])
bearer_res = ssm.get_parameters(Names=["bearer_token"], WithDecryption=True)
client = tweepy.Client(consumer_key = params["consumer_key"],
consumer_secret = params["consumer_secret"],
access_token = params["access_token"],
access_token_secret = params["access_token_secret"],
bearer_token = bearer_res["Parameters"][0]["Value"])
ssmに保管したkey/tokenを取得します。
boto3.client("ssm", "region")
にてクライアントを準備、
get_parameters(Nmes=["*パラメータ名*"])
にて取得できます。
中身はJSONファイル形式なのでjsonで読み込み、
そのままtweepy.Client
の引数に指定しています。
▼SSM(boto3)のドキュメントはこちら▼
2-2-2.OpenWeatherMapから天気情報を取得
config_dict = get_default_config()
config_dict["language"] = "ja"
owm = OWM("*自分のAPIkey*", config_dict)
mgr = owm.weather_manager()
w = mgr.weather_at_place("Tokyo,JP").weather
temp = w.temperature("celsius")["temp_max"]
forecast = mgr.forecast_at_place("Tokyo,JP", "3h").forecast
status_list = []
for weather in forecast.weathers[2:7]:
status_list.append(weather.detailed_status)
today_w = mode(status_list)
今回OpenWeatherMapの詳細については省き、
大まかな説明とさせて頂きます。
ここで行っていることは以下の2点です。
・最高気温予測の取得
・日中の天気予報情報の取得
無料のAPIでは3時間ごとの予報が取得可能のため、
日中の天気予報で最も多かった予報を採用しています。
▼参考ページ▼
2-2-3.取得した情報をツイート
weekday_dict = {0:"月曜日", 1:"火曜日", 2:"水曜日",
3:"木曜日", 4:"金曜日", 5:"土曜日", 6:"日曜日"}
t_delta = datetime.timedelta(hours=9)
JTS = datetime.timezone(t_delta, "JTS")
now = datetime.datetime.now(JTS)
weekd = weekday_dict[datetime.datetime.weekday(now)]
today = now.strftime("%m/%d") + "(" + weekd[0] + ")"
tweet_text = "{}\n天気は{}予報で、最高気温予想は{}だそうです。\n今日も一日頑張りましょう。(from lambda)".format(today,today_w, temp)
client.create_tweet(text=tweet_text)
先に定義した辞書から取得した日時の曜日を取り出し、
"mm/dd(weekday)"のような形に変換する。
【Lambda内の実行時間】
datetime.now()などを使う場合は注意が必要です。
Lambda実行時の日時は日本時間ではなくUTCであるため、
日本時間にするにはtimedeltaを使って(+9h)の調整が必要になります。
あとはこれまでに取得した日付や天気情報を、
定型文にformat関数を用いて挿入してツイートする。
▼create_tweetのリファレンス▼
3. Lambdaへコードをデプロイ
Lambdaの編集画面で直接コードを書くことも可能ですが、
今回は事前に書いたpyファイルをアップロードしていきます。
またLambda内で使用できるモジュールには限りがあるため、
使用するモジュールによっては別で準備する必要があります。
今回はスクリプトのpyファイルと一緒に、
zipファイルに圧縮した状態でLambdaにアップロードします。
なおLambdaへアップロードする際は必ず スクリプトファイルの名前は、
「lambda_function.py」にする 必要があります。
【パッケージをzipする際の注意点】
パッケージとpyファイルをzipファイルに圧縮する際は、
画像のように個別に選択した状態で行います。
(2点を1つのファイルに入れてから圧縮するとエラーになる)
pythonのコードを書いたpyファイルとパッケージを全てまとめて
zipファイルに圧縮し、アップロードします。
今回はとても多くのパッケージを含んでいるため、
非常に大きなzipファイルとなってしまいました。
どうやらレイヤー機能を使うとパッケージを準備せず、
直接Lambda内でimportできるようなのですが、
今回は分かりやすい方法を採用しました。
そしてここで必要になるのが ssm連携の権限設定 です。
きちんと権限を設定しないとこの後のテスト段階で
延々とエラーバトルになるので必ず設定します。
▼Lambdaの権限設定▼
4. Lambdaのテスト
今回は初期設定のテストを行っただけですが、
エラーではなく 「Response」 が表示されていれば成功です。
実際に連携させたtwitterを見てみると、
設定したテキストがツイートされていることが確認できます。
(天気はわりと当たるが、気温は低く出がち?)
5. cloud watchの設定
最後にLambdaのトリガーを設定します。
このLambdaは毎朝8:00きっかりに働いて貰おうと思います。
作成したLambdaの設定から「トリガーを選択」を選びます。
EventBridgeを選択し、
時間をUTCの23:00(日本時間だと+9hで8:00)に設定します。
これで毎朝8:00にLambdaが自動で実行されます。
実際に上に添付したツイートの画像を見てみると、
投稿時間が8:00ジャストであることが分かると思います。
▼EventBridgeの参考リンク▼
6. 所感と今後の展望
6-1. 躓いた点
・サービスの全体像と繋がり
・IAMロールの仕様
・JSONファイルの扱い
今回AWSのサービスに触れるのは初めてで、
自分のやりたいことに対してどのサービスを使うべきか、
その全体像を把握するのがまず躓いた点でした。
サービスの全体像はAWSが以前に公開している
サミットのスライド資料を参考に少しずつ理解しました。
▼2019年サミット資料/動画▼
そして各サービスを連携させるにあたって
必ず必要になるIAMロールや権限の設定の問題。
本記事で権限については触れていませんが、
基本一人での開発ではFullAccessで対処していました。
チームでの開発の場合は各ロールに権限の範囲を
適切に設定することで安全に開発ができると思います。
最後はJSONファイルの扱いについてですが、
これはスクレイピング未経験だったためです。
次回はデータを取得してJSONファイルとして扱い、
S3バケットへの保存をするのでここで一気に学びました。
6-2. 今後の展望
今回は初回ということで基本的なLambdaの使い方について、
前回学んだTwiiterAPIと併せて練習してみました。
次回からはこのLambdaの機能を利用して、
自動でTwitter上からデータを取得する機能 を作ります。
ちなみに今回のコードの応用だけで簡単な
Twitterbotも作れるのでそれだけでも楽しいと思います。
今回詳細は省きながら書かせて頂きましたがいずれは、
・AWSの登録方法
・IAMロールの仕様
・SSMでのパラメータ作成方法
・cloudwatchの仕様
・lambdaのレイヤー
あたりの詳細についても記事を書きたいと考えています。
6-3. さいごに
本記事を読んで頂いてありがとうございました。
コメントや質問、お気軽に宜しくお願い致します。
次回の記事
その他の参考リンク