しろかい!

アプリ開発や機械学習などの開発Tips.

【Python】Flask+TweepyでTwitter連携アプリを作る

「Flask」と「Tweepy」を使ってTwitter連携アプリを作成する方法をまとめました.
どちらもPythonで実装されたライブラリで,FlaskはWeb開発フレームワーク,TweepyはTwitter APIへのアクセスを簡単にしてくれるライブラリです.

Flask と Tweepy について

Flaskとは?

公式サイトの日本語版ドキュメントによると,

Flaskは、Python用のマイクロWeb開発フレームワークです。
Bitbucket | The Git solution for professional teams

とのことです.

Webフレームワークといえば,Rails,CakePHP,Django等が有名ですが,これらはフルスタックWeb開発フレームワークと呼ばれています.
「フルスタック」とは「全部入り」という意味で,Web開発に必要なあらゆる機能をこれ1つでカバーしています.
ただし,その分学習コストが高く敷居は高めです.

一方で,FlaskはWebアプリの実装に必要最小限の機能のみに絞ったコンパクトなフレームワークです.
機能が必要最小限しかないので,学習コストが低く敷居は低めです.
また,最小限と言っても簡単なWebアプリを開発する程度であれば十分の機能を持っています. これが「マイクロ」の意味するところです.

今回はこのFlaskを使ってWebアプリを開発します.

Tweepyとは?

PythonからTwitter APIを簡単に利用できるライブラリです.
Twitter APIは素のまま使おうと思うと色々面倒(特に認証周り)なのですが,その辺をライブラリ側で大体何とかしてくれます.

他にもそのようなライブラリは複数存在しますが,個人的に一番しっくりきたのがTweepyだったので,今回はこれを使用します.

なお,公式サイトは以下になります.
Tweepy

環境構築

以下がインストール済みであることを前提に話を進めます.

  • Pythonは 2.7.xç³» をインストール済み.
  • pip をインストール済み.
  • git をインストール済み.

Flask, Tweepyのインストール

pip でインストールするだけです.
root権限で実行して下さい.

# pip install flask
# pip install tweepy

また,アプリの実行に以下も必要なのでインストールしておきます.

# pip install gunicorn

Twitter API key の取得

以下のページを参考にして,Twitter API keyを取得します.

http://wplogs.com/twitter-apps/

アプリケーション作成画面 (Create an application) での入力内容に関しては何でも構いません.
「Website」の項目も適当なURL(例えば http://twitter.com/ )を入力しておけばOKです. また,「Callback URL」も何でもいいので必ず入力するようにして下さい*1.

作成が完了したら,上記のページを参考にして「Consumer key」と「Consumer secret」を控えておきます.

Heroku周り

アカウント登録

Heroku公式サイトの「Sign up」ボタンからアカウント登録を行います.

Heroku Toolbelt のインストール

「Heroku Toolbelt」とはHerokuをターミナル上で操作するのに必要なツールです.
以下からインストールできます.

インストールしたら heroku login コマンドでログインします.
メールアドレスとパスワードを要求されるので入力します.

$ heroku login
Enter your Heroku credentials.
Email: [Herokuに登録したメールアドレス]
Password (typing will be hidden): [パスワード]

また,HerokuへアプリをデプロイするのにSSH公開鍵の登録が必要です.
鍵を作成していない場合は以下のように表示されるので作成して登録します.

Could not find an existing public key.
Would you like to generate one? [Yn]
Generating new SSH public key.
Uploading ssh public key /Users/hoge/.ssh/id_rsa.pub

アプリの実装

今回作るアプリは「連携アプリ認証を行い,そのユーザーのタイムラインを表示する.」というものです.

実装したコードはGitHubに公開してあります.

実際に以下のURLで稼働しています.
https://flask-tweepy.herokuapp.com/

以下,FlaskとTweepyの使い方に触れながらコードの解説を書いていますが,とりあえずアプリを動かしたいという方は「ローカルで動かす」や「Herokuに公開」の項にスキップして下さい.

ディレクトリ構成

flask-tweepy
├── Procfile         # Heroku上で起動するコマンドを記述するファイル
├── README.md        # Readme
├── app.py           # アプリ本体
├── requirements.txt # 依存ライブラリを記述するファイル
├── static           # 静的ファイル (画像, CSS, JS等) を置くディレクトリ (今回は使いません)
└── templates        # アプリ内で呼び出すテンプレートを置くディレクトリ
    └── index.html   # root ページのテンプレート

実際にコードを書くのは app.py と templates/index.html の2つです.

app.py

# Consumer Key
CONSUMER_KEY = os.environ['CONSUMER_KEY']
# Consumer Secret
CONSUMER_SECRET = os.environ['CONSUMER_SECRET']
# Callback URL (認証後リダイレクトされるURL)
CALLBACK_URL = 'https://flask-tweepy.herokuapp.com/' # Heroku上
# CALLBACK_URL = 'http://localhost:5000/' # ローカル環境

CONSUMER_KEY と CONSUMER_SECRET は「Twitter API key の取得」で控えておいた「Consumer key」と「Consumer secret」のことです.
環境変数に設定して呼び出すようにしています.
こうすることで,ソースコードに直にkeyを記述する必要がなくなります.
環境変数への設定方法は後述します.

CALLBACK_URL は連携アプリ認証後にリダイレクトされるURLです.
ローカル環境とHeroku上ではURLが異なるので,都度変更する必要があります.

# Flask の起動
app = Flask(__name__)

Flaskを使うための呪文です.
こう書くものだと思って下さい.

# flask の session を使うにはkeyを設定する必要がある.
app.secret_key = os.environ['SECRET_KEY']

Flask の session 機能を使うためには app.secret_key に値を設定する必要があります.
ここでも環境変数を用いており,設定方法は例のごとく後述とします.

@app.route('/')
def index():

Flask独特の書き方が出てきました. 関数の直前に @app.route(PATH) と書くことで,PATH と 関数を紐付けます.
上記の例では,'/' (root ページ) がリクエストされたら index() 関数を呼び出すように設定したことになります.

return render_template('index.html', timeline=timeline)

このように書くことで,テンプレートを使ってページをレンダリング(描画)してくれます.
上記では、index.html を使ってページを描画しています.
テンプレートは templates ディレクトリに置いておくことで自動で認識してくれます. また,値をテンプレートに渡すことも可能で,上記では timeline (ユーザーのタイムラインのツイートのリスト) を渡しています.

@app.route('/twitter_auth', methods=['GET'])
def twitter_auth():

'/twitter_auth' と twitter_auth() 関数を紐付けます.
ただし,今回は methods=['GET'] と指定することで「GET以外のリクエストを拒否」しています.

# tweepy でアプリのOAuth認証を行う
auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET, CALLBACK_URL)

