LambdaでAppStoreの最新レビューを取得してSlackチャンネルに通知する

# はじめに

こんにちは、Gakken LEAP のエンジニアの okamotoです。

AppStoreのレビューを自動で定期的に確認し、新規で投稿されたものがあれば通知を行う仕組みを作成しました。

本記事ではAWS Lambdaでアプリケーションを実行し、Slackのチャンネルに通知するための手順を紹介します。

# 準備するもの

## アプリのレビューを取得するためのURL

`
https://itunes.apple.com/jp/rss/customerreviews/id=[Apple ID]/sortBy=mostRecent/xml
`

※[Apple ID]はレビューを取得したいアプリのAppStoreのURLに「idxxxxxxxx」で記載されています。

## 通知先のSlackチャンネルのURL

### 手順

* 以下のURLにアクセス

      <https://api.slack.com/apps>

1. 「Create an APP」をクリック
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/1a80887d-3fed-cf0d-c0aa-52715600b198.png)

2. 「From scratch」をクリック
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/2a96d191-bc8e-2a2f-3c2a-002e55fececc.png)

3. 「AppName」に任意の名称を入力
4. 「Pick a workspace to develop your app in:」のプルダウンでワークスペースを選択
5. 「Create App」をクリック
![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/dafc1142-344d-577c-26ca-c98d52241b74.png)

6. 「Incoming Webhooks」をクリック![図4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/5c456f73-4aa7-a975-f423-89ee7983b8f3.png)

7. 「Incoming Webhooks」のスイッチをONに切り替える
![図5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/f73afb4d-a28b-cc37-8e54-e646d9ee3445.png)

8. 「Add New Webhook to Workspace」をクリック
![図6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/d53d2043-ccf9-3bf3-4fe6-f0d51a7fad47.png)

9. プルダウンから通知先のチャンネルを選択
10. 「許可する」をクリック
11. Webhook URLが発行される

# Lambdaの作成

1. AWSコンソールからLambdaの画面を開く

2. サイドバーの「関数」をクリック

3. 「関数を作成」をクリック

4. 任意の関数名を入力

5. ランタイムはPythonを選択

6. 関数の作成をクリック
![図7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/922f0ef2-5451-dfa1-01ca-a1e9e302715f.png)

7. Lambda関数作成画面で「設定」タブの「環境変数」をクリック

8. 「編集」をクリック

9. 下記を入力し「保存」

    |キー|値|
    |:---|:---|
    |review_url|レビュー取得URL|
    |slack_url|Webhook URL|

    ![図8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/e8db870b-838a-6eb4-db3e-77e1340fee47.png)

10. 「コード」タブをクリック

11. エディタ内に下記コードを入力

      ~~~python
      import urllib.request
      import xml.etree.ElementTree as ET
      from datetime import datetime, timedelta
      import json
      import os

      review_url = os.environ['review_url']
      slack_url = os.environ['slack_url']

      def lambda_handler(event, context):
        get_review()

      # レビュー内容取得関数
      def get_review():
        try:
          with urllib.request.urlopen(review_url) as response:
            xml_data = response.read().decode('utf-8')
            root = ET.fromstring(xml_data)

            # 最新３件のentryを取得
            print('最新3件のレビューを取得します')
            entries = root.findall('{http://www.w3.org/2005/Atomentry')[0:3]

            for entry in entries:
              if entry is not None:
                # 日付要素を取得
                date = entry.find('{http://www.w3.org/2005/Atom}updated')

                # 一週間以内に投稿されたレビューかチェック
                if is_within_last_week(date.text):
                  dt = datetime.fromisoformat(date.text[:-6])
                  formatted_date = dt.strftime("%Y/%m/%d %H:%M:%S")
                  date_str = "投稿日時:" + formatted_date

                  # 評価要素を取得
                  rate = entry.find('.//im:rating', {'im': 'http://itunesapple.com/rss'})
                  if rate is not None:
                    rate_str = "" + generate_stars(rate.text)
                  else:
                    print("Rateが見つかりませんでした。")

                  # title要素を取得
                  title = entry.find('{http://www.w3.org/2005/Atom}title')
                  if title is not None:
                    title_str = "タイトル:" + title.text
                  else:
                    print("Titleが見つかりませんでした。")

                  # content要素を取得し出力
                  content = entry.find('{http://www.w3.org/2005/Atomcontent')
                  if content is not None:
                    content_str = "本文:" + content.text
                  else:
                    print("Contentが見つかりませんでした。")

                  # メッセージ成形
                  msg = rate_str + '\n' + date_str + '\n' + title_str +'\n' + content_str + '\n'
                  print(msg)
                  # slackに送信
                  post_slack(msg)
                else:
                  print("一週間以内のレビューではありません。")
          except urllib.error.URLError as e:
            print("リクエストが失敗しました。エラー:", e)

      # 評価を星形式に変換
      def generate_stars(rating):
        num_rating = int(rating)
        stars = ""
        for i in range(num_rating):
          stars += "★"
        for i in range(5 - num_rating):****
          stars += "☆"
        return stars

      # 指定された日付が一週間以内の日時かどうかをチェック
      def is_within_last_week(date_str):
        # 現在の日付を取得
        today = datetime.today()

        # 指定された日付をdatetimeオブジェクトに変換
        original_date = datetime.fromisoformat(date_str[:-6])

        # 現在の日付から一週間前の日付を計算
        one_week_ago = today - timedelta(days=7)

        return original_date >= one_week_ago and original_date <= today

      # メッセージ送信関数
      def post_slack(msg):
        send_data = {
          "text": msg,
        }
        send_text = json.dumps(send_data)
        request = urllib.request.Request(
          slack_url,
          data=send_text.encode('utf-8'),
          method="POST"
        )
        with urllib.request.urlopen(request) as response:
          response_body = response.read().decode('utf-8')
      ~~~

12. 「Deploy」をクリック

13. 画面上部に「関数 test が正常に更新されました。」と表示されたら「Test」をクリック

14. 任意のイベント名を入力し「保存」をクリック

# イベントの作成

* Lambda画面上部の「＋ トリガーを追加」をクリック
![図9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/b2000d49-b744-1c25-7899-096b2b2b6be6.png)

* トリガー設定画面で「ソースを選択」プルダウンから「EventBridge（CloudWatch Events）を選択
* 「新規ルールを作成」を選択し、任意のルール名称を入力
* 「ルールタイプ」の「スケジュール式」を選択し、動かしたいタイミングの式を入力する
今回は毎週月曜の朝９時に実行させたいためCron式で下記のように記述
`cron(0 0 ? * MON *)`
※UTC基準なので設定したい時間の9時間前で設定する

* 「追加」をクリック
![図10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/d429b241-b53e-def0-1da0-8d1107695bda.png)

## 実際に通知されるメッセージ例

![図11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457529/3a2524e3-e787-3ff6-877c-eefe57395a05.png)

---

Gakken LEAP では教育をアップデートしていきたいエンジニアを募集しています。

https://gakken-leap.co.jp/recruit/

# 参考

<https://www.m3tech.blog/entry/2023/03/07/132833>
<https://www.softbank.jp/biz/blog/cloud-technology/articles/202301/deploy-a-slack-using-lambda/>