8
8

More than 5 years have passed since last update.

Twitter retrobot 構築 で学ぶ AWS Lambda Python

Last updated at Posted at 2015-11-30

Lambda の Advent Calender にタッチの差で参加できなかったので、#0的に11月30日を狙って(勝手に)投稿してみます!!

今年の頭から EC2 上で Twitter retrobot を動かしていたのですが、先月 Lambda が Python 対応&スケジュール実行されたので、今回その retrobot を Lambda に移行してみました。

最初は Lambda の勉強のために移行しようと思ったのですが、移行後金額を見積もってみるとまさかの無料枠内(しかもかなり余裕があるように見えます。)に収まったので、経費削減にもつながりました。(計算間違ってるかもしれないので、最後に見積もりを載せてみました。間違っていたらご指摘ください!)

前提/環境

  • 10分に1回、約1年前のツイートをつぶやきなおすbotになります。
  • Lambda 歴トータル1週間くらいです。(4月のハンズオン以来。。)
  • Python も初心者です。(運用スクリプト少し書いたことある程度)
  • Yosemite 10.10.4 で作業しています。

こんな人向け

  • Lambda function を初めて書く方
  • 安価に retrobot 運用してみたい方

Twitter アプリの登録とアクセスキーの取得

こちらのページを参考にして進めてください。

Consumer Key(CK)
Consumer Secret(CS)
Access Token(AT)
Access Token Secret(AS)
の4つが必要になります。

過去1年分のツイートファイル(json形式/月ごと)を取得し、S3にアップロードする

過去のツイートは tweet.zip という形でダウンロードできます。
設定画面を開いてください。

スクリーンショット 2015-11-30 22.05.54.png

設定画面の一番下に「全ツイート履歴」という項目がありますので、そこからメールを送信してください。
(私は最近履歴をダウンロードしているので「再送信」となっていますが、みなさんの画面では「送信」になっているかと思います。)

スクリーンショット 2015-11-30 22.08.52.png

次に、S3 に retrobot 用のバケットを作成してください。
S3 > Create Bucket で作成することができます。
名前は全世界でユニークにしないとなりませんので、(twitterアカウント名).retro とでもすればよいと思います。

そして、先ほどのzipファイルを展開し、直近1年分の js ファイルを upload してください。
こんな感じになるはずです。↓

スクリーンショット 2015-11-30 22.14.15.png

Pythonスクリプトの作成

やっていることは下記の通りです。
(Python 素人なのでもっといい書き方あればぜひコメントください!)

  • 1年前同月のツイートファイルを S3 から取得
  • 1年前の同じ時刻〜10分後までのツイートをフィルタする
  • フィルタされた結果をつぶやく

# * enter your hogehoge となっている5箇所だけ変更すれば動くはずです。

ketancho_retro.py
from requests_oauthlib import OAuth1Session
import commands, boto3, re, json

CK = '***' # * enter your Consumer Key *
CS = '***' # * enter your Consumer Secret *
AT = '***' # * enter your Access Token *
AS = '***' # * enter your Accesss Token Secert *

UPDATE_URL = 'https://api.twitter.com/1.1/statuses/update.json'

AWS_S3_BUCKET_NAME = "***" # * enter your backet name *

def _(cmd):
    return commands.getoutput(cmd)

# get "keyName" obj from S3
def _getTweetList(keyName):
    s3 = boto3.resource('s3', region_name='ap-northeast-1')
    bucket = s3.Bucket(AWS_S3_BUCKET_NAME)
    obj = bucket.Object(keyName)

    response = obj.get()
    body = response['Body'].read()
    return body.decode('utf-8')

# tweet text
def _tweet(text):
    params = {"status": text }
    twitter = OAuth1Session(CK, CS, AT, AS)
    req = twitter.post(UPDATE_URL, params = params)

    if req.status_code == 200:
        return text
    else:   
        return req.status_code

def handler(event, context):
    # yyyy_mm.js
    GET_OBJECT_KEY_NAME = _('date +"%Y_%m" --date "1 year ago"') + ".js"
    tweetList = _getTweetList(GET_OBJECT_KEY_NAME)

    # delete first line ("Grailbird.data.tweets_yyyy_mm =")
    tweetListJson = re.sub(r"^.*\n", "", tweetList)
    tweets = json.loads(tweetListJson)

    # yyyy-mm-dd hh:m
    targetDateTime = _('date +"%Y-%m-%d %H:%M" --date "1 year ago"')[:-1]
    targetTweetList = []
    for tweet in tweets:
        if tweet["created_at"].startswith(targetDateTime):
            # replace mention and hashtag mark
            text = tweet["text"].replace('@','*').replace('#','+')
            targetTweetList.append(text)

    # desc -> asc
    targetTweetList.reverse()

    for text in targetTweetList:
        _tweet(text)