try:
    # 連携アプリ認証用の URL を取得
    redirect_url = auth.get_authorization_url()
    # 認証後に必要な request_token を session に保存
    session['request_token'] = auth.request_token
except tweepy.TweepError, e:
    logging.error(str(e))

twitter_auth() 関数では Tweepy を使って連携アプリ認証用のURLを取得します.
ソースコードのコメント通り,

  1. OAuth認証
  2. アプリ認証用URLの取得
  3. request_token を session に保存

という流れになります.
request_token はアプリ認証後に Access token, Access token secret というものを取得する時に必要になるので,セッションに保存しておく必要があります.

return redirect(redirect_url)

redirect もFlaskの機能で,指定したURLにリダイレクトしてくれます.
上記では取得したアプリ認証用のURLに飛ばしています.

def user_timeline():

アプリ認証したユーザのタイムラインを取得する関数です.
流れとしては,

  1. request_token と oauth_verifier のチェック
  2. OAuth 認証
  3. Access token, Access token secret の取得
  4. Twitter APIにアクセスするためのインスタンスを生成し,タイムラインを取得

という感じです.

# request_token と oauth_verifier のチェック
token = session.pop('request_token', None)
verifier = request.args.get('oauth_verifier')
if token is None or verifier is None:
    return False # 未認証ならFalseを返す

request_token と oauth_verifier のチェックです.

request_token は session に保存してあるはずなので,そこから取得します.
取得したら session からは削除しておきたいので pop メソッドを使っています.

oauth_verifier はアプリ認証後にアプリのページにリダイレクトされる際にURLパラメータとして付与されています.
Flaskの request.args.get() 関数を使えば,URLパラメータの値を取得することができます.

最終的に,2つのうちどちらか一方でも欠けている場合は認証が済んでいないとみなし,False を返します.

# tweepy でアプリのOAuth認証を行う
auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET, CALLBACK_URL)

# Access token, Access token secret を取得.
auth.request_token = token
try:
    auth.get_access_token(verifier)
except tweepy.TweepError, e:
    logging.error(str(e))
    return {}

OAuth 認証と Access token, Access token secret の取得です.
Access token, Access token secret を取得するには先程チェックした request_token と oauth_verifier が必要です.
正しく Access token, Access token secret を取得できていれば,auth.access_token, auth.access_token_secret にそれぞれ値が格納されているはずです.
もし,認証状態を永続させる場合はこれらをDB等に保存しておくとよいです.

# tweepy で Twitter API にアクセス
api = tweepy.API(auth)

# user の timeline 内のツイートのリストを最大100件取得して返す
return api.user_timeline(count=100)

tweepy.API(auth) で,Twitter APIにアクセスするためのインスタンスを生成します.
そして api.user_timeline() メソッドによりタイムラインのツイートをリスト形式で取得して返しています.
count=100 により,最大100件まで取得するようにしています.

templates/index.html

{% if timeline == False %}
  <!-- 条件が True の場合に表示する要素 -->
{% else %}
  <!-- 条件が False の場合に表示する要素 -->
{% endif %}

所謂if文です.
基本的にPythonと同じように使えますが,若干仕様が異なるみたいです.
上記コードでは,アプリ認証が済んでいない場合はアプリ認証用のリンクを表示し,済んでいる場合はユーザのタイムラインを表示します*2.

