CodlessCode
AWS

AWS で Twitter Bot を作る【 Lambda + EventBridge + CloudShell 】

今日は、これらAWSサービスを使って決まった時間に呟く Twitter Bot を作ってみます。

  • Lambda
  • EventBridge
  • CloudShell
 

事前に必要な作業

 

Twitter の Developer Platform に SignUp

Twitter APIを使うには、認証のためのキーやトークンが必要です。

こちらからTwitterのDeveloper Platformに登録して、アプリケーションを作成し、以下の4つを取得しておきます。
(👆無料です)

  • API Key
  • API Key Secret
  • Access Token
  • Access Token Secret

1度しか表示されないので注意です!

 

AWS アカウント作成済み

AWSコンソールにログインしておきましょう。

 

IAM ロールの準備

Lambda関数の実行権限を付与するためのIAMロールが必要ですが、Lambda関数作成時に自動で作成できるので、ここでは作りません。

 

Lambda のひな型作成

  1. Lambdaページで「関数の作成」
  2. 以下のように入力
    • 「一から作成」にチェック
    • 関数名:MorningTwitterBot
    • ランタイム:Python3.9
    • アーキテクチャ:x86_64
    • 「基本的な Lambda アクセス権限で新しいロールを作成」にチェック
      (こうすると MorningTwitterBot-role-XXXXXX という名前のLambda実行ロールが自動的に作成されます。)
  3. 右下の「関数の作成」を実行

関数作成後、MorningTwitterBotの詳細ページに飛びます。
   
コードソースに lambda_function.py が作成されていて、編集中になっていると思います。
これでひな型が作成できました。

 

外部ライブラリ追加

Twitter APIの認証で request_oauthlib というPythonライブラリを使用するので、lambda_function.py で使用できるようにしていこうと思います。

  1. CloudShellを開く(ちょっと時間かかる) 
  2. 以下のコードを上から順に実行する
    mkdir morning-twitter-bot
    cd morning-twitter-bot/
    pip3 install -U pip
    pip3 install requests_oauthlib -t ./
    touch lambda_function.py
    zip -r morning-twitter-bot.zip ./
    aws lambda update-function-code --function-name MorningTwitterBot --zip-file fileb://morning-twitter-bot.zip

    ※ fileb:// です。file:// ではないです。

   
ちなみにCloudShellはAWSコンソールの右上にずっと居ます。
CloudShellショートカットアイコン

実行結果はこのようになりました。
requests_oauthlib インストール時にエラーが出る可能性がありますが問題ありませんでした。

[cloudshell-user@xxxxx morning-twitter-bot]$ pip3 install -U pip
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: pip in /home/cloudshell-user/.local/lib/python3.7/site-packages (21.3.1)
[cloudshell-user@xxxxx morning-twitter-bot]$ pip3 install requests_oauthlib -t ./
Collecting requests_oauthlib
  Using cached requests_oauthlib-1.3.0-py2.py3-none-any.whl (23 kB)
Collecting requests>=2.0.0
  Using cached requests-2.27.1-py2.py3-none-any.whl (63 kB)
Collecting oauthlib>=3.0.0
  Using cached oauthlib-3.1.1-py2.py3-none-any.whl (146 kB)
Collecting certifi>=2017.4.17
  Using cached certifi-2021.10.8-py2.py3-none-any.whl (149 kB)
Collecting charset-normalizer~=2.0.0
  Using cached charset_normalizer-2.0.10-py3-none-any.whl (39 kB)
Collecting idna<4,>=2.5
  Using cached idna-3.3-py3-none-any.whl (61 kB)
Collecting urllib3<1.27,>=1.21.1
  Using cached urllib3-1.26.8-py2.py3-none-any.whl (138 kB)
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests, oauthlib, requests-oauthlib
ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
awsebcli 3.20.2 requires requests<=2.26,>=2.20.1, but you have requests 2.27.1 which is incompatible.
aws-sam-translator 1.39.0 requires six~=1.15, but you have six 1.14.0 which is incompatible.
aws-sam-cli 1.33.0 requires requests==2.25.1, but you have requests 2.27.1 which is incompatible.
Successfully installed certifi-2021.10.8 charset-normalizer-2.0.10 idna-3.3 oauthlib-3.1.1 requests-2.27.1 requests-oauthlib-1.3.0 urllib3-1.26.8
[cloudshell-user@xxxxx morning-twitter-bot]$ touch lambda_function.py
[cloudshell-user@xxxxx morning-twitter-bot]$ zip -r morning-twitter-bot.zip ./
  adding: bin/ (stored 0%)
  adding: bin/normalizer (deflated 27%)
  ...
  ...
  adding: idna-3.3.dist-info/WHEEL (stored 0%)
  adding: idna-3.3.dist-info/LICENSE.md (deflated 47%)

先程作成したLambda関数のMorningTwitterBotを開くと、コードソースの部分にいろいろできてると思います。

どうでもいい補足

コードソースの左上に歯車アイコンがあります。
クリックして Themes からLambda編集エディターの外観を変えれます。

Lambdaのエディターテーマ
 

Lambda 関数の修正

以下のように修正してDeployします。

