お役立ち Twitter Bot を作りながら学ぶ AWS ドリル

~第 2 回 昔書いた記事の宣伝 Bot 編

2022-02-02
How to be a Developer

Author : 金澤 圭

ソリューションアーキテクト (SA) の金澤 (@ketancho) です。寒い日が続いていますが、皆さまいかがお過ごしでしょうか ? 先月は関東でも久しぶりに雪が積もりましたが、こんなに寒いと外に出てランニングができないのも致し方ないという雰囲気を感じます。その代わりに、温かいコーヒーを飲みながら AWS ドリルで自己研鑽、いかがでしょうか?

さて、 前回の記事 は多くの方にご覧いただけ、AWS ドリル連載としていい滑り出しを切ることができました。周りの方にシェアしていただいた方、ありがとうございます。実際に Bot 用の Twitter アカウントを作成 & 運用されている方も見受けられ、陰ながらニヤニヤ眺めさせていただいています。

こういう連載モノは 2 つ目の記事が大事だと思っておりますので、今回もしっかり丁寧にやっていければと思います。皆さまも引き続き、実際に手を動かしていただき、#AWSウェブマガジン ハッシュタグをつけてフィードバックいただけるとありがたいです。

この連載記事のその他の記事はこちら

選択
  • 選択
  • 第 1 回 おはよう Bot 編
  • 第 2 回 昔書いた記事の宣伝 Bot 編
  • 第 3 回 リファクタリング & 曜日ごとのツイート 編
  • 第 4 回 新章突入 ! 気になるワード検索 & 通知 Bot 編
  • 第 5 回 皆さまの代わりに英語でツイートしておくよ Bot 編
  • 第 6 回 AWS Step Functions を使って Well-being Bot を作ろう ! (前編)
  • 第 7 回 AWS Step Functions を使って Well-being Bot を作ろう ! (後編)
  • 第 8 回 - 総集編 & 夏休みの自由研究のすすめ
  • 第 9 回 - IaC 入門しながら作るリマインダー Bot (前編)
  • 第 10 回 - IaC 入門しながら作るリマインダー Bot (中編)
  • 完結回 - IaC & CI/CD 入門しながら作るリマインダー Bot (後編)

このクラウドレシピ (ハンズオン記事) を無料でお試しいただけます »

毎月提供されるクラウドレシピのアップデート情報とともに、クレジットコードを受け取ることができます。 


1. この記事で作る Bot の機能と、とりあげる AWS サービス・機能

さて、前回に引き続き、Twitter Bot を作りながら手に馴染んだ AWS サービス・機能を増やしていただければと考えています。今回のドリル #2 では、前回作成したおはよう Bot を拡張し、毎日違うツイートをする Bot を作ります。ツイートの文面はデータベースに事前に格納しておき、毎朝そこから取得する形に変更します。この変更をすることで Bot に毎日違うツイートをさせられるので、私は過去に書いた記事の紹介文と URL を格納し、その宣伝をしていきたいと考えています。

AWS サービスとしては、前回も利用した AWS Lambda に加え、

を使っていきます。前回のドリル #1 の作業を前提とする部分がありますので、今回のドリルを実装していただく方は、先に前回の内容を終わらせてから戻ってきていただきたいです。

クリックすると拡大します

また、前回の記事を入稿した直後に Twitter 側でアップデートがあり、API Key や Access Token を払い出すまでの手順が変わってしまっていました。教えていただいた読者の皆さま、ありがとうございました。1/24 に ドリル #1 の記事を修正しましたので、もし前回のドリルでそこで躓いてしまった・・・という方がいらっしゃいましたら、ぜひもう一度挑戦していただければ嬉しいです。


2. 前回のドリルの振り返り

それでは今回のドリルを進めていきましょう。まずは前回のドリルの振り返りからやっていきます。前回の記事では、

を使って、毎日特定の時間になったら日付と共に「おはよう」と言う Bot を作成しました。簡単な構成例はこちらになります。

クリックすると拡大します

