ホーム
記事一覧
プライバシーポリシー
免責事項
お問い合わせ

AWS Lambdaを使ったツイート収集システム

2020-03-22

以前書いたPythonとTwitter APIを利用したツイート収集方法ではTwitter APIを利用して特定のキーワードのツイートを収集する方法を紹介しました。

しかし、記事で述べたようにAPIで取得できるのは7日前までのツイートのみです。

有料プランを使わずにより多くの情報を取得するには、日々検索を行い地道に集める必要があります。

そこで、AWS Lambdaを利用して毎日決まった時間にTwitter APIを叩くコードを作成します。

本記事で伝えたいことは以下の3つです。

  • dockerを使ったlambda-uploaderの使い方
  • lambdaからs3への保存方法
  • lambdaのスケジュール実行

Dockerを利用したAWS Lambdaアップロード方法

AWS Lambdaの簡単なアップロード方法については【AWS】python-lambda-localとlambda-uploaderを使ってみたで書きました。この記事では、ローカルでdockerを使わずにlambda-uploaderを使用していました。

しかし記事のやり方ではコード内でnumpyを用いると以下のようなエラーがでます(pandasを使ったコードだったので内部的にnumpyが必要になるようです。)

Unable to import module 'lambda_handler': Missing required dependencies ['numpy']

どうやら普通にノートPC上でやるとlambda-uploaderで作成されるzipはLambdaに合った形式になっていないようです。

今回はamazonlinux2上で使用するモジュールごとzip化することで解決しました。

公式ドキュメントを読んだ感じでは、他にも解決方法がありそうです。わかりやすいところだとlayerを使うという手があります。

参考URL

さて、amazonlinux2上で作業するにはEC2のAMIで選択すればいいのですが、いちいちEC2を使うのも面倒なのでDockerのamazonlinux2イメージを利用します。

さらにDocker上にLambdaのアップロード環境も構築します。

今回使用した作業フォルダの構成は以下になります。

.
├── Dockerfile
├── README.md
├── docker-compose.yml
├── script.sh
└── upload-files
    ├── event.json
    ├── lambda.json
    └── lambda_handler.py

upload-filesの中身は以前書いた記事の通りです。

使用したDockefileはこんな感じです。

FROM amazonlinux:2

RUN yum install python3 -y
RUN yum install unzip -y
RUN pip3 install pip --upgrade
RUN pip3 install lambda-uploader python-lambda-local 

RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" 
RUN unzip awscliv2.zip 
RUN ./aws/install

WORKDIR /home/work
COPY ./upload-files/ /home/work

CMD ["/bin/bash"]

DockerでAWS CLIの認証情報を設定する

DockerでAWS CLIを利用するにはaws cliのインストールの他に認証情報の設定が必要になります。

Docker内でいちいち設定するのも大変なので、環境変数に設定してスクリプトでdocker-compose を実行することにしました。

本当は${HOME}/.aws/をマウントしてやろうしましたが、うまくいきませんでした(うまくいくやり方が合ったら教えてください)。

作成したスクリプトファイルとdocker-compose.ymlは以下のようになりました。

version: '3'
services:
  aws-cli:    
    build: .     
    tty: true
    environment:
      AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
      AWS_DEFAULT_REGION: ap-northeast-1
      AWS_DEFAULT_OUTPUT: json
    command: /bin/bash

regionとdefault outputは上記しか使う予定がないので決め打ちしてます。 スクリプトファイルは以下です。

#!/bin/bash

export AWS_ACCESS_KEY_ID="*************"
export AWS_SECRET_ACCESS_KEY="*************"
docker-compose build
docker-compose run aws-cli lambda-uploader --variables '{環境変数Key:Value}'

認証情報やLambdaで使用する環境変数は各々設定してください。

このようにスクリプトファイルにしておけば、スクリプトの実行でLambdaのアップロードが実行できます。

Twitter APIで1日分のツイートを取得

