HOME > 電算 > python で twitter メモ
python で twitter メモ
Python (tweepy 利用)を使って、twitter に投稿した、読んだり、過去ログを保管したりするのだ。
参考:事前準備については、http://jmillerinc.com/2010/05/31/twitter-from-the-command-line-in-python-using-oauth/ がわかりやすかった。
参考:tweepy については、http://joshthecoder.github.com/tweepy/docs/ を見た。
事前準備
認証方式が OAuth になったが、ようするに「twitter がアプリに ID を発給し、ユーザは特定のアプリだけに対してアカウントへの許可をすることができる。この許可はいつでも取り消すことができる」ということだけわかっていればなんとかなる。(OAuth の仕組みについては、http://tools.ietf.org/html/rfc5849 でいいのかな)
(1) twitter にアプリを登録して、CONSUMER KEY と CONSUMER SECRET をもらう。
自分用に複数のスクリプトを書く場合でも、この CONSUMER KYE と CONSUMER SECRET は使いまわせばよいので、登録は一度だけやればよい。この作業はググれば、すぐに親切なスクリーンショットつき解説が見つかるよね。
(2) twitter の自分のアカウントにそのアプリからのアクセスを許可する
(1)で登録したアプリに対して、自分の twitter アカウントへのアクセスを許可する。このとき twitter は ACCESS KEY と ACCESS SECRET を発行するので、これをアプリに教えてやる。以下、具体的作業を対話的にやってみた様子。
$ python >>> import tweepy >>> CONSUMER_KEY = '********************' >>> CONSUMER_SECRET = '*******************' >>> #(上二行は、(1)でもらっておいたキーとシークレットを入れる) >>> auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET) >>> auth_url = auth.get_authorization_url() >>> print 'Please authorize: ' + auth_url Please authorize: http://twitter.com/oauth/authorize?oauth_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx >>> #(ここで上に表示された URL をブラウザに張り付けて、このときだけ使う暗唱番号を web ページからゲット) >>> verifier = raw_input('PIN: ').strip() PIN: xxxxxxxx >>> #(上の PIN: のところで、先程もらった暗唱番号をコピペ) >>> auth.get_access_token(verifier) <tweepy.oauth.OAuthToken object at 0x8f9166c> >>> print "ACCESS_KEY = '%s'" % auth.access_token.key ACCESS_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' >>> #(上に表示されたアクセスキーは後々まで使うのでメモしておく) >>> print "ACCESS_SECRET = '%s'" % auth.access_token.secret ACCESS_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' >>> #(上に表示されたアクセスシークレットは後々まで使うのでメモしておく)
(2)の許可は自分の twitter アカウントから取り消すことができる。その場合は、(2)の手続きをもう一度行って、アクセスキーとアクセスシークレットを再取得する。
あとは以上で手に入れた CONSUMER KEY と CONSUMER SECRET と ACCESS KEY と ACCESS SECRETを使って作業すればよい。
投稿専用スクリプト
#!/usr/bin/env python import sys import tweepy CONSUMER_KEY = 'xxxxxxxxxxxxxxxx' CONSUMER_SECRET = 'xxxxxxxxxxxxxxxx' ACCESS_KEY = 'xxxxxxxxxxxxxxxx' ACCESS_SECRET = 'xxxxxxxxxxxxxxxx' mypost = sys.stdin.readline().strip() if 0==len(mypost): exit() auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET) auth.set_access_token(ACCESS_KEY, ACCESS_SECRET) api = tweepy.API(auth) api.update_status(mypost)
これをシェルから起動すると、一番目の引数にした文字列を投稿することができる。私は GNOME 環境なので、
alias twip='zenity --text-info --filename=/dev/null --editable | python /pass/to/the/script.py'
というのを、シェル用のエイリアスとして書いておき、なんちゃって GUI にして投稿に使っている。
twikabi
ついでだから、コマンドラインでパイプにかませて使えるしょぼいクライアントを書いてみたよ。
過去ログ取得
とりあえず、いくらか実用的なスクリプトを。
sqlite3 形式で過去ログを sqlite3 形式で取得する。twitter 側の制限により最新 3200 件以前のものを取得することはできない。
取得項目は
statusid(発言ID), postdate(時刻), text(本文), replyto(リプライ相手のスクリーンネーム), replyto_id(リプライ相手のID), reply_status_id(リプライ対象となった発言のID)
設定
変数 CONSUMER KEY, CONSUMER SECRET, ACCESS KEY, ACCESS SECRET の値をハードコーディングする ^^;
sqlite3 ファイルへのパス(sqlite3fileという変数名)をハードコーディングする ^^;
使い方
$ python twisave.py
するだけ。二回目以後は、新しく投稿された分だけ取得する。
過去ログ取得2
設定、使用法は前の twisave.py と同じだが、自分へのメンションを含むツイート、自分がリプライした相手のツイートも保存する。リプライ対象となるツイートの保存は、一件につき 1 API カウントを消費するので、初回バックアップは API 回数の制限のために、時間をおいて何度かに分けてやないといけないかもしれない。「お気に入り」をつけたツイートの保存をするには、ファイル最後あたりでコメント・アウトした部分を生かせばよい。ただし、これは毎回全件(最大3200件)を取得するので API カウントを多く消費する。ログファイルは、twisave.py と互換性がない。
フォロー、リムーブにかんする情報の取得
新たにフォローされた/した、リムーブされた/した、一方的フォロー相手、一方的にフォローされている相手、相互にフォローされている相手、を調べる。
設定
変数 CONSUMER KEY, CONSUMER SECRET, ACCESS KEY, ACCESS SECRET の値をハードコーディングする ^^;
また、変数 FOLLOWS, FOLLOWERS にデータを保存するテキストファイルのパスをハードコーディングする。それぞれ、フォロー相手名、フォロワーの名を列挙したテキストファイルのパス。この変数にしたがい、初回に記録ファイルが自動生成され、以後更新される。
使い方
$ python twifollower.py
するだけ。
対話環境で投稿したり、タイムラインを読んだりして遊ぶ
まず、以下を念仏のように最初にやって api オブジェクトを得る。
$ python >>> import tweepy >>> import type >>> CONSUMER_KEY = '' >>> CONSUMER_SECRET = '' >>> ACCESS_KEY = '' >>> ACCESS_SECRET = '' >>> #(上4行は、すでに発行してもらっているものをコピペ) >>> auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET) >>> auth.set_access_token(ACCESS_KEY, ACCESS_SECRET) >>> api = tweepy.API(auth)
投稿のテストをしてみる。
>>> api.update_status('test') <tweepy.models.Status object at 0x90ec66c>
タイムラインを取得。
>>> api.home_timeline()
とやると、最新20個のホーム・タイムラインの投稿をリストにしたものが得られる(すぐ読めるわけではない)
このリストの要素はそれぞれ
<class 'tweepy.models.Status'>
のインスタンスで、投稿(=ステータス)ひとつひとつに対応する。
これらはそれぞれ以下のような変数を持つ。
api | class 'tweepy.api.API' | |
contributors | type 'NoneType' | |
truncated | type 'bool' | |
text | type 'unicode' | 投稿内容 |
created_at | type 'datetime.datetime' | 投稿時間 |
author | class 'tweepy.models.User' | 投稿者※下参照 |
in_reply_to_status_id | type 'NoneType' | リプライ対象となった投稿のID |
coordinates | type 'NoneType' | |
source_url | type 'str' | |
source | type 'str' | |
favorited | type 'bool' | |
in_reply_to_screen_name | type 'NoneType' | リプライ相手の@名 |
in_reply_to_user_id | type 'NoneType' | リプライ相手のID(自然数) |
place | type 'NoneType' | |
geo | type 'NoneType' | |
id | type 'long' | その投稿のID |
user | class 'tweepy.models.User' |
(これらは、ドキュメントが見つからないから__dict__ を調べた。なお type の欄は、たまたま調べたオブジェクトに値がなかったものが none になっているから、それは信用できない)
テキストの内容は、text <type 'unicode'> だから、最新(0番目)の投稿本文は、
>>> api.home_timeline()[0].text
で得られる。
上で投稿者名は、author という変数が示していて、それは <class 'tweepy.models.User'> のインスタンスである。そこで、これが持つ変数を調べてみると、
profile_use_background_image | type 'bool' | |
id | type 'int' | |
api | class 'tweepy.api.API' | |
verified | type 'bool' | |
profile_sidebar_fill_color | type 'str' | |
profile_text_color | type 'str' | |
followers_count | type 'int' | |
profile_sidebar_border_color | type 'str' | |
location | type 'str' | |
profile_background_color | type 'str' | |
utc_offset | type 'int' | |
statuses_count | type 'int' | |
description | type 'unicode' | |
friends_count | type 'int' | |
profile_link_color | type 'str' | |
profile_image_url | type 'str' | |
notifications | type 'bool' | |
geo_enabled | type 'bool' | |
profile_background_image_url | type 'str' | |
screen_name | type 'str' | |
lang | type 'str' | |
profile_background_tile | type 'bool' | |
favourites_count | type 'int' | |
name | type 'unicode' | |
url | type 'str' | |
created_at | type 'datetime.datetime' | |
contributors_enabled | type 'bool' | |
time_zone | type 'str' | |
protected | type 'bool' | |
following | type 'bool' |
(これらは、ドキュメントが見つからないから__dict__ を調べた。なお type の欄は、たまたま調べたオブジェクトに値がなかったものが none になっているから、それは信用できない)
したがって、最新(0番目)の投稿について、api.home_timeline()[0].author.name で名前、api.home_timeline()[0].author.screen_name でスクリーンネーム(@の後につけるやつ)を知ることができる。
まあ、タイムライン最新の20個を一通り読めるようになった。
では、最新20より前のものをどうやって取得するか。
そのために、まず home_timeline() メソッドに食わせるパラメータを見る。(http://joshthecoder.github.com/tweepy/docs/api.html#timeline-methods)
API.home_timeline([since_id][, max_id][, count][, page])¶ * since_id この数字より新しい ID のツイートを得る * max_id この数字と同じか、より古い ID を持つツイートを得る * count 得るツイート数 * page 得るページを指定する
つまり、
>>> api.home_timeline(count=30)
とかやると、最新30ツイートが得られる。
だが、これには制限がある。
http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-home_timeline には May not be greater than 200 と書いてある。
ページングを使えば、もっと前のものを知ることもできる。
>>> api.home_timeline(count=200, page=2)
とやれば、200件ずつ最新から表示した場合の2ページ目、つまり最新から数えて201件から400件目までを得られる。 ただ、このやり方にも制限がある。
http://apiwiki.twitter.com/Things-Every-Developer-Should-Know#6Therearepaginationlimits を見ると、ページとカウントで得られるのは 3200 件までとある。
これは、一度に取得できる件数を指すのではなく、それより古い投稿に、ページとカウントを使ってアクセスすることができないということらしい。(なお、これは API の残りカウント http://apiwiki.twitter.com/Rate-limiting とは別立ての制限である)
tweepy のカーソル機能
tweepy は api.user_timeline メソッドなど 1 ページずつ結果を戻してくるメソッドに、対しカーソルを用意し、ページのことを考えないで済むようにしている。
for p in tweepy.Cursor(api.user_timeline,since_id=10000).items(100): print unicode(p.text)
上の例は、自分のツイートを、ID が 1001 のツイートから最新のツイートまでのうちで、新しいほうから自分のツイート 100 件を、順にプリントする。
エラーとレスポンス・コード
http://apiwiki.twitter.com/HTTP-Response-Codes-and-Errors にコード一覧
tweepy でエラーの種類を捕えるには、
try: r = api.get_status(id) except tweepy.error.TweepError, e: print "error response code: " + str(e.response.status) print "error messate: " + str(e.response.reason)
などとやればよい。
「お気に入り」
api.favorites(id=xxxxxxxx, page=xxxxxxx) などとやって、ユーザのお気に入りツイートを取得できる。
_api | tweepy.api.API |
contributors | |
truncated | bool |
text | unicode |
created_at | datetime.datetime |
author | tweepy.models.User |
in_reply_to_status_id | |
coordinates | |
source | str |
favorited | bool |
place | |
in_reply_to_user_id | |
in_reply_to_screen_name | |
geo | |
id | long |
user | tweepy.models.User |