Python で Twitter から情報収集 (Twitter API 編)

# Python から Twitter の情報にアクセス
Python から Twitter の情報にアクセスする場合は OAuth 認証を利用し、
Twitter API を通して情報のやり取りを行う。

以下それらについての説明と、サンプルコードです。

* Python で Twitter からの情報収集 (環境構築編)
    * 環境構築等は[こちら](http://qiita.com/Salinger/items/081754e9e211135fa6d1)

# Twitter アプリケーションのための認証キーの作成
Twitter は認証方式として OAuth認証 という認証方法を利用している。

* OAuth 認証に必要な物
    * Consumer key
    * Consumer secret
    * Access token
    * Access token secret

これらの作成方法は下記のページに詳しく書いてあるので、ここを参考に4つの認証キーを作成する。
[twitterアプリケーションの作成](http://website-planner.com/twitterアプリケーションの作成（consumer-key、consumer-secret、access-token、access-token-secret/)

# OAuth 認証のための Python ライブラリインストール
今回は [requests-oauthlib](https://github.com/requests/requests-oauthlib)という Python 用の OAuth 認証ライブラリを用いてアクセスする。

`twi-py` 環境下で以下のコマンドを実行する。

```
(twi-py)$ pip install requests requests_oauthlib
```

動作チェック。

```
(twi-py)$ python
>>> from requests_oauthlib import OAuth1Session
>>>
```

エラーが出なければOK。

# Twitter API
基本的にプログラムから Twitter のデータ取得、情報発信は下記APIを利用する。
[https://dev.twitter.com/rest/public](https://dev.twitter.com/rest/public)

今回の目的は指定のキーワードで検索して必要な情報を取得することなので、
GET search/tweets を用いる。
[https://dev.twitter.com/rest/public/search](https://dev.twitter.com/rest/public/search)

# Twitter 検索 API を利用したサンプルコード
## tweet_crawler.py
`#python` のハッシュタグで検索し、その結果を出力するプログラムのサンプルコード。
それぞれの関数中で何をやっているかは、Pythonが読み書き出来る人ならわかると思う。

基本的に url, params, oath.get()/oath.post() 辺りを弄れば、
他の Twitter API を使った操作が行えるので遊んでみよう。

```
#!/usr/bin/env python                                                                                                                                             
# -*- coding:utf-8 -*-                                                                                                                                            

from requests_oauthlib import OAuth1Session
import json

### Constants                                                                                                                                                     
oath_key_dict = {
    "consumer_key": "xxxxxxxxxxxxxxxxxxxx",
    "consumer_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "access_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "access_token_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

### Functions                                                                                                                                                     
def main():
    tweets = tweet_search("#python", oath_key_dict)
    for tweet in tweets["statuses"]:
	tweet_id = tweet[u'id_str']
        text = tweet[u'text']
        created_at = tweet[u'created_at']
        user_id = tweet[u'user'][u'id_str']
	user_description = tweet[u'user'][u'description']
	screen_name = tweet[u'user'][u'screen_name']
	user_name = tweet[u'user'][u'name']
	print "tweet_id:", tweet_id
	print "text:", text
	print "created_at:", created_at
	print "user_id:", user_id
	print "user_desc:", user_description
	print "screen_name:", screen_name
	print "user_name:", user_name
    return


def create_oath_session(oath_key_dict):
    oath = OAuth1Session(
	oath_key_dict["consumer_key"],
	oath_key_dict["consumer_secret"],
	oath_key_dict["access_token"],
	oath_key_dict["access_token_secret"]
	)
    return oath

def tweet_search(search_word, oath_key_dict):
    url = "https://api.twitter.com/1.1/search/tweets.json?"
    params = {
        "q": unicode(search_word),
        "lang": "ja",
        "result_type": "recent",
        "count": "15"
        }
    oath = create_oath_session(oath_key_dict)
    responce = oath.get(url, params = params)
    if responce.status_code != 200:
        print "Error code: %d" %(responce.status_code)
        return None
    tweets = json.loads(responce.text)
    return tweets

### Execute                                                                                                                                                       
if __name__ == "__main__":
    main()

```

## 出力例
```
(twi-py)$ python tweet_crawler.py
tweet_id: 531312631831732225
text: ShannonLabが地元八王子にてpythonの勉強会を定期的に行なっております。プログラミングの初級者の方も参加出来ます。「Python　勉強会　八王子」で検索してね。 ATND\
 から登録出来ます。 #python
created_at: Sun Nov 09 05:09:37 +0000 2014
user_id: 426868502
user_desc: 創造力で、人を、世界を、変える。Shannon Labは数理、人工知能、芸術の融合により、イノベーティブな世界をつくる。プログラミング勉強会やAndroidアプリ製品の\
情報をつぶやきます。現在、PythonでAndroidアプリをつくる勉強会を企画中。インターン、エンジニアー募集中です。
screen_name: shannon_lab
user_name: Shannon Lab
tweet_id: 531253415548944385
text: こうやって見ると初心者向けのハンズオンとかって結構意義があるのかもしれない。
Pythonと出会ったデザイナーの話 #PyLadiesTokyo by @uniq #python http://t.co/rZMEruT4yf @SlideShareさんから
created_at: Sun Nov 09 01:14:19 +0000 2014
user_id: 337419400
user_desc: 日々之エンジニア
screen_name: icoxfog417
user_name: ピクシィ
tweet_id: 531247311288946688
text: Pythonと出会ったデザイナーの話 #PyLadiesTokyo by @uniq #python http://t.co/MwMFS5IFQ1 null
created_at: Sun Nov 09 00:50:03 +0000 2014
user_id: 1497018468
user_desc: Software Engineer
.NET/C#/HTML5/CSS3/JavaScript/jQuery/Perl/Ruby/Python
screen_name: teruru2013
user_name: てる
... 
```

# Twitter API 制限の話
[https://dev.twitter.com/rest/public](https://dev.twitter.com/rest/public)
各APIの説明を読むと中に下記のような記述がある。

```
Requests / 15-min window (user auth)  180
Requests / 15-min window (app auth)   450
```

これは15分間あたりにAPIを利用して情報を取得できる上限回数だ。
デフォルトだとこの場合 180回/15min となる。

１つの Access token と Access token secret 以外からアクセスしない、
app auth の方を利用すれば、 450回 / 15min となる。

app auth については、公式ページの下記URLに詳細が記述されている。
[https://dev.twitter.com/oauth/application-only](https://dev.twitter.com/oauth/application-only)

ガンガン情報を集めているとすぐに引っかかってしまうので、回避策を検討する必要がある。
基本的に上限に引っかからない回数までに押さえるのがベストだが、
短時間に制限以上のの検索結果が必要な場合は複数個の Twitter id を取得して、
OAuth 認証に必要なキーをレスポンスのステータスが上限に達した場合、
次のキーに切り替えて取得を続ける方法がある（内部的には複Twitterアプリ構成となる）。
ただし、アカウントを量産しすぎるとアカウントが凍結される危険性も高まるので注意。