以前の記事では、クエリに対して取得できるだけツイートを取得していました。しかしこのやり方では、毎日収集すると重複するデータが大量に発生するので1日分のツイートだけ収集するように書き換えます。

やり方は簡単です。APIへ入力するクエリにsince:until:のオプションを付加します。JSTの時間にも対応しているようなので以下のように日時を設定しました。

from datetime import datetime, timedelta, timezone

# タイムゾーンの生成
JST = timezone(timedelta(hours=+9), 'JST')

# 現在の日時
now = datetime.now(JST)

# 前日の日時
yesterday = now - timedelta(days=1)

# 日本時間の24時
now = " until:" + now.strftime('%Y-%m-%d_00:00:00_JST')

# 日本時間の前日の24時
yesterday = " since:"+ yesterday.strftime('%Y-%m-%d_00:00:00_JST')

# 検索クエリ。検索範囲を前日24時から当日24時までの24時間に設定
query = QUERY_WORDS + now + yesterday

これでクエリをAPIの入力にすれば、日本時間で1日分のツイートを取得できます。

注意する必要があるのは、APIの結果に含まれるツイート時間(created_at)はUTC表記になっていることです。結果も日本時間に合わせるなら変換が必要です。

LambdaからファイルをS3に保存

PythonとTwitter APIを利用したツイート収集方法のファイルに保存する部分のコードをS3に保存するように書き換えます。

コードの書き換えの他にLambdaの実行ロールにS3のアクセスを許可するようにポリシーをアタッチします。

該当関数は以下になります。

import boto3
from io import StringIO
from datetime import datetime, timedelta, timezone
import pandas as pd

def putFileToS3(data,q):
    until = datetime.now(JST) 
    since = until - timedelta(days=1)   
    file_name = '{0}_to_{1}.csv'.format(since.strftime('%Y-%m-%d'), until.strftime('%Y-%m-%d'))
    
    # csvのカラム
    columns = ["投稿日", "ID", "User_name", "Screen_name", "text", "favorite", "retweet_count", "followers", "follows", "user_mentions"]

    df = pd.DataFrame(data)
    df.columns = columns

    csv_buffer = StringIO()
    df.to_csv(csv_buffer)
    content = csv_buffer.getvalue()

    s3 = boto3.client('s3')
    bucket = BUCKET_NAME
    s3FilePath = QUERY_WORDS + "/{0}/{1}/{2}".format(until.year, until.month, file_name)
    s3.put_object(Bucket=bucket, Key=s3FilePath, Body=content)

CloudWatch Eventsで定期実行

前述までのコードが想定通りに動けば、あとは毎日定時にLambdaが起動するように設定するだけです。これまでのものと組み合わせると最終的な構成は以下になります。

Lambdaとcloudwatch Eventsでツイート収集

やり方は簡単でLmabdaのトリガーにCloudWatch Eventsを指定するだけです。

まずはブラウザからAWSのコンソールにアクセスし、Lambda関数のページにアクセスします。アップロードがうまくいっていれば関数一覧に作成した関数があるはずです。

アップロードした関数を選択し、以下のようにトリガーの追加を選択します。

トリガーにはCloudWatch Eventsを指定します。

次にCloudWatch Eventsの設定を行なっていきます。とはいってもイベントパターンをスケジュール式にしてcronを書くだけです。

cronを書く際に気をつけるのはタイムゾーンがUTCになっていることです。日本時間で実行したいなら9時間ずらす必要があります。ちなみに画像のスケジュール式は毎日日本時間の24時に実行されるように書いてます。

cronでのスケジュール式の書き方は公式ページが参考になります。

まとめ

本記事ではDockerでlambda-uploaderを使う方法やAWS LambdaとCloudWatch Eventsを使ったツイート日時収集システムの構築方法についてまとめました。

詰まったところはAWS CLIの認証情報をDockerに渡す部分です。本当はスクリプトファイルを使わずにやりたかったのですが、力及ばずでした。。。

次は集めた情報を自然言語処理で前処理を行い簡単な可視化を行う記事を書こうと思ってます。