はじめに
基本的にはこちらを参考にしています。
Lambda関数作成
serverless-chroniumダウンロード
Lambdaの様なサーバレスで動かすヘッドレスなブラウザです。
$ mkdir -p bin/
$ curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-57/stable-headless-chromium-amazonlinux-2.zip > headless-chromium.zip
$ unzip headless-chromium.zip -d bin/
$ rm headless-chromium.zip
chromedriverダウンロード
$ curl -SL https://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zip > chromedriver.zip
$ unzip chromedriver.zip -d bin/
$ rm chromedriver.zip
seleniumダウンロード
Amazon Linux2で動くSeleniumをダウンロードするために、Dockerコンテナを作成します。(Macなどで直接pip install
するとMac用のSeleniumをダウンロードしてしまうから)
下記はそのためのDockerfileです。
FROM lambci/lambda:build-python3.6
ENV AWS_DEFAULT_REGION ap-northeast-1
ENV APP_DIR /var/task
ADD . .
CMD pip install -r requirements.txt -t $APP_DIR && \
zip -9 deploy_package.zip lambda_function.py && \
zip -r9 deploy_package.zip *
requirements.txtを作成する。
selenium
スクショを取得してS3にアップロードするソースコード
from selenium import webdriver
import boto3
def lambda_handler(event, context):
options = webdriver.ChromeOptions()
# のちほどダウンロードするバイナリを指定
options.binary_location = "./bin/headless-chromium"
# headlessで動かすために必要なオプション
options.add_argument("--headless")
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1280x1696")
options.add_argument("--disable-application-cache")
options.add_argument("--disable-infobars")
options.add_argument("--no-sandbox")
options.add_argument("--hide-scrollbars")
options.add_argument("--enable-logging")
options.add_argument("--log-level=0")
options.add_argument("--single-process")
options.add_argument("--ignore-certificate-errors")
options.add_argument("--homedir=/tmp")
# set driver and url
driver = webdriver.Chrome(
"./bin/chromedriver",
chrome_options=options)
url = 'https://www.google.com/search?q=%E6%9D%B1%E4%BA%AC+%E5%A4%A9%E6%B0%97'
driver.get(url)
title = driver.title
# get width and height of the page
w = driver.execute_script("return document.body.scrollWidth;")
# set window size
driver.set_window_size(w,600)
# Get Screen Shot
weather_capture = driver.save_screenshot('/tmp/weather.png')
driver.close()
# s3
s3 = boto3.client('s3')
bucket = '[バケット名]'
s3.upload_file(Filename="/tmp/weather.png",
Bucket=bucket,
Key="weather.png")
return title
下記のコマンドを実行するとLambdaにアップロードするdeploy_package.zipが作成されます。
$ docker build -t lambda_headless_chrome .
$ docker run --rm -v "${PWD}":/var/task lambda_headless_chrome
AWS側の設定
Lambdaリソース設定
aws cliでもGUIでもいいのでLambdaを作成して下さい。
タイムアウト時間は5分、メモリは512MB程度にしないとそもそも動かない可能性があります。
IAMロール設定
Lambdaには実行可能ポリシーに加えて、S3へアップロードしたいので「AmazonS3FullAccess」ポリシーもアタッチして下さい。
S3バケット作成
S3バケットを作成して下さい。また作成したバケット名をlambda_function.pyに記述します。
fonts
このままだと検索結果が文字化けしたままスクリンショットを保存してしまいます。そのため日本語対応したフォントを追加します。ここから「Noto Sans CJK JP」と「Noto Serif CJK JP」の2つをダウンロードして下さい。
以下のディレクトリ階層となるzipを作成します。
$ tree .fonts [master]
.fonts
├── NotoSansCJKjp-Regular.otf
└── NotoSerifCJKjp-Regular.otf
$ zip -r fonts.zip .fonts
これをLambda関数に含めるとファイルサイズが大きくなるのでLambdaレイヤーに配置します。またLambda関数が.fontsディレクトリを認識するために次の環境変数を追加します。
HOME | /opt/ |
テストを実行すると「東京 天気」の検索結果のスクリーンショットがS3に保存されるはずです。
$ aws s3 cp s3://[バケット名]/weather.png ./
$ open weather.png
ルール作成
CloudWatchのルール追加から定期実行をするイベントを作成します。スケジュール方式でCRONを設定し、ターゲットに先程作成したLambdaを登録します。
S3から画像を取得してSlackに送信する
S3にアップロードするLambdaを作ったので、次はS3からSlackに画像を送信するスクリプトを作成したいと思います。Slack APIの詳細についてはこちらをご確認下さい。
まずは先程と同様にLambda関数を作成して下さい。次にコードを書いていきますが、先程のディレクトリをコピーして作成していきます。requirements.txtとlambda_function.pyを次の様に変更します。
requests
import requests
import boto3
import base64
def lambda_handler(event, context):
s3 = boto3.client('s3')
bucket = '[バケット名]'
file_path = 'weather.png'
response = s3.get_object(Bucket=bucket, Key=file_path)
image_data = response['Body'].read()
files = {'file': image_data}
param = {'token': '[トークン]', 'channels': '[チャンネルID]', 'initial_comment': '<@[ユーザーID(メンション用)]>'}
res = requests.post(url="https://slack.com/api/files.upload",params=param, files=files)
return res.text
再度次のコマンドを実行してdeploy_package.zipを作成してLambdaにアップロードして下さい。
$ docker run --rm -v "${PWD}":/var/task lambda_headless_chrome
テストしてSlackに画像がアップロード出来ることを確認したらCloudWatchから先程作ったルールのターゲットに、今回のLambdaを追加します。