前回作成した Lambda 関数 twitter-bot-hello のプログラムも再掲します。lambda_handler の中でツイートする文言を組み立て、21 行目でその文言を引数に Twitter API を呼び出してツイートしています。ツイート文言の日付部分は毎日変わるものの、基本的には固定のツイートをする Bot でした。

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

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

# API Key, Access Token (本来、ハードコーディングするのは望ましくありません。連載の中で修正していきます。)
consumer_key = '*Input Your API Key*'
client_secret = '*Input Your API Key Secret*'
access_token = '*Input Your Access Token*'
access_token_secret = '*Input Your Access Token Secret*'

oauth = OAuth1Session(consumer_key, client_secret, access_token, access_token_secret)

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

このドリルでは、ツイートする文言をデータベースから取得する形に変更することで、毎日違うツイートをするようにプログラムを修正します。今回はデータベースとして Amazon DynamoDB を採用するので、まずは前準備として Amazon DynamoDB のテーブルを作成していきましょう。


3. Amazon DynamoDB テーブルの作成

Amazon DynamoDB は、フルマネージドな NoSQL データベースサービスで、ストレージの容量制限がない、可用性・耐久性が高い、需要に応じてスケールする機能がサービス自体に組み込まれている、といった特徴があります。今回のドリルではこの DynamoDB に Key-Value の形で、日付 (YYYYMMDD) とその日に投稿したいメッセージを格納します。

まず、Amazon DynamoDB の画面に遷移し、「テーブルの作成」ボタンをクリックします。

「テーブルの詳細」欄には、

  • テーブル名 : TwitterBotDailyMessage
  • パーティションキー : Date

を設定しましょう。

また、その下の「設定」欄では「設定をカスタマイズ」の方を選択してください。

クリックすると拡大します

その後、画面を下にスクロールしていただき、「読み込み/書き込みキャパシティーの設定」欄を下記のように設定してください。

  • キャパシティモード : プロビジョンド
  • 読み込みキャパシティ
    • Auto Scaling : オフ
    • プロビジョンドキャパシティユニット : 1
  • 書き込みキャパシティ
    • Auto Scaling : オフ
    • プロビジョンドキャパシティユニット : 1

今回は DynamoDB の無料枠 をなるべく活かしたい、かつ、DynamoDB テーブルを参照する頻度があまり高くないという背景から、キャパシティモードをプロビジョンド、キャパシティユニットの設定値は最小の値としました。

クリックすると拡大します

その他の設定はデフォルトのまま進めるので、画面を一番下までスクロールし、右下にある「テーブルの作成」ボタンをクリックしてください。少し待った後、リロードボタンを押し、「状態」欄が Activate になればテーブル作成完了です。

続いて、作成したテーブルに日毎に投稿したいメッセージを追加します。DynamoDB 画面の左側のメニューから「項目の探索」をクリックし、先ほど作成したテーブルを選択してください。この時点では項目の一覧は空になっているはずです。その後、右上の「項目を作成」ボタンをクリックしてください。

クリックすると拡大します

項目作成画面で下記の作業を進めます。

  • Date の隣の「」には、YYYYMMDD の形式で投稿したい日付 を入力してください。
    • 例えば、2022/1/13 であれば 20220113 とします。
    • 後続のテストの際に「Date が作業当日の日付であること」を条件に項目を取得するので、ドリルを進めている日の日付を入れていただくことをおすすめします。
  • その後、左下にある「新しい属性の追加」をクリックし、プルダウンから「文字列」を選択すると属性名と値の行が追加されます。その「属性名」には Message、「」には 投稿したい文字列 を入力してください。
    • ここは皆さまが発信したいメッセージを書いていただければ大丈夫です。私は冒頭でお伝えしたとおり、過去の自分の記事を宣伝したいので「 今日のイチオシ記事はこちら!Twitter Bot を作ってみよう! https://aws.amazon.com/jp/builders-flash/202201/aws-drill-twitter-bot-1/ 」としました。

ここまで入力が完了したら、右下の「項目を作成」をクリックすれば項目ができあがります。

クリックすると拡大します

続いて、この作業を何度か繰り返し、未来の投稿予約をしていきましょう。