デプロイパッケージの作成

外部ライブラリを使用しているため、zipファイルにまとめてアップロードする必要があります。
※ここでは手順のみ記載しますが、こちらに詳細がありますので、詳しく知りたい方はご確認ください。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html

Lambda ファンクション用のディレクトリを作成してください。
また、今回 requests_oauthlib モジュールを使用しますので、こちらをインストールしてください。

mkdir lambda_function
cd lambda_function/
pip install requests_oauthlib -t ./

pip がなければインストールしてください。(sudo 権限が必要です)

easy_install pip

Python ファイルのアップロード方法は下記の3つがありますが、

  • ソースを Management Console 上に記入する
  • zip ファイルを作成し直接 upload する
  • zip ファイルを作成し、S3 に upload し、Lambda function から参照する

今回のように外部モジュールを使用するときは、zip ファイルを作成する必要があります。
今回は2番目の方法で進めます。

cp (pyのあるdir)/ketancho_retro.py ./
zip -r ketancho_retro.zip ./

Lambda ファンクションの作成

Lambda のトップ画面から Create Lambda function を選択します。

スクリーンショット 2015-11-28 19.57.35.png

blue print は hello-world-python を選択してください。

スクリーンショット 2015-11-28 20.01.04.png

Configure function では、下記の項目を設定してください。

  • Name:Lambda function の名前を入力してください。
  • Lambda function code:"Upload a .ZIP file" を選択し、先ほど作成した zip ファイルを選択してください。
  • handler:[先ほど作成した .py のファイル名].[最初に実行するメソッド名]になります。私の場合は、ketancho_retro.handler となります。
  • Role:今回は S3 バケットにアクセスが必要なので、Create New Role から "S3 execution role" を選択してください。すると、別タブで IAM 画面が開かれますが、何も変更せずAllowとしてください。元の画面に戻ってきて、今作成したロールが設定されます。

スクリーンショット 2015-11-28 20.07.15.png

最後にAdvanced sttingsですが、タイムアウト値が3秒ではたまにタイムアウトしてしまうので、10秒としています。
設定できたらNextを押してください。

スクリーンショット 2015-11-28 20.16.45.png

Event sources の設定

Lambda ファンクションが作成できたら、次に Event sources を設定します。
何をトリガーにファンクションを実行するかの定義になります。
「Event source」タブを押してください。

スクリーンショット 2015-11-30 22.30.08.png

「Add event source」を押してください。

スクリーンショット 2015-11-30 22.33.41.png

今回はcronライクに10分に1回起動するようにしたいので、
「Event source type」は Scheduled Event を、
「Schedule expression」は cron(0/10 * ? * * *) としてください。

スクリーンショット 2015-11-30 22.36.03.png

ここまでで設定完了です。
うまく動くかテストしたい場合は、「Test」ボタンからテストできます。
インプットは何にするか聞かれますが、そのまま Save and Test としてください。
(このインプットは使わないのでなんでもOKです。)
ただし、1年前の同じ時間から10分後までに何もつぶやいていない場合は、botの方も何もつぶやかれません。
すぐにテストしたい場合は、targetDateTimeを適当な値に変更してzipファイルをアップロードしなおしてテストしてみてください。

見積もり

最初に「タダかも!」と書きましたが、私は下記のように見積もっています。
AWS公式ページに「Lambda では 1 か月に 1,000,000 件の無料リクエストおよび 400,000 GB/秒のコンピューティング時間が無料利用枠となっています。 」と書かれています。

まず、リクスト数ですが、
10分に1回 x 6 x 24時間 x 31日分で最大でも4,464回/月となり、無料枠の1%にも満たないです。

次に、コンピューティング時間ですが、何日か運用したのですが、
スクリーンショット 2015-11-30 22.56.00.png
のように、せいぜい3,000msで処理が完了します。(青がMax、緑がavg、橙がminです。)
これを月換算(x4,464回分)すると、13,392秒/月になります。
Lambdaでは何GBメモリおを占有したかで決まるので、これに設定しているメモリ128MBをかけると1,674GB、、無料枠のこちらも1%にも届きません。
なのでタダ!と書いた次第です!(間違っていてら教えてください。)

まとめ

retrobot は Lambda を学ぶ材料として、ちょうどいい規模だと思います。
スムーズにいけば1時間程度で完了すると思いますので、サーバレスこと始めとしてやってみてもらえればと思います。
次は、AMI の自動取得を Lambda に移行しようと思います。

また、retrobot は1年前に自分がやろうとしてたこと/やりたかったこと、でもやってなかったことを思い出すのにちょうどいいです。
タダで運用できそうですので、備忘録がてら(?)運用してみてください!

8
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8