ブログに3日間書き込みしなかったら催促メールを送る
AWS Lambdaを使って、定期的にブログのトップページをチェック。 3日間書き込みがなかったら、催促メールを送り続ける。
あまり嬉しくないプログラムを作成します。
概要
大まかな流れは以下になります。
- CloudWatch Events が定期的にLambda関数を実行
- ブログのトップページから最新(最終)エントリ日を取得
- 3日間経過していたらメール送信
Lambda関数を作成する前に、下準備をします。
メール送信の準備
メールが送信できるように、Amazon SNSでトピックを作成してメール用のサブスクリプションを準備します。
トピックの作成
マネジメントコンソールから、サービス [アプリケーション統合] - [Simple Notification Service] を選択します。
トピックを選択して、[新しいトピックの作成] ボタンをクリック
トピック名を入力して[トピックの作成] ボタンをクリック
トピックが作成されます。
サブスクリプションの作成
トピック一覧から作成したトピックのARN
リンクをクリックして、トピックの詳細を開きます。
[サブスクリプションの作成] ボタンをクリックします。
プロトコルとエンドポイントを入力します。
- プロトコル:
Email
- エンドポイント:
送信したいメールアドレス
[サブスクリプションの作成]ボタンをクリックすると、確認用のメールが送信されます。
メール内のConfirm subscription
リンクをクリックすると確認済となり、これで利用可能となります。
メールの確認
メールが受信できるか確認します。
トピックの詳細画面、左上の [トピックに発行] ボタンをクリック
件名とメッセージを入力して [メッセージの発行] ボタンをクリック
メールが届いたら成功です。
トピックARN
は後で利用するので、メモ(コピー)しておいてください。
ロールの準備
Lambdaからメール送信ができるように、IAMロールを作成します。
マネジメントコンソールから、サービス [セキュリティ、 アイデンティティ、 コンプライアンス] - [IAM] を選択します。
サイドパネルの [ロール] から、[ロールの作成] ボタンをクリックします。
ロールを使用するサービスを選択
AWSサービスのLambdaを選択して、[次のステップ:アクセス権限] ボタンをクリックします。
ポリシーの割り当て
Lambdaからメール送信ができるように、以下のポリシーにチェックをつけます。
- AWSLambdaBasicExecutionRole
- AmazonSNSFullAccess
ポリシーのフィルタで絞り込むと探しやすいです。
ロールの確認と作成
ロール名 lambda-check-entry-date
を入力し、ポリシーを確認。
問題がなければ、[ロールの作成] ボタンをクリックします。
以上で下準備は終わりです。
今回もAWS Cloud9上から作成していきます。
ローカル上にLambda関数を作成
ローカル上にLambda関数を作成します。
右側サイドバーにある、[AWS Resources] を選択して [AWSリソース] ウィンドウを開き、[λ+] ボタンをクリックします。
- 関数名
- checkEntryDate
- アプリケーション名
- CheckEntryDate
- ランタイム
- Python 3.6
- 設計図
- hello-world-python3
- 関数トリガー
- none
- メモリ
- 128MB
- ロール
- Choose an existing role
- lambda-check-entry-date (下準備で作成したロール)
- Choose an existing role
外部モジュールのインストール
Pythonの外部モジュールをインストールします。
- Requests
- 使い勝手のよいHTTPライブラリ
- Beautiful Soup
- スクレイピングでよく使われるHTMLパーサー
- dateutils
- 日付操作用ライブラリ
- pytz
- タイムゾーンライブラリ
ターミナルから、CheckBlog
ディレクトリ直下にインストールします。
$ cd CheckBlog/ $ pip-3.6 install requests -t . $ pip-3.6 install beautifulsoup4 -t . $ pip-3.6 install dateutils -t . $ pip-3.6 install pytz -t .
-t
はどこにインストールするかのターゲットを、.
はカレントディレクトリを意味します。
必要なモジュールがインストールされました。
template.yaml
template.yaml に環境変数とスケジュールを登録します。
環境変数の使い方は、下記のエントリを参照してください。
AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: An AWS Serverless Specification template describing your function. Resources: checkBlog: Type: 'AWS::Serverless::Function' Properties: Handler: checkBlog/lambda_function.lambda_handler Runtime: python3.6 Description: '' MemorySize: 128 Timeout: 15 Role: 'arn:aws:iam::123456789012:role/lambda-check-entry-date' CodeUri: .debug/ Environment: Variables: site: 'https://oreout.hatenablog.com' period: '3' topic: 'arn:aws:sns:ap-northeast-1:123456789012:check_blog' subject: '俺の通知' body: | 何怠けとるねん! そろそろブログを更新して! Events: CheckBlogScheduledEvent: Type: Schedule Properties: Schedule: rate(6 hours)
環境変数
- site
- チェックするブログのトップページ
- period
- 最終投稿日からの何日間で判定するか
- topic
- メール送信の準備て作成した
トピックARN
- メール送信の準備て作成した
- subject
- メール件名
- body
- メール本文 (改行する場合はパイプ
|
を定義して次行に本文)
- メール本文 (改行する場合はパイプ
スケジュール
起動する間隔をRate式で定義します。
rate(数値 単位)
単位は 分
、時
、日
を指定できます。
注意点として、数値が複数の場合は、単位が複数形になります。
Rate式は Rate または Cron を使用したスケジュール式 を参照してください。
Lambda関数
下記コードに差し替えて、保存 (Command+S) します。
サンプルのため、例外処理は考慮していません。
lambda_function.py
import boto3 import os import requests from bs4 import BeautifulSoup from datetime import datetime from dateutil import relativedelta from dateutil import parser from pytz import timezone SITE = os.environ['site'] PERIOD = int(os.environ['period']) TOPIC = os.environ['topic'] SUBJECT = os.environ['subject'] BODY = os.environ['body'] def lambda_handler(event, context): r = requests.get(SITE) soup = BeautifulSoup(r.text, 'html.parser') entry = soup.find('time').get('datetime') # 最後の投稿日 latest = parser.parse(entry).date() # N日前 target = datetime.now(timezone('Asia/Tokyo')) - relativedelta.relativedelta(days=PERIOD) target = target.date() if target > latest: sns = boto3.client('sns') sns.publish(TopicArn=TOPIC, Subject=SUBJECT, Message=BODY) return False else: return True
- requestsでブログのトップページをGET
- レスポンス結果をBeautifulSoupに渡してHTMLパース
- 最初のtimeタグ(投稿日の降順)を取得して、datetime属性の値(日付)を取得
- 現在日と比較してN日間経過している場合はメール送信
実行とデプロイ
ローカルで実行確認、問題がなければデプロイします。
ローカルの実行、デプロイの仕方は、下記のエントリを参照してください。
これで、ブログをさぼっていたら、催促メールが飛んでくるようになりました。