tweepyでStreaming API

id:nekomusha6:20110121:1295606221 でライブラリがtweepyに決まったので、次はアプリケーションの作成になります。

お題

tweepyを使ってフォローしている人のつぶやきをStreaming APIを使って拾う

はじめに

twitterAPIには、公式*1 *2によると現在以下の3種類、分け方によっては5種類があります。

  1. REST API
  2. REST API(Search API)
  3. Streaming API
    1. Streaming API
    2. User Stream
    3. Site Stream

(これらのWeb ServiceのPythonラッパーである)tweepyで対応しているのは、(1)〜(3-1)までですが、今回使用するのは(1)と(3-1)だけです。

それでは検討

Streaming APIのサンプルを見ると、どうやらユーザー名とパスワードが分かれば(Basic認証で)なんかできそうな気がします。で、やってみると...

動きますが、filterのユーザー指定(folow)ができません。いや正確には例えば私のユーザーを指定するのだったら@の後ろに書くnekomushaでいいのかと思っていたのですが、ユーザーID(230193917)が必要でした。それでは

  1. どうすればユーザー名からユーザーIDを得られるのか?
  2. それにどうすればフォローしている人の一覧を得られるのか?

しかし(3-1)Streaming APIにはどちらの機能も用意されていません。これらは(1)REST APIの1つである以下のAPIでまとめて用意されています。

"GET friends/ids"
http://dev.twitter.com/doc/get/friends/ids

これはREST APIかつ認証不要なAPIなので、例えばブラウザから

http://api.twitter.com/1/friends/ids.json?screen_name=nekomusha

とするだけで私のフォローしている人のID一覧がJSON形式で取れてしまいます。

もちろんtweepyにもこのAPIを使う関数が用意されています。

API.friends_ids(id/screen_name/user_id[, cursor])(http://joshthecoder.github.com/tweepy/docs/api.html#API.friends_ids)

これだけ情報が揃えば十分作れそうです。

実装

ほぼサンプルのままですが...

#!/usr/bin/env python

from textwrap import TextWrapper
import tweepy

username = "ユーザー名"
password = "パスワード"

class StreamWatcherListener(tweepy.StreamListener):

    status_wrapper = TextWrapper(width=60, initial_indent=' ', subsequent_indent=' ')

    def on_status(self, status):
        try:
            print self.status_wrapper.fill(status.text)
            print '\n %s %s via %s\n' % (status.author.screen_name, status.created_at, status.source)
        except:
            # Catch any unicode errors while printing to console
            # and just ignore them to avoid breaking application.
            pass

    def on_error(self, status_code):
        print 'An error has occured! Status code = %s' % status_code
        return True # keep stream alive

    def on_timeout(self):
        print 'Snoozing Zzzzzz'

follow_list = tweepy.api.friends_ids(screen_name=username)
if len(follow_list) > 5000:
    print "too many firends."
else:
    stream = tweepy.Stream(username, password, StreamWatcherListener(200), timeout=None)
    stream.filter(follow_list)

なお、フォローしている人が5000人を超えたらエラーにしているのは、

"Streaming API: Methods"
http://dev.twitter.com/pages/streaming_api_methods#statuses-filter

により、デフォルトだとその辺が上限だからです。これ以上増やしたい場合は、User Streamの出番なのでしょう。試していたらfollowしたりされたりなどのイベントまで拾ってくれるようです(いい忘れましたがStreaming APIにするだけでもいっぺんに拾える情報が増えます)。

おまけ

今回は認証方法はBasic認証になっていますが、HTTPなのでパスワードが平文で送られることになります。パスワードは昨今いろいろなところで同じのが使われていたりしがちなので、(OAuthに比べて)漏れたときのダメージが格段に大きく、あまりよくありません。せっかくStreaming APIに対応しても、OAuthでほぼ同じことができるREST APIの方が安全で良いという結論になってしまいます(実はStreaming APIBasic認証/OAuth両対応してます。tweepyがBasic認証しか対応してないだけです)。そこで、まずは暗号化通信できないか調べてみました。結果...

暗号化通信はできませんでした。twitterSSL(HTTPS)に対応していますが、tweepyのStreaming APIではできないからです。しかしtweepyを1行いじればHTTPSで通信できるようになります(HTTPでは通信できなくなりますが)。

/usr/share/pyshared/tweepy/streaming.py: 196

                conn = httplib.HTTPConnection(self.host)

これを

/usr/share/pyshared/tweepy/streaming.py: 196

                conn = httplib.HTTPSConnection(self.host)

こうするだけ!