Amazonで商品の金額が変動したことを知らせてくれるLine botを作ってみた

去年の終わりに、AWS認定ソリューションアーキテクト（アソシエイト）を取得した。
普段の業務ではまったく使う機会がないが、せっかく勉強したので何かしら作ってみたい！ということでLine botを作ってみた、というお話。
※あまり具体的なところまでは踏み込みません。興味があれば参考URLをご参照ください。

「試しに使ってみたい！」という人は以下のリンクで友達追加してみてください。
（LINE botのプランによる制約（後述）により、先着50名までです）
<a href="https://line.me/R/ti/p/%40oza6645k"><img height="36" border="0" alt="友だち追加" src="https://scdn.line-apps.com/n/line_add_friends/btn/ja.png"></a>

# 何故Line bot？
最初は「ReactでSPA作ってやるぜ～」と思っていたが、早々に挫折。（JSわからなすぎる）
今回の目的はAWSを使ってみることなので、あまりクライアント側に体力を割きたくない・・・
で、いろんな人に相談した結果、Line botが簡単そうだったので採用。

# アプリケーションの概要
1. LINEbotにASIN（※）を送信することで、商品が登録される。
1. 登録されている商品の価格に変動がある場合、登録しているユーザーへ通知する。

（※）ASINは「Amazon Standard Identification Number」の略で、Amazonグループが取り扱う
　　　書籍以外の商品を識別する10けたの番号。以下のように、商品ページに記載されている。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/101329/aca962c2-35d0-b73d-347d-fb5a13b34370.png)

あと「登録している一覧の取得」と「登録商品の削除」の機能もあるが、今回は割愛。

# 処理の流れ

## 商品登録時
![image.png](https://qiita-image-store.s3.amazonaws.com/0/101329/b6977eb3-ff29-a563-d893-c6c41ab58096.png)

1. LINEでASINを送信する。
2. API Gatewayでリクエストを受け付け、商品登録用のLambdaファンクションを起動する。
3. 受け付けたASINを基にAmazon商品ページをスクレイピングし、商品名、金額を取得する。
4. 取得した内容をDynamoDBへ登録する。

## 価格チェック時
![image.png](https://qiita-image-store.s3.amazonaws.com/0/101329/10cb4906-0eef-7b39-2e6b-a2ed7e0a5316.png)

1. CloudWatch Eventsで価格チェック用のLambdaファンクションを定時起動する。
2. DynamoDBから登録されている商品（ASIN）を取得する。
3. 取得したASINを基にAmazon商品ページをスクレイピングし、最新の金額を取得する。
4. 最新の金額と比較し、金額に変動があった場合は登録しているユーザーへPUSH通知を送信する。

# 使用した技術要素

## Serverless Framework
作り始める前、「そもそもどうやってデプロイするのかな～」と調べているときに発見。
Serverless.ymlというファイルにLambdaやIAMロール、DynamoDB、API Gatewayなどの設定を書いておくことで、AWS上に必要な資源をデプロイしてくれるというフレームワーク。
CLIでデプロイコマンドを実行すると、AWS上でCloudFormationを実行し各種リソースを作成してくれる。

## LINE Messaging API
LINE botを動かす為のAPI。
アカウント作成～botの作成までそこまで悩むことなく作成できた。
botには「Developer Trial」、「フリー」、「ベーシック」、「プロ」といったプランがあり、それぞれによってできることと費用が異なる。
今回は、無料でPUSH通知ができるが、友達追加数に制限（50人まで）のある「Developer Trial」を選択。

## AWS API Gateway
LINE botからLambdaファンクションを実行させる為、API Gatewayを使ってAPI化。
Serverless.ymlに数行書くだけで、設定される。
デプロイすると、リクエストをPOSTする先のURLが発行されるので、それをLINEbot側に設定しておく。

## AWS Lambda
言わずと知れた、サーバーレスの代名詞。
今回はAWSを動かしてみるのが目的なので、慣れ親しんだJavaを選択。
・・・が、世に出ているサンプルは大抵Pythonだったりするので、結果的に学習コストが低かったか？は微妙・・・

LINEがJavaでLINE bot作る人向けのサンプルコードをGitHubに公開しているが、SpringBootを利用して作られていた為、Lambdaを使いたかった私はこれもあまり参考にできず。

いろいろ情報が少なくて苦労したが、勉強にはなった。

### jsoup
Amazonから商品情報を取得する方法として、最初は「Product Advertising API」を利用することを検討。しかし、当APIはアフィリエイトの為に提供されているものであり、利用用途が合わないことから利用を断念。
代わりに、jsoupを使ったスクレイピングで対応することに。（jsoup は Java で HTML の解析・編集を行うためのライブラリ）

jsoup自体は特に難しくはなかったが、Amazon商品ページのHTMLソースを解析するのが結構大変だった・・・

## AWS DynamoDB
これも有名なNoSQLデータベース。
スキーマレスで、キー項目だけ定義すれば、追加する項目は自在に増減できる。
普段の業務ではRDBしか使ったことがなく、NoSQLのテーブル設計は未だに正解がわからない・・・
今回のアプリケーションではUserテーブル（キー：UserID）とProductテーブル（キー：ASIN）の２つを作成。

現状はスケーラビリティやレスポンス性能をそこまで意識していないので、もう少し追求したいところ。

## AWS CloudWatch Events
CloudWatch EventsでLambdaを定期実行し、価格の変動チェックをしている。
これもServerless.ymlに数行書くだけで、設定される。

# 作ってみた感想
* 初回なのでわからないことは多かったが、AWSのウェブ記事は数多あるので割とスムーズに作れたと思う。
* AWSもLINEも公式の日本語ドキュメントがとても充実していた。困ったらまずここを見るのが良い。
* 実際にモノを作ってみると、曖昧だった部分が明確になったり、新たな疑問が生まれたりするので本当に勉強になる。
* しばらく動かしてみた感じ、AWS無料枠を超えることはほぼないと思う。サーバーレスすごい。

# 今後改善していきたいこと
* 金額変動を通知する際に、登録後最安値を表示したい。（今のテーブル構成だとできない）
* ほしいものリストの商品を纏めて登録したい。（スクレイピングでやりたいけど、イメージが湧かない）
* 開発/テスト環境を整えたい。バージョン管理、自動ビルド&デプロイ、CIなど。（むずそう）
* スケーラビリティやレスポンス性能を意識して再設計したい。（キューの導入、テーブル構成など）

# 参考URL
* [Messaging APIリファレンス](https://developers.line.biz/ja/reference/messaging-api/)
* [Messaging APIの各プランまとめ：個人利用で最適なプランとは？](https://qiita.com/line_gamebook/items/2fc3f4319fc59a1e31d3)
* [Lambda(Java)を使ってLINE Message APIとやり取りする](https://qiita.com/hondasports8/items/0c7ebe1d2a74ab81d70b)
* [jsoup使い方メモ](https://qiita.com/opengl-8080/items/d4864bbc335d1e99a2d7)
* [Serverless FrameworkでAWS LambdaにJavaをディプロイする方法](https://qiita.com/arimas/items/3943ad795e49fac87c85)
* [[小ネタ]Serverless FrameworkでLambdaを定期実行させる](https://dev.classmethod.jp/etc/serverless-framework-lambda-cron-execute/)