import json
import os
from requests_oauthlib import OAuthSession
from datetime import datetime, timedelta, timezone

JST = timezone(timedelta(hours=+9), 'JST')

# 一時的にキーやトークンをここに直接記述します。実際の開発では絶対やめてください。
API_KEY = 'Twitter Developer Platformで入手した API Key'
API_KEY_SECRET = 'Twitter Developer Platformで入手した API Secret Key'
ACCESS_TOKEN = 'Twitter Developer Platformで入手した Access Token'
ACCESS_TOKEN_SECRET = 'Twitter Developer Platformで入手した Secret Access Token'

oauth = OAuthSession(API_KEY, API_KEY_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)


def lambda_handler(event, context):
    now = datetime.now(JST).strftime("%Y年%-m月%-d日")
    text = now + " おはようございます!"
    
    response = oauth.post(
        "https://api.twitter.com/2/tweets",
        json={'text': text}
    )
    
    if response.status_code != 201:
        raise Exception("[ERROR] {} {}".format(response.status_code, response.text))

  

テストイベントで動作確認

コードソースのTestをクリックして以下のように設定します。

  • イベントテンプレート:hello-world
  • イベント名:MorningTwitterBotTest
  • それ以外はそのまま変更なし

右下の「作成」を実行してテストイベントを作成します。

テストを作成すると、元の編集画面に戻るので、もう一度Testをクリックし、作成したテストイベントを実行してみましょう。
Execution resultsタブが増えて、ログが出力されます。
ERRORがなければOKです。
Twitterを開いて、実際につぶやきが投稿されているか確認してみましょう。

 

EventBridge をトリガーに設定

決まった時間にツイートしたいので、EventBridgeCronを使って毎朝8時に呟くようにしてみます。

  1. Lambda関数ページの「関数の概要」で左側の「トリガーを追加」をクリック
  2. 「EventBridge(CloudWatch Events)」を選択
  3. ルールは「新規ルールを作成」
  4. 適当なルール名を入力(例:MorningTwitterBotEventAt8)
  5. 適当な説明を入力(例:毎朝8時におはよう)
  6. ルールタイプは「スケジュール式」
  7. 「スケジュール式*」に cron(0 23 * * ? *) と入力して「追加」

AWSのCronのスケジュール式は、LinuxのCronとは文法が違うので注意してください!
詳細はこちら👇
Cronのスケジュール式について

とはいえ以下2点を気をつければ大丈夫です。

  • 日 Day-of-month曜日 Day-of-weekは同時に設定できない(どっちかが「?」になる場合が多い)
  • 時刻は常にUTC基準

設定し終えると以下のようになります。
TwitterBotの呟き

これで明日の朝8時に、あなたの代わりにAWSが「おはよう」と呟いといてくれます。
(勤怠管理システムと連携して、Botで出勤打刻とかダメ絶対ですよ?笑)

 

認証情報を環境変数として設定(おまけ)

Lambdaで認証情報を扱う場合など、直接記述するのではなく環境変数を利用します。

以下の画面の「編集」ボタンでTwitter APIのAPI_KEYAPI_KEY_SECRETACCESS_TOKENACCESS_TOKEN_SECRETを追加します。

Lambdaの環境変数編集画面

追加したら、Lambda関数の認証情報を設定している箇所を変更します。

import json
import os
from requests_oauthlib import OAuth1Session
from datetime import datetime, timedelta, timezone

JST = timezone(timedelta(hours=+9), 'JST')

API_KEY = os.environ.get('API_KEY', '')  # ここ修正
API_KEY_SECRET = os.environ.get('API_KEY_SECRET', '')  # ここ修正
ACCESS_TOKEN = os.environ.get('ACCESS_TOKEN', '')  # ここ修正
ACCESS_TOKEN_SECRET = os.environ.get('ACCESS_TOKEN_SECRET', '')  # ここ修正

oauth = OAuth1Session(API_KEY, API_KEY_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)


def lambda_handler(event, context):
    now = datetime.now(JST).strftime("%Y年%-m月%-d日")
    text = now + " おはようございます!"
    
    response = oauth.post(
        "https://api.twitter.com/2/tweets",
        json={'text': text}
    )
    
    if response.status_code != 201:
        raise Exception("[ERROR] {} {}".format(response.status_code, response.text))

修正できたら、適宜テストイベントで確認してみてください!

 

おわりに

Twitter Botを作る過程で一番面倒なのって、Developer Platformに登録してキーやトークンを取得するところかもしれませんね😅
私はすでに登録済みだったので、キーの再生成だけで済みました。

今回触れたサービスは3つです。

  • AWS Lambda
  • Amazon EventBridge
  • AWS CloudShell
 

Amazon EventBridge

CloudWatch Eventsの後継で、これが新しくなったものです。イベント駆動型アプリケーションを構築できます。

AWS CloudShell

ブラウザベースのシェルで、追加費用なしでコードをすぐに実行できます。
また、awsコマンドやPythonなどの一般的な開発ツールがインストール済みなので、今回みたくLambda関数に外部ライブラリ追加したいとか、Lambdaレイヤーを作成するときは便利ですね。

今後もどんどんAWSサービスに触れていきます!
お疲れ様でした✨