【個人開発】AWSでサーバーレスなWebスクレイピングアプリを作ってみた

個人的に Web サイトを定期的に解析するアプリが必要になったので、AWS を活用してサーバーレスな Web スクレイピングアプリを構築してみました。

せっかく作ったので、このアプリのアーキテクチャと構築時のポイントを初心者にもわかりやすいように解説してみようと思います。

# アーキテクチャ

アーキテクチャとしては EventBridge, Lambda, DynamoDB, SNS を用いたシンプルな **サーバーレスアーキテクチャ** です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2443303/ba0290a4-decd-84c6-5e79-677f0ecc24e6.png)


# 解説

ここからは AWS サービス毎に構築時のポイントを解説していきます。

## 1. Lambda

Web スクレイピングツール（ライブラリ）として **Beautiful Soup** を使うため、Lambda ランタイムは **Python** を選びました。

処理の流れは以下のとおりです。

1. **Requests ライブラリ** を用いて対象のWebサイトからコンテンツを取得する
2. 取得したコンテンツを **Beautiful Soup ライブラリ** を使って解析する
3. **DynamoDB** から前回の解析結果を取得する
4. 前回の解析結果と今回の解析結果を比較する
5. 解析結果に差分がある≒ Web コンテンツが更新された場合、**SNS トピック** を発行する
6. 今回の解析結果を **DynamoDB** に保存する


### 構築時のポイント

#### 外部ライブラリは Lambda レイヤー化する

外部ライブラリは Lambda レイヤー化しましょう。

Lambda レイヤーとは Lambda 関数で使用できるライブラリをパッケージ化し、Lambda 関数間で共有する機能です。
今回のアプリはひとつなので Lambda 関数間で共有することはありませんが、外部ライブラリを Lambda レイヤー化しておくと、Lambda 関数のアーカイブサイズを小さくしたり、Lambda 関数と外部ライブラリを分けて管理できるメリットがあります。

Lambda レイヤーについては以下の記事がわかりやすく解説しています。

https://qiita.com/t_okkan/items/394a15577bd1aad46ec3


### 参考

#### Requests とは

説明不要かもしれませんが、Python ではスタンダードな **HTTP ライブラリ** です。
Web サイトからコンテンツ（HTML）を取得するために使用します。

https://requests-docs-ja.readthedocs.io/en/latest/


#### Beautiful Soup とは

簡単に言うと、Beautiful Soup とは **「HTML からデータを抽出するための Python ライブラリ」** です。
Beautiful Soup の使い方は以下の記事がわかりやすく解説しています。

https://atmarkit.itmedia.co.jp/ait/articles/1910/18/news015.html

Beautiful Soup 公式はこちら↓

https://www.crummy.com/software/BeautifulSoup/bs4/doc/


## 2. DynamoDB

このアプリでは Web コンテンツの解析結果を保存するために DynamoDB を使用しています。
DynamoDB は AWS が提供している NoSQL データベースサービスです。

### 構築時のポイント

#### Boto3 (AWS SDK for Python)

DynamoDB に限らず、Python で AWS リソースを操作するには、Boto3 (AWS SDK for Python) というライブラリを使用します。

https://aws.amazon.com/jp/sdk-for-python/

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html

どのメソッドを使用するかは設計次第ですが、一般的には put_item / get_item を用いて、テーブル内のデータ (item) を操作します。

#### DynamoDB のテーブル設計

DynamoDB のテーブル設計は解析対象の Web コンテンツや解析したい内容によって変わってきますので、以下の記事等を参考に設計しましょう。

https://blog.usize-tech.com/table-design-for-amazon-dynamodb/


## 3. SNS (Simple Notification Service)

このアプリでは Web コンテンツに更新があった際、メール通知するために SNS を使用しています。

### 構築時のポイント

#### Boto3 (AWS SDK for Python)

SNS の操作も Boto3 (AWS SDK for Python) を使用します。

https://aws.amazon.com/jp/sdk-for-python/

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sns.html

SNS トピックにメッセージを発行するには create_topic を使用します。

#### SNS によるメール通知

SNS によるメール通知方法は以下の記事がわかりやすく解説しています。

https://dev.classmethod.jp/articles/amazon-sns-2017/


## 4. EventBridge

このアプリでは定期的に Web スクレイピング処理 ＝ Lambda 関数を実行するために EventBridge を使用しています。
EventBridge では、cron 式や一定間隔でイベントを実行することが可能です。

EventBridge による Lambda 関数の実行方法は以下の記事を参照してください。

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-run-lambda-schedule.html


# AWS 利用料金について

ここまで、アーキテクチャと構築時のポイントを解説してきましたが、AWS を使用する上で気にしなければいけないことがあります。そう、**コスト ＝ AWS 利用料金** です。

このアプリケーションの AWS 利用料金はいくらになるでしょうか？

正解はなんと **0円** です。正確に言うと、**無料利用枠に収まる範囲** です。

:::note warn
他のアプリ等で無料利用枠を消費している場合は AWS 利用料金が発生する可能性があります。
:::

本アプリで使用している AWS サービスの無料利用枠は以下で確認できます。

https://aws.amazon.com/jp/free/

https://aws.amazon.com/jp/eventbridge/pricing/

* Lambda の無料利用枠
  * 1,000,000 件/月の無料リクエスト
  * 1 か月あたり最大 320 万秒のコンピューティング時間

* DynamoDB の無料利用枠
  * 25 GB のストレージ
  * 25 個のプロビジョニングされた書き込みキャパシティーユニット (WCU)
  * 25 個のプロビジョニングされた読み込みキャパシティーユニット (RCU)

* SNS の無料利用枠
  * 100 万件の発行
  * 10 万件の HTTP/S 配信
  * 1,000 件のメール配信

* EventBridge の無料利用枠
  * 月間 14,000,000 回の呼び出し
    

# Web スクレイピングする際の注意事項

Web スクレイピング自体に違法性はありませんが、**以下に該当する場合、違法となる可能性があります。**

* Web サイトの利用規約に違反する
* Web サイトに過度の負荷をかける
* 著作権を侵害する
* 同意なく個人情報を取得・利用する

詳しくは以下を参照してください。

https://www.octoparse.jp/blog/10-myths-about-web-scraping/

:::note warn
Web スクレイピングする際は違法行為に当たらないよう十分に注意しましょう。
違法か否かに関わらず、Web サイト側に迷惑が掛かることがないよう配慮しましょう。
:::


# あとがき

今回は AWS と Beautiful Soup を用いて、サーバーレスな Web スクレイピングアプリを構築してみました。
個人開発レベルの小規模なアプリだと、**サーバーレスアーキテクチャのコストメリット** が際立ちますね。

最後まで読んでいただき、ありがとうございます。
この記事が少しでも役に立てば幸いです。