Date に未来日付を入れる形で、項目をいくつか作成してください。私はこのように宣伝したい記事に関するメッセージを 3 日分入れてみました。ドリルを進められる際には、その当日、翌日、2 日後・・・という形で項目を追加するのをおすすめします。


4. Lambda 関数から DynamoDB テーブルにアクセスする実装を進める

DynamoDB テーブルの準備が整ったので、Lambda 関数の修正を進めていきます。当日の日付をキーに DynamoDB からメッセージを取得したいのですが、プログラムから AWS のサービスやリソースへの操作をする際は、各プログラミング言語ごとに用意された AWS SDK を利用していきます。

AWS SDK の利用方法は言語ごとのドキュメントにまとまっているので、今回は AWS SDK for Python のドキュメント をチェックしながら実装を進めていきます。DynamoDB のテーブルに関する操作をするので、ドキュメントのこの部分 を参考にしてみましょう。

はじめに実装方針をざっくり共有し、その後完成形のプログラムを示します。「2 回目だし自分で実装にチャレンジしたい !」という方は、先に方針だけ確認していただき、その流れに沿ってご自身で実装を進め、最後に答え合わせ的に完成形を見ていただく、というやり方も面白いと思います。

4-1. 実装方針 (1) : AWS SDK for Python (boto3) をインポート & DynamoDB テーブルインスタンスを生成するコードを追加する

ドキュメントにある通り、DynamoDB のテーブルに関する操作をするには、

A resource representing an Amazon DynamoDB Table:

> import boto3
> 
> dynamodb = boto3.resource('dynamodb')
> table = dynamodb.Table('name')

このような下準備をする必要があります。name にはテーブルの名前を入れる必要があるので、先ほど作成した DynamoDB テーブルの名前である TwitterBotDailyMessage に変更しましょう。また、table という変数名も分かりにくいので、わかりやすい名前に変更してもいいでしょう。

4-2. 実装方針 (2) : 当日日付を YYYYMMDD の形で取得し、それをキーに DynamoDB テーブルから Item を取得するコードを追加する

ドキュメントのこの部分 に利用できるメソッド群が記載されており、今回はこの中の get_item() を利用します。パラメータ一覧が記載されていますが、今回は指定が必須である Key のみを利用します。当日日付を YYYYMMDD の形で文字列にし、それを

twitter_bot_message_table.get_item(Key={'Date': date})

のような形で Key に渡すことで、該当する項目を取得していきましょう。

4-3. その他の細かい修正

前回の記事では、「おはようございます ! 今日は 2022 年 1 月 13 日 です。頑張っていきましょう !!」と励ますメッセージにしていましたが、この「頑張っていきましょう !!」を削除します。そして、先ほど DynamoDB テーブルから取得したメッセージを末尾に付与する形にしていきます。

プログラムの変更方針は以上となります。私は下記のような Lambda 関数の最終形にしてみました。

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

# 追加(1) - ここから
import boto3
 
dynamodb = boto3.resource('dynamodb')
twitter_bot_message_table = dynamodb.Table('TwitterBotDailyMessage') 
# 追加(1) - ここまで

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

# API Key, Access Token (本来、ハードコーディングするのは望ましくありません。連載の中で修正していきます。)
consumer_key = '*Input Your API Key*'
client_secret = '*Input Your API Key Secret*'
access_token = '*Input Your Access Token*'
access_token_secret = '*Input Your Access Token Secret*'

oauth = OAuth1Session(consumer_key, client_secret, access_token, access_token_secret)

def lambda_handler(event, context):
    now = datetime.now(JST).strftime("%Y年%-m月%-d日")
    text = 'おはようございます!今日は ' + now + ' です。' # 変更
 
    # 追加(2) - ここから
    date = datetime.now(JST).strftime('%Y%m%d')
    response = twitter_bot_message_table.get_item(Key={'Date': date})
    if('Item' in response):
        text = text + response['Item']['Message']
    # 追加(2) - ここまで

    payload = {'text': text}
    response = oauth.post(
        "https://api.twitter.com/2/tweets",
        json=payload,
    )
    if response.status_code != 201:
        raise Exception(
            "[Error] {} {}".format(response.status_code, response.text)
        )

