drilldripper’s blog

ソフトウェア開発と人生をやっていきます

AWS Lambdaを使ってサーバレスにWebサイトを監視してSlackに通知する

Webサイトの状況を監視するためのスクリプトを動かしたいというシチュエーションが発生することがあります。典型的な例としてECサイトの在庫監視などがあると思います。この文章を読んでいる人の中には、Nintendo Switchの在庫状況を監視して通知するスクリプトを動かしている人もいるもいるのではないでしょうか。*1

在庫確認のようなシチュエーションでは常時起動しているPC、すなわちサーバに相当するものを用意しなければなりません。VPSを借りる人も多いと思いますが、スクリプトを動かすだけに使用するには少々オーバースペックです。

そこで今回はAWS Lamdaを使って安価にサーバレスでサイトの在庫状況を監視するシステムを構築します。例としてNintendo Switchの在庫状況を通知するシステムを作ります。

おそらく無料枠内で収まると思いますが、無料枠を超えたとしてもAWS Lambda自体がかなり安価なので、VPSを借りるよりも安価になることが多いはずです。

構成

AWS Lambda上で実行することができる言語の一つ、Pythonスクリプトを記述します。スクリプトの中に通知をとばす処理を記述しておきます。今回はSlackに通知します。

その後スクリプトを使用するライブラリを含めてアップロードを行い、Cloud Watchをトリガーにして一定間隔でAWS Lambdaを実行します。

構成図は以下のようになります。 f:id:drilldripper:20170708210908p:plain

スクリプト

スクレイピングが明示的に禁止されているサイトは実行しないでください。*2

最初に使用するライブラリをpip installでインストールします。

pip install requests -t .
pip install beautifulsoup4 -t .
pip install slackweb -t .

AWS Lambdaではライブラリを含めたフォルダをzipでまとめてアップロードする必要があるので、-tオプションでカレントディレクトリを指定しています。

次に実行したいスクリプトを書きます。

import requests
import slackweb
from bs4 import BeautifulSoup


def buy_bot(event, context):
    # Camouflage User Agent
    user_agent = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; NP06; rv:11.0) like Gecko"
    }

    # merchandise URLs
    # Example: Checking Joshin switch stock
    joshin_url = [
        "http://joshinweb.jp/game/40519/4902370535716.html",  # Neon Blue
        "http://joshinweb.jp/game/40519/4902370535709.html",  # Gray
    ]

    # Incoming Webhook API key
    slack = slackweb.Slack(url="INCOMING WEBHOOKS API KEY ")
    # slack.notify(text="From Python to Slack") # DEBUG

    # Joshinサイトの監視
    for url in joshin_url:
        html = requests.get(url, headers=user_agent)
        html.encoding = html.apparent_encoding
        html = html.text
        soup = BeautifulSoup(html, "html.parser")
        detail = soup.find("form",{"name":"cart_button"}).text
        if not ("販売休止中です" in detail):  # Check stock messages
            slack.notify(text="Joshin: Nintendo Switch is available now. \n" + url)

Beautiful Soupでスクレイピングを行い、販売が休止していないときにIncoming WebhooksのAPIを使って在庫が存在していることをSlackのチャンネルへ通知します。Incoming Webhooksの仕様は公式ドキュメントを参考にしてください。

api.slack.com

また関数がdef buy_bot(event, context)のように宣言されていますが、このeventcontextAWS Lambdaのイベントをハンドルするために必要な引数となります。

AWS Lambdaの設定

ハンドラ

スクリプトをzipで圧縮し、AWS Lambda上にアップロードします。アップロードが終わったら関数がハンドラを受け取れるように設定を変更します。

f:id:drilldripper:20170708210839p:plain ハンドラは<ファイル名><メソッド名>で記述します。例で使用したスクリプトであればbuybot.buy_botとなります。ロールはlambda_exec_roleにします。

タイムアウトとリソース

デフォルトの設定ではリソースが足りずにタイムアウトしてしまうので、設定でメモリを増やしてタイムアウトの時間を長くします。

f:id:drilldripper:20170708211012p:plain

なおAWS Lambdaはメモリを増やすことでCPUの性能が増加する仕様になっています。

よくある質問 - AWS Lambda | AWS

トリガー

次にAWS Lambdaを動かすためのトリガーを設定します。Lambdaを一定間隔で実行するためにCloudWatch Eventsを使用します。ここではおなじみのcron式を使うことができます。

f:id:drilldripper:20170708211037p:plain スクレイピングを行う場合、サイトに迷惑がかからないように十分な間隔を開けましょう。

今回のスクリプトは1分間に1回だけ実行するようにしました。次のようなcron式になります。

cron(*/1 * * * *)

まとめ

とても簡単にサーバレスな監視システムを作ることができました。EC2やVPSなどを使って1からシステムを作る場合はサーバーの構築などを行わないといけないので、それに比べると気軽に動かすことができていい感じですね。

参考

switchが入荷したらLINEで通知するプログラムを作った - Qiita

Amazon Web Services クラウドネイティブ・アプリケーション開発技法 一番大切な知識と技術が身につく (Informatics&IDEA)

Amazon Web Services クラウドネイティブ・アプリケーション開発技法 一番大切な知識と技術が身につく (Informatics&IDEA)

*1:ちなみに私はSwitchをまだ持っていません。欲しいです。

*2:例えばAmazonスクレイピングが禁止されています

https://www.amazon.co.jp/gp/help/customer/display.html?nodeId=201909000