본문 바로가기
Cloud/AWS

【AWS】 LambdaとSNSを活用したWEBクローリング&メール送信

by migre 2024. 8. 6.

はじめに

  • AWS EventBridgeを利用して、特定のサイトとキーワードをクロールし、SNSにクロールされたデータを送信する方法を紹介します。
  • API Gatewayを接続することで、キーワードを直接修正でき、データをDynamoDBに保存すれば、クロールされたデータをウェブサイトなどでも閲覧することができます。
  • 本記事では、最も簡単な方法として、トリガーにて毎朝9時にメールで送信します。

結果物


図式化



事前準備

  • SNSの受信には、メールアカウントが必要です。
    (または、SlackやTeamsのチャンネルメールアドレスを利用することも可能です)
  • Lambdaで使用するPythonライブラリをインストールする必要があるため、pipのインストールが必要です。

SNS設定

  • タイプ:スタンダード
  • 名前:任意
  • その他:デフォルト

Lambdaからクローリングされたデータを送信するためのAmazon SNSトピックを作成します。


 
作成されたSNSトピックにサブスクリプションを登録します。
右上の「サブスクリプションの作成」をクリックします。


 

  • ※トピックARN:作成した Amazon SNSのトピック
  • プロトコル:Eメールアドレス
  • エンドポイント:通知先のメールアドレス

 
※ トピックARNはLambdaコードで使用するため、メモ帳などにコピーしておきます。


 

 

 
作成したサブスクリプションのステータスが「保留中確認」になったら、エンドポイントのメールアドレスに認証メールが届きます。


 
メール内の「Confirm subscription」をクリックすると、ステータスが「確認済み」になったことを確認できます。
 


Pythonライブラリー作成(Lambdaレイヤー用)

 

Lambdaは内蔵ライブラリが限られているため、外部ライブラリを使用するにはレイヤーの追加が必要です。レイヤーでライブラリを追加するためには、特定のディレクトリ構造に従って圧縮する必要があります。
参考: レイヤーコンテンツのパッケージング - AWS Lambda (amazon.com)
 

pip install requests beautifulsoup4 -t .
zip -r9 myLayer.zip .

 

myLayer.zip
1.43MB

 

上記のコマンドを使用して、ライブラリを圧縮ファイルにまとめます。


環境構築

Lambda関数作成

 

  • 関数名:任意
  • ランタイム:Python 3.12
  • アーキテクチャ:x86_64
  • その他:デフォルト

先ほど作成したSNSトピックにクローリングデータを送信するためのLambda関数を作成します。
本記事ではPythonを利用してコードを作成します。


 

Lambdaレイヤー作成

 
Lambdaダッシュボードの「その他のリソース」ー「レイヤー」から、右上の「レイヤーの作成」をクリックします。

 

  • 名前:任意
  • .zipファイルをアップロード:myLayer.zip(先ほど作成したPythonライブラリ)
  • 互換性のあるアーキテクチャ:x86_64
  • 互換性のあるアーキテクチャ:Python 3.12

上記の内容でLambdaレイヤーを作成します。


Lambda関数設定

Lambda設定変更

 
Lambda関数へ切り替えて作業を進めます。
「設定」→「一般設定」で「タイムアウト」を「30秒」に変更し、保存します。


Lambdaレイヤー追加

 
「コード」タブー⇒「レイヤー」⇒「レイヤーの追加」をクリックします。


 

 

  • レイヤーソース:カスタムレイヤー
  • カスタムレイヤー:追加したレイヤー
  • バージョン:最新のもの

 
上記の内容で保存します。


 

Lambda送信先追加

 
「送信先を追加」をクリックし、データの送信先になるAmazon SNSを追加します。


 

  • ソース:非同期呼び出し
  • 条件:失敗時
  • 送信先タイプ:SNSトピック
  • 送信先:作成したAmazon SNSのARN

上記の内容で保存します。


Lambdaトリガー追加

 
「トリガーを追加」をクリックし、Lambdaコードを実行するためのEventBridgeを追加します。


 

  • ルール:新規ルールを作成
  • ルールタイプ:スケジュール式
  • ※ スケジュール式:cron(0 0 ? * MON-FRI *)

※ 日本時間毎朝9時に実行されます。(JST⇒UTC)
 
参考:cron 式のリファレンス - Amazon EventBridge
 
上記の内容で保存します。


Lambdaコードを作成

 
Lambdaのコードソースに以下のコードを貼り付けます。


 
※右上の「COPY」を押して簡単にコピーできます。

import json
import requests
from bs4 import BeautifulSoup
import boto3
from datetime import datetime

def lambda_handler(event, context):
    sns_client = boto3.client('sns')
    sns_topic_arn = 'arn:aws:sns:ap-northeast-1:'  #作成したSNSトピックARNに変更

    # デフォルトのURLとキーワードリスト
    default_urls = ['example.com'] #クローラー対象のWEBサイト
    default_keywords = ['AI'] #クローラー対象のWEBキーワード
    
    # Eventから受け取ったURLとキーワードを追加または更新
    urls = event.get('urls', default_urls)
    keywords = event.get('keywords', default_keywords)
    
    # URLとキーワードを重複なくマージ
    urls = list(set(default_urls + urls))
    keywords = list(set(default_keywords + keywords))
    
    all_results = []
    
    for url in urls:
        response = requests.get(url)
        response.raise_for_status()
        
        soup = BeautifulSoup(response.content, 'html.parser')
        
        for keyword in keywords:
            articles = soup.find_all('a', href=True)
            
            for article in articles:
                title = article.get_text().strip()
                link = article['href']
                
                # タイトルがキーワードと完全に一致する場合は除外
                if title.lower() == keyword.lower():
                    continue
                
                if keyword.lower() in title.lower():
                    full_link = link if link.startswith('http') else f"https://www.itmedia.co.jp{link}"
                    all_results.append({'title': title, 'link': full_link})
    
    # 今日の日付を取得
    today = datetime.today().strftime('%Y-%m-%d')
    sns_subject = f"{today}の最新ニュース"
    
    # SNSメッセージのフォーマット
    sns_message = "\n".join([f"タイトル: {result['title']}\nリンク: {result['link']}" for result in all_results])
    
    # SNSを通じてフォーマットされたメッセージを送信
    sns_client.publish(
        TopicArn=sns_topic_arn,
        Message=sns_message,
        Subject=sns_subject
    )
    
    return {
        'statusCode': 200,
        'body': 'クローリングの結果がSNSに送信されました。'
    }

 
コード内部にある一部の箇所を変更する必要があります。
 

sns_topic_arn= 'arn:aws:sns:ap-northeast-1:xxx' 

 
作成したSNSトピックARNに変更します。

default_urls = ['example.com']

 
サイトを追加する場合は、 ['example.com', 'example2.com'] のように記述します。

default_keywords = ['AI']

 
キーワードを追加する場合は、 ['AI', 'Tech'] のように記述します。


 

 
コードを修正したら、「Deploy」後に「Test」を押します。
テストイベントのテンプレートはデフォルトのSNS値で問題ありません。


 

 
設定したメールで内容が届くことを確認できます。


まとめ

Lambdaを使って簡単にコードを作成し、クロールしたデータをメールに転送してみました。
サイトによってはクロールがうまくいかない場合もありますので、コードは適宜修正してください。
また、許可されていない商用利用は禁止されている場合もあるので、ご注意ください。

最後までご覧いただきありがとうございました!