これでプログラムの完成です。デプロイを忘れずに行い、テスト実行してみてください。先ほど DynamoDB に追加したメッセージがツイートされましたか ?!

・・・と言いたいところなのですが、ここまで記事通りに実装を進められた方は、Lambda 関数を実行すると下記のようなエラーが出ると思います。エラー文言をぜひ読んでみてください。「DynamoDB に対して GetItem オペレーションを実行しようとしてるが、その権限がないよ !」と言われているようですね。

Response
{
  "errorMessage": "An error occurred (AccessDeniedException) when calling the GetItem operation: User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/twitter-bot-hello-role-iwdg6ohe/twitter-bot-hello is not authorized to perform: dynamodb:GetItem on resource: arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:table/TwitterBotMessage",
  "errorType": "ClientError",
  .. 

皆さまがマネジメントコンソールで利用しているユーザーも同じですが、Lambda 関数が AWS に関する操作を何でもかんでもできる、というのはセキュリティ上よくありません。そのための権限を管理するサービスが AWS IAM です。Lambda 関数ができる操作は IAM ロール、というリソースで定義します。

実は Lambda 関数作成時に、関数に紐づく IAM ロールが自動的に作られるのですが、デフォルトのまま権限を変更していなかったので、現在最低限の権限しかついていない状況です。そこで、この Lambda 関数に紐づく IAM ロールに DynamoDB の操作権限を追加します。

5. Lambda 関数に紐づく IAM ロールに権限 (IAM ポリシー) を追加する

Lambda 関数 twitter-bot-hello の画面で上の方にスクロールすると、「コード」タブが選択されていると思います。こちらを「設定」タブに切り替えていただき、その後「アクセス権限」を押してください。

実行ロールという箇所があると思いますので、そちらのロール名のリンクをクリックしてください。

クリックすると拡大します

クリックすると、該当する IAM ロールの画面に遷移します。「アクセス権限」タブにある、「ポリシーをアタッチします」というボタンをクリックしてみてください。

クリックすると拡大します

すると、IAM ポリシーをアタッチできる画面に移ります。IAM ポリシーは利用者が作成することができ、本来であればその操作に必要最低限の権限に絞るべき (今回であれば DynamoDB の GetItem のみ) なのですが、今回は標準で用意されている IAM ポリシーを使っていこうと思います。

上部の検索窓に「DynamoDB」と入力していただき、表示される「AmazonDynamoDBReadOnlyAccess」ポリシーをマークしてください。

クリックすると拡大します

その後、右下の「ポリシーのアタッチ」ボタンをクリックすると、IAM ロールにこのポリシーが割り当たります。こちらで今回必要な権限を Lambda 関数 twitter-bot-hello に割り当てることができました。

AWS をご利用いただく上で、この IAM はとても重要なサービスで、ぜひ詳細を抑えていただきたいと考えています。過去に、IAM について学べる座学 & ハンズオンコンテンツを作成しておりますので、こちら記事の最後で紹介させていただきます。あわせてご覧いただければと思います。

それでは、必要な作業が完了したので、これで今回の Bot が完成したはずです。改めて Lambda の画面に遷移し、 twitter-bot-hello を実行してみてください。無事にツイートされましたでしょうか?

もし、同じ権限エラーが出る場合は、古い権限が残ってしまっているかもしれないので、ソースコードをダミーで変更 (空行を入れるなど) し、再度デプロイし、Lambda 関数を再実行してみてください。

動作確認が済みましたら、DynamoDB テーブルに Date を未来日付にした項目を更にいくつか追加しておきましょう。該当日の朝に、それが自動的にツイートされるはずです。Bot から発信したい情報をテーブルに追加し、しばらく動作を見守っていただければと思います。なお、その日の項目がない場合は、「おはようございます ! 今日は YYYY 年 MM 月 DD 日 です。」というツイートがされる実装にしていますので、項目の日付が飛んでいても Bot の動作に問題はありません。

こちらで今回のドリルは完了です🎉お疲れさまでした !

6. 落ち穂拾い&参考情報

まず、今回のドリルの落ち穂拾いを行います。今回の Lambda 関数ですが、一切例外処理を実装していません。実際の開発ではしっかり実装するべきですので、参考になるドキュメント を共有します。各言語の SDK から DynamoDB を操作する手順やサンプルプログラムが掲載されているので、ぜひ参考にしてみてください。

続いて、今回利用した AWS サービス群を更に深く学ぶための動画ハンズオンコンテンツを紹介させていただきます。

Hands-on for Beginners - ハンズオンはじめの一歩: AWS アカウントの作り方 & IAM 基本のキ

AWS アカウントの作成と、AWS IAM の基本を学べるハンズオンです。今回のドリルでは、IAM の「体験」から入っていただきましたが、こちらの動画ハンズオンでは AWS IAM の座学、また IAM ユーザーや IAM グループといった、IAM のその他のリソースについても手を動かしながら学んでいただけます。ぜひこちらもご覧いただければと思います。

Hands-on for Beginners - AWS Lambda と AWS AI Services を組み合わせて作る音声文字起こし & 感情分析パイプライン

前回のドリルでも紹介したハンズオンです。今回のドリルでは DynamoDB から項目を取得しましたが、こちらの動画ハンズオンでは DynamoDB に項目を追加する手順を紹介しています。あわせて手を動かしていただくことで、ドリルで得た知見がより深まると思いますので、ぜひお試しください。


7. まとめ

「お役立ち Twitter Bot を作りながら学ぶ AWS ドリル」連載の第 2 弾として、毎日違うツイートをする Bot を作成しました。このドリルを通して、新たに

  • Amazon DynamoDB
  • AWS IAM

の 2 つのサービスを体験していただき、前回のドリルとあわせて合計 5 つの AWS サービスをお使いいただきました。

最後に改めてのお願いなのですが、皆さまのご感想・ご要望を #AWSウェブマガジン タグをつけて呟いていただけたら嬉しいです🙏 この記事に +α して、こんなものを作ってみました ! という共有も大歓迎です。今後の連載の参考にさせてもらいたいと思っておりますので、ぜひよろしくお願いしますー !

それでは次回の記事でまたお会いしましょう !

この連載記事のその他の記事はこちら

選択
  • 選択
  • 第 1 回 おはよう Bot 編
  • 第 2 回 昔書いた記事の宣伝 Bot 編
  • 第 3 回 リファクタリング & 曜日ごとのツイート 編
  • 第 4 回 新章突入 ! 気になるワード検索 & 通知 Bot 編
  • 第 5 回 皆さまの代わりに英語でツイートしておくよ Bot 編
  • 第 6 回 AWS Step Functions を使って Well-being Bot を作ろう ! (前編)
  • 第 7 回 AWS Step Functions を使って Well-being Bot を作ろう ! (後編)
  • 第 8 回 - 総集編 & 夏休みの自由研究のすすめ
  • 第 9 回 - IaC 入門しながら作るリマインダー Bot (前編)
  • 第 10 回 - IaC 入門しながら作るリマインダー Bot (中編)
  • 完結回 - IaC & CI/CD 入門しながら作るリマインダー Bot (後編)

builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

金澤 圭 @ketancho
アマゾン ウェブ サービス ジャパン合同会社
技術統括本部 ソリューションアーキテクト

サーバーレスが好きなソリューションアーキテクト。業種業界問わず、お客様のプロダクト開発をサポートさせていただいています。「AWS Hands-on for Beginners」というオンデマンドで視聴できるハンズオンも企画・推進しており、楽しく学べるコンテンツを日々考えています。好きなサービスは AWS Lambda、AWS Step Functions、Amazon Personalize で、好きな休日の過ごし方は娘ふたりと川の字になって昼寝👧👧と赤ん坊を抱っこしながらの散歩です👶

さらに最新記事・デベロッパー向けイベントを検索

下記の項目で絞り込む
1

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する