{{ url_for('twitter_auth') }}

Flaskではテンプレートで使える関数がいくつか用意されており,url_for() もその1つです.
この関数は,指定したパスを実際にアクセスできるURLに変換します.
上記だと,アプリ認証用のURLに変換してくれます.

また,関数や変数を使う時は {{ }} で囲う決まりになっています.

{% for status in timeline %}
  <p>{{ status.text }}</p>
  <hr>
{% endfor %}

こちらは for 文ですね.
timeline からツイート (Statusオブジェクト) を1件ずつ取り出し,ツイート本文 status.text を表示しています.

ローカルで動かす

Herokuで動かす前に,まずはローカル環境で動かしてみます.
そのためには .env というファイルを準備する必要があります.

中身は以下のようにします.

SECRET_KEY=******
CONSUMER_KEY=******
CONSUMER_SECRET=******

SECRET_KEY には 任意の英数字を記述します.何でも構いません(例:HvonjvTDDllnFkcnKJbvT6i,lnJYFY)が,短すぎるのは止めといたほうがよいでしょう.

CONSUMER_KEY, CONSUMER_SECRET には「Twitter API key の取得」で控えておいた「Consumer key」と「Consumer secret」をコピペします.

完成したら,Procfile を置いているのと同じディレクトリに保存して下さい.
実はこれでローカル環境への環境変数の設定が完了したことになります.

もう1つ変更が必要な箇所があります.
app.py の CALLBACK_URL にローカル環境用のURLをセットします.
以下のようにコメントアウトする行を変更して下さい.

# Callback URL (認証後リダイレクトされるURL)
# CALLBACK_URL = 'https://flask-tweepy.herokuapp.com/' # Heroku上
CALLBACK_URL = 'http://localhost:5000/' # ローカル環境

さて,それでは動かしてみます.
アプリのディレクトリ直下で以下のコマンドを入力します.

% foreman start
12:30:34 web.1  | started with pid 61216
12:30:35 web.1  | [2015-09-01 12:30:35 +0900] [61216] [INFO] Starting gunicorn 19.3.0
12:30:35 web.1  | [2015-09-01 12:30:35 +0900] [61216] [INFO] Listening at: http://0.0.0.0:5000 (61216)
12:30:35 web.1  | [2015-09-01 12:30:35 +0900] [61216] [INFO] Using worker: sync
12:30:35 web.1  | [2015-09-01 12:30:35 +0900] [61219] [INFO] Booting worker with pid: 61219

この状態でブラウザから以下のURLにアクセスして下さい.

http://localhost:5000/

無事にアプリは動きましたか?

ちなみに,foreman というコマンドはローカルにHerokuの擬似環境を立ち上げるコマンドで,開発時にはお世話になるかと思います.

Herokuに公開

いよいよHerokuに公開します.

まずはHeroku上でアプリ作成を行います.

$ heroku create
Creating tranquil-chamber-4602... done, stack is cedar-14
https://tranquil-chamber-4602.herokuapp.com/ | https://git.heroku.com/tranquil-chamber-4602.git

次に,コードを1ヶ所修正します.
app.py の CALLBACK_URL に作成したアプリのURLをコピペします.
URLは heroku create コマンド実行時に表示されます(上記なら「https://tranquil-chamber-4602.herokuapp.com/」)

).

続いて git commit を行い,それをHerokuにpushしてデプロイします.
以下のコマンドでアプリのディレクトリ直下で実行します.

$ git init
$ git add .
$ git commit -m 'Initial commit'
$ git push heroku master

最後にHeroku側でも環境変数を設定する必要があるので,heroku config:set コマンドで設定します.

$ heroku config:set SECRET_KEY=******
$ heroku config:set CONSUMER_KEY=******
$ heroku config:set CONSUMER_SECRET=******

それでは実際にアクセスしてみます.

$ heroku open

ローカル環境の時と同じように動きましたか?

まとめ

「Flask」と「Tweepy」を使ってTwitter連携アプリを作成し,それをHeroku上に公開する方法を紹介しました.
気づいたらかなり長い記事になってしまいました^^;
読みにくかったらごめんなさいm(__)m

Flask, Tweepy, Heroku にはこの記事で紹介しきれていない機能がまだまだたくさん存在します.
興味のある方は以下の参考ページを参照して下さい^^

参考ページ

続いてはPython(Flask)でHeroku! - Qiita
FlaskアプリをHerokuに公開する手順はここを参考にしました.

Flask
Flaskの公式サイト.英語.

Flask v0.5.1 documentation
Flaskのチュートリアル,ドキュメント,APIリファレンス.一部英語.

Pythonで学ぶwebアプリケーションの作り方 by Flask
Flaskのチュートリアルその2.

Tweepy
Tweepyの公式サイト.英語.

Tweepy Documentation
Tweepyのドキュメント,APIリファレンス.英語.

python で twitter メモ
Tweepyの解説記事.

*1:http://d.hatena.ne.jp/speg03/20091019/1255957580 参照

*2:アプリ認証が済んでいない場合,timeline は False となるように実装しているのでした.