AWS Lambdaからfacebookのタイムラインへ投稿する

  • 5
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

これは今年もやるよ!AWS Lambda縛り Advent Calendar 2015の20日目の記事である。


AWS Lambdaからfacebookの自分自身もしくは特定ページのタイムラインへ投稿してみよう。ただ残念なことに、facebookにはincoming webhookの仕組みがない。そのためfacebookのアクセストークンを取得するにはかなり面倒な手順が必要となる。

検証環境

今回の検証は、以下の環境で実施した。

version
OS Ubuntu 14.04.3 (3.13.0-71-generic)
python 2.7.10
pip 7.1.2
aws-cli 1.9.12
lambda-uploader 0.5.0
requests 2.8.1
facebook-sdk 0.4.0

AWS Lambda用IAMユーザとIAMロールを作成

AWS Lambda Developers Guide等を参考に、AWS Lambda用IAM UserとIAM Roleを作成する。

IAM User

今回は検証のため、AdministratorAccess権限を持ったIAM Userを作成した。本来はきっちり権限を制限した方が良い。

AdministratorAccess
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    }
  ]
}

またこのユーザのAccess Keyを取得し、AWS CLIに設定した。

awscli
$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************J5NA shared-credentials-file    
secret_key     ****************uUMd shared-credentials-file    
    region           ap-northeast-1      config-file    ~/.aws/config

IAM Role

今回のLambda Functionは他のAWSリソースにはアクセスしないため、CloudWatch Logsへ出力できる権限だけ持つ lambda_basic_execution を適用したIAM Roleを作成した。

lambda_basic_execution
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}

後に必要となるため、Role ARN をメモしておく。

Facebookに投稿するアクセストークンの取得

Facebookのアクセストークンを取得するには、結構面倒な手順(facebookアプリの作成 & OAuth コールバックを処理するhttp endpointの作成)が必要だ。これはAWS Lambdaとは関係無い話でもあるため、手順は別のページにまとめている。そのページを参考にしながら、User Access TokenとPage Access Tokenを取得して欲しい。

なお今回は、取得したアクセストークンをeventとしてLambda Functionに与える形を取っているが、リクエスト毎に変更されるものでもないため、S3やDynamoDBなどに保存しても良いだろう。

Lambda Functionの作成

pythonを用いてLambda Functionを作成し、lambda-uploaderを用いてAWS Lambdaに登録する。

Lambda Functionの設定ファイル作成

lambda-uploaderで用いるlambda.jsonを次のように作成する。

lambda.json
{
  "name": "facebook_publisher",
  "description": "Post a message to facebook timeline",
  "region": "ap-northeast-1",
  "handler": "facebook_publisher.lambda_handler",
  "role": "arn:aws:iam::<AccountID>:role/lambda_basic_execution",
  "timeout": 300,
  "memory": 256 
}

メモしておいたIAM RoleのARNをroleに設定すること。

requirements.txtの作成

今回はFacebookのGraphAPIをラップするFacebook SDK for Pythonを利用する。このFacebook SDK for Pythonはrequestsに依存しているが、これら二つのライブラリをrequirements.txtに記述しておけば、Lambda Functionと同梱してAWSにアップロードされる。

requirements.txt
requests
facebook-sdk

Lambda Functionの作成

トークンとメッセージをeventとして入力されると、自分自身もしくはトークンを取得したfacebookページにメッセージを投稿するLambda Function(facebook_publisher.py)を作成する。

facebook_publisher.py
#!/usr/bin/env python
# -*- encode: utf-8 -*-

from __future__ import print_function

import json
import facebook


class Timeline:
    def __init__(self, user_token, page_token):
        self.user_endpoint = facebook.GraphAPI(user_token)
        self.page_endpoint = facebook.GraphAPI(page_token)

    def post_me(self, msg):
        self.user_endpoint.put_object('me', 'feed', message=msg)
        print('posted to my timeline: %s' % msg)

    def post_page(self, msg):
        self.page_endpoint.put_wall_post(message=msg)
        print('posted to page timeline: %s' % msg)


def lambda_handler(event, context):
    user_token = event['token']['user_access']
    page_token = event['token']['page_access']
    target = event['target']
    message = event['message']
    try:
        timeline = Timeline(user_token=user_token, page_token=page_token)
        if target == 'me':
            timeline.post_me(message)
        elif target == 'page':
            timeline.post_page(message)
        else:
            print('%s is invalid' % target)
            return False
    except Exception as e:
        print('[%s] %s' % (type(e).__name__, str(e)))
        return False

    return True

AWS Lambdaへアップロード

labmda-uploaderを利用して、Lambda Functionと関連ライブラリをAWS Lambdaへアップロードする。

$ tree .
.
├── facebook_publisher.py
├── lambda.json
└── requirements.txt
$ 
$ lambda-uploader 
λ Building Package
λ Uploading Package
λ Fin

AWS LambdaからFacebookのタイムラインへ投稿

では、AWS CLIからAWS Lambdaへイベントを発行し、AWS LambdaからFacebookへメッセージを投稿してみる。

イベントファイルの作成

今回の検証では、他のサービスから呼び出されるのではなく、手動でイベントを発行するので、次のイベントファイル(event.json)を作成する。

event.json
{
  "token": {
    "page_access": "<取得したFacebookのPage Access Token>", 
    "user_access": "<取得したFacebookのUser Access Token>"
  },
  "target": "<me|page> 自分のタイムラインに投稿する場合はme、facebookページに投稿する場合はpage",
  "message": "<投稿するメッセージ>"
}

イベント発火

では、AWS CLIからイベントを発火させよう。

$ aws lambda invoke --invocation-type RequestResponse --function-name facebook_publisher --payload file://event.json output.txt
{
    "StatusCode": 200
}

発火時に指定したoutput.txtを確認すれば、Lambda Functionからの戻り値がわかる。

output.txt
vagrant@trusty64:~/python/aws_lambda$ cat output.txt 
true

投稿結果

上記の手順により、自分自身のタイムラインやfacebookページのタイムラインへAWS Lambdaから投稿できた。

スクリーンショット 2015-12-15 0.24.02.png

スクリーンショット 2015-12-15 0.24.54.png

AWS Lambdaの結果は、CloudWatch Logsから確認できる。

スクリーンショット 2015-12-15 0.28.49.png

まとめ

AWS Lambda以前の部分で苦労はあるものの、facebookの自分のタイムラインやページのタイムラインへAWS Lambdaからメッセージを投稿することができた。例えばreleaseタグをgithubへpushしたらfacebookページへ告知するなど、なんかイイカンジに使えないかと考えている。