tweepyでStreaming API
id:nekomusha6:20110121:1295606221 でライブラリがtweepyに決まったので、次はアプリケーションの作成になります。
お題
tweepyを使ってフォローしている人のつぶやきをStreaming APIを使って拾う
はじめに
twitterのAPIには、公式*1 *2によると現在以下の3種類、分け方によっては5種類があります。
(これらのWeb ServiceのPythonラッパーである)tweepyで対応しているのは、(1)〜(3-1)までですが、今回使用するのは(1)と(3-1)だけです。
それでは検討
Streaming APIのサンプルを見ると、どうやらユーザー名とパスワードが分かれば(Basic認証で)なんかできそうな気がします。で、やってみると...
動きますが、filterのユーザー指定(folow)ができません。いや正確には例えば私のユーザーを指定するのだったら@の後ろに書くnekomushaでいいのかと思っていたのですが、ユーザーID(230193917)が必要でした。それでは
- どうすればユーザー名からユーザーIDを得られるのか?
- それにどうすればフォローしている人の一覧を得られるのか?
しかし(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 APIはBasic認証/OAuth両対応してます。tweepyがBasic認証しか対応してないだけです)。そこで、まずは暗号化通信できないか調べてみました。結果...
暗号化通信はできませんでした。twitterはSSL(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)
こうするだけ!
ubuntu & pythonでtwitter
gwibberによる収集もいいのですが、BOTによる自動収集で規模を増やしたくなりました。そこで今更ですがpythonからtwitter APIを使うことにします。
結論
PPAからpython-tweepy引っ張ってくることにしました。
経緯
まず疑問点が2つありました。
- UbuntuってPythonで動いている部分が結構あるんだけどapt使わずにsudo easy_installとかしていいの?
- python用のtwitterモジュールっていくつもあるけどどれがいいの?
以下ではこれらの疑問に対する答えを探っています。
1. Ubuntuパッケージとの競合
Ubuntuでは結構Pythonを使っているので心配です。モジュールの追加に関して調べてみたところ
"Why you should not use easy_install carelessly on Debian"
http://workaround.org/easy-install-debian
という2009年12月のブログを見つけました。英語なので概略だけ書いておくと、
- easy_install(setuptool)は悪くないけどアンインストールもできないし汚い
- easy_install(setuptool)とaptで二重にインストールが行われるかもしれない(どちらが使われるかは設定次第)
- debianのaptだとバージョンが古くてもセキュリティパッチが提供され続ける
- 新しいものが欲しければdebian unstableを使えばいい
- 日常使用にはオススメしないがvirtualenvで環境を切り替えられるよ
とのこと。競合までするのか分かりませんが、互いに互いを意識してなさそうなので重ならないようにしないといけない気がします。
なおvirtualenv自体の使い方などについては、同じ時期にこちらにも
"2009年版Python開発環境を整えよう"
http://labs.unoh.net/2009/12/2009python.html
書かれていました。これらの情報、玄人的には当たり前なのかもしれませんが、素人的には助かります。
以上の情報から、Ubuntuはunstable相当でしょうし、個人的には
基本はaptで、公式リポジトリになかったり欲しいのより古ければPPAで、それでもなければvirtualenvかeasy_installという感じ
でいいのかな、と考えています。
2. python用twitterモジュールの選択
twitter公式にあるだけでも現在
モジュール | 作者 | 説明 |
---|---|---|
oauth-python-twitter2 | Konpaku Kogasa | Combines python-twitter and oauth-python-twitter to create an evolved OAuth Pokemon. |
python-twitter | DeWitt Clinton | This library provides a pure Python interface for the Twitter API. |
python-twyt | Andrew Price | BSD licensed Twitter API interface library and command line client. |
twitty-twister | Dustin Sallings | A Twisted interface to Twitter. |
twython | Ryan McGrath | REST and Search library inspired by python-twitter. |
Tweepy | Josh Roesslein | Supports OAuth, Search API, Streaming API. |
これだけあるようです。ググったりするとtweepyがいいようですが、python-twitterも名前がそのものすぎて気になります。python-twitterは10.10付属のバージョンだとOAuthが使えずにダメなのですが、PPAで新しいのを持ってくるとOAuthは使えるようになります。対してtweepyはUbuntu公式リポジトリにはありません。これは迷います。
さて、twitterへのアクセスは
"Rate Limiting"
http://dev.twitter.com/pages/rate-limiting#rest
にあるように、認証つきのものはユーザーごとに350リクエスト/h、認証なしのものはIPごとに150リクエスト/hとなっており、制限を超えてしまうとエラーになってしまいます。例えば頻繁に更新したくて、制限ギリギリまでリクエストを出すように設計すると、同じユーザーで別のアプリからいじったときに350/h制限に引っかかったりしてしまい、面倒だったりします。
しかし、Streaming APIを使うとこの制限を受けません。tweepyはこの紹介文中唯一Streaming API対応をうたっています*1。というわけで今回は
tweepyが良いかな
という感じです。
3. 総合的に
tweepyはUbuntu公式リポジトリには用意されていませんでしたが、PPAにはあるようです。
"python-tweepy"
https://launchpad.net/~chris-lea/+archive/python-tweepy
というわけでtweepyに決定です。11.04では公式リポジトリに入ってほしいな。
おまけ
gwibberはどうしているかというと...OAuthとJSONパーサはモジュール使うものの、後は自力なようです。
MySQL対応
その人を表す特徴的な単語*1で書いたコードをMySQLに対応させてみました。
https://github.com/nekomusha/public/tree/hatena20110120/twitter_statistics/src
*1:id:nekomusha6:20110113
SQLAlchemy+MySQL Unicode文字列の怪
Python2.Xで日本語を扱うときUnicode文字列への/からの変換時に面倒な問題があるらしく*1、コード内ではどちらかに統一したいと思うらしいです(そう思います)。しかしSQLAlchemyにはPlane/Unicodeどちらで渡す/から返される文字列はどちらなのか仕組みがよく分かりません。そこで分かる範囲内で少し(現象的に)調べてみました。
結果
以下のように推測します。
create_engine()のconvert_unicode引数 | True | False |
---|---|---|
渡す文字列 | Unicode型? | DB-APIが受け取れるもの? |
返る文字列(String経由) | Unicode型 | DB-APIが返したもの |
返る文字列(executeなどDB-API直) | DB-APIが返したもの | DB-APIが返したもの |
特に問題になるのはデータベースのドライバが返したものが何になるのかですが、MySQLdbとSQLiteについては以下のように推測します。
DB-API | 条件 | 返る型 |
---|---|---|
SQLite | なし | unicode |
MySQLdb | collate *2 がbinary(utf8_binなど) | str |
MySQLdb | collateがbinary以外でuse_unicode=1 *3 | unicode |
MySQLdb | collateがbinary以外でuse_unicode=0 | str |
collate値によってunicodeにならないのは不自然と思います。調べてみたら案の定
http://sourceforge.net/tracker/index.php?func=detail&aid=2837134&group_id=22307&atid=374932
バグ登録されてました。1年以上前に....(でもopen
つまりDB-APIのMySQLdbのバグでSQLAlchemyは無罪ということのようです。
根拠
以下の2サイトの情報を元に
http://technolize.blogspot.com/2010/11/sqlalchemy-collate-utf8bin.html
http://groups.google.com/group/sqlalchemy/browse_thread/thread/f4ba7ca61206fa7e/cb47da86cb7856f2
以下のように現象ベースで試しみました。
MySQLについては以下の2パターンで
(1)create database practice CHARACTER SET 'utf8';
(2)create database practice CHARACTER SET 'utf8' COLLATE 'utf8_bin';
以下のコードを実行して
#! -*- coding: utf-8 -*- from itertools import izip from sqlalchemy import Column, String, create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Sample(Base): # Sampleクラスとsamplesテーブルとそのマッピングの定義 __tablename__ = 'samples' # テーブル名 __table_args__ = {'mysql_engine':'InnoDB'} # MySQLではInnoDB id = Column(String(10), primary_key=True) # IDカラムの定義 val = Column(String(10)) # VALカラムの定義 def __init__(self, id, val): self.id = id self.val = val # SQLiteとMySQLのデータベースの定義 engine_parameters = ( "sqlite:////home/user1/practice.sqlite", "mysql+mysqldb://root@localhost/practice?charset=utf8&use_unicode=0", "mysql+mysqldb://root@localhost/practice?charset=utf8&use_unicode=1", ) # エンジンの作成 engines = [] names = [] for param in engine_parameters: for conv in (True, False): engines.append(create_engine(param, echo=False, convert_unicode=conv)) scheme = param[0:5] + param[-1] names.append("%s-%s" % (scheme, conv)) # セッションクラスの作成とセッションオブジェクトの作成(SQLiteとMySQL両方) Sessions = [] sessions = [] for engine in engines: # create table Base.metadata.create_all(engine) # セッション生成 Sessions.append(sessionmaker(bind=engine)) sessions.append(Sessions[-1]()) # SQLの実行 for name, session in izip(names, sessions): # insert into samples values(xxx, 'val1') session.add(Sample(u'文字列ID', u"文字列VAL")) selector = session.query(Sample) value = selector.filter(Sample.id == u"文字列ID").one().val print name, "query", type(value), value (value,), = session.execute("select val from samples where id=:id", {"id": u"文字列ID"}) print name, "execute", type(value), value session.rollback() session.close()
以下のようになりました。
(1)collate指定なし
sqlite-True query <type 'unicode'> 文字列VAL sqlite-True execute <type 'unicode'> 文字列VAL sqlite-False query <type 'unicode'> 文字列VAL sqlite-False execute <type 'unicode'> 文字列VAL mysql0-True query <type 'unicode'> 文字列VAL mysql0-True execute <type 'str'> 文字列VAL mysql0-False query <type 'str'> 文字列VAL mysql0-False execute <type 'str'> 文字列VAL mysql1-True query <type 'unicode'> 文字列VAL mysql1-True execute <type 'unicode'> 文字列VAL mysql1-False query <type 'unicode'> 文字列VAL mysql1-False execute <type 'unicode'> 文字列VAL
(2)collate指定がbinary
sqlite-True query <type 'unicode'> 文字列VAL sqlite-True execute <type 'unicode'> 文字列VAL sqlite-False query <type 'unicode'> 文字列VAL sqlite-False execute <type 'unicode'> 文字列VAL mysql0-True query <type 'unicode'> 文字列VAL mysql0-True execute <type 'str'> 文字列VAL mysql0-False query <type 'str'> 文字列VAL mysql0-False execute <type 'str'> 文字列VAL mysql1-True query <type 'str'> 文字列VAL mysql1-True execute <type 'str'> 文字列VAL mysql1-False query <type 'str'> 文字列VAL mysql1-False execute <type 'str'> 文字列VAL
つまり
- SQLiteは全てがunicodeです
- MySQLはuse_unicode=1かつcollateデフォルトで全てunicodeです。
- MySQLはuse_unicode=1かつcollateがbinaryで全てstrです。
- MySQLはuse_unicode=0かつconvert_unicode=Falseでは全てstrです。
- MySQLはuse_unicode=0かつconvert_unicode=Trueではqueryはunicodeです。
- MySQLはuse_unicode=0かつconvert_unicode=Trueではexecuteはstrです。
ということになり、辻褄が合うように一般化すると最初の推測になる、というわけです。
SQLAlchemy+MySQLでUpdate文に失敗
ハマった問題の原因調査結果です。
現象
sqlalchemy.orm.exc.ConcurrentModificationError: Updated rowcount 0 does not match number of objects updated 1
原因不明なこんなメッセージに悩まされてました。
再現条件
- SQLAlchemy
- MySQL
- アダプタがMySQLdb
再現スクリプト
動作条件
Ubuntu 10.10で必要なパッケージは
以下のデータベースを作成済みであること
CREATE DATABASE practice DEFAULT CHARACTER SET utf8 COLLATE utf8_bin
スクリプト
コメントにしてますが、比較用にSQLiteでの動作なども確認できます。
#! -*- coding: utf-8 -*- from sqlalchemy import Column, String, Numeric, create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Sample(Base): # Sampleクラスとsamplesテーブルとそのマッピングの定義 __tablename__ = 'samples' # テーブル名 __table_args__ = {'mysql_engine':'InnoDB'} # MySQLではInnoDB id = Column(Numeric(18,0), primary_key=True) # IDカラムの定義 val = Column(String(10)) # VALカラムの定義 def __init__(self, id, val): self.id = id self.val = val # SQLiteとMySQLのデータベースの定義 # MySQLは事前にCREATE DATABASE practice DEFAULT CHARACTER SET utf8 COLLATE utf8_bin(大文字小文字区別あり) engines = ( # create_engine("sqlite:////home/user1/practice.sqlite", echo=True), create_engine("mysql+mysqldb://root@localhost/practice?charset=utf8&use_unicode=0", echo=True), ) # セッションクラスの作成とセッションオブジェクトの作成(SQLiteとMySQL両方) Sessions = [] sessions = [] for engine in engines: # create table Base.metadata.create_all(engine) # セッション生成 Sessions.append(sessionmaker(bind=engine)) sessions.append(Sessions[-1]()) # SQLの実行 for session in sessions: # insert into samples values(xxx, 'val1') session.add(Sample(19778376323571713, "val2")) # commit session.commit() # select * from samples for sample in session.query(Sample): print sample.id, sample.val # update samples set val='削除します' where id=? sample.val = u'削除します' # commit session.commit() # delete from samples where id=? session.delete(sample) # commit session.commit() session.close()
原因
update時に
UPDATE samples SET val='削除します' WHERE samples.id = '19778376323571713'
なクエリが出ていたこと。MySQLのマニュアル*1によると、この文字列は一旦53bitの浮動小数点数に丸められるため、この桁数は表現できず、WHERE句の条件では一致しない。
正しくは
UPDATE samples SET val='削除します' WHERE samples.id = 19778376323571713
でないといけない。
回避策
この例ではNumericの代わりにBigIntegerを使用する
とても助かったページ↓(マニュアルの翻訳)
http://omake.accense.com/static/doc-ja/sqlalchemy/index.html
Python開発環境 on Ubuntu 10.10
普通はemacsかvimか、もしくはNetBeansと言ったところ(WindowsだとPyScripterとかも。wineでどうかとかは知りません。)なんでしょうが、eclipseでのPython開発環境構築方法をメモっておきます。先に断っておくと環境にもpythonにも詳しくなくまだ勉強中の身の上です。環境はUbuntu 10.10 64bit版です。
(ちょっと長めですが、細かく書いただけで別に大変な作業ではありません。)
JREのインストール
eclipseはほとんどJavaで書かれており、その動作にJREが必要になるので、まずは入れちゃいます。
$ sudo apt-get install default-jre
Javaの開発もしたい人は
$ sudo apt-get install default-jdk
としてJDKも入れた方がいいかもしれません。
eclipse本体のインストール
Ubuntuにはeclipseパッケージも用意されていますが、最新ではないのでここでは本家から取ってきます(好み)。
http://www.eclipse.org/downloads/
ただし以下のように目的別にいろいろなエディションが用意されています(Pythonはないですが)。
Pythonは後からプラグインで入れるのでどれでもいいのですが、ここではせっかくLinuxなのでEclipse IDE for C/C++ Linux Developersにしておきます(趣味)。
ダウンロードが終わったら、書庫マネージャでホームディレクトリに展開します。展開し終わると以下のようにホームディレクトリにeclipseフォルダができ、この中にeclipseがインストールされています。
このフォルダにあるeclipseをダブルクリックすればeclipseが起動するのですが、このままでは英語版のC/C++開発環境になります。
eclipse日本語化プラグインPleiadesのインストール
次はメニューなどを日本語にします。以下のサイト
http://mergedoc.sourceforge.jp/
に行って赤丸部分をクリックしpleiadesプラグインだけをダウンロードしにいきます(all-in-oneはWindows用なので)。
いつでも
subversionのリポジトリなので分かりにくいデスが、赤丸部分からダウンロード出来ます。ダウンロードが終わったら書庫マネージャからeclipseフォルダ(~/eclipse)に展開します。
展開が終わったらeclipse.ini(~/eclipse/eclipse.ini)を編集するので開きます。
開いたら以下の(ユーザー名)をご自分のユーザー名に置き換えて最終行に追加します。
-javaagent:/home/(ユーザー名)/eclipse/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
ここまでできれば日本語用の設定はOKです。
eclipse(~/eclipse/eclipse)を実行して日本語の画面が表示させてください。
この画面が日本語の最初の画面です。eclipseのプロジェクトの置き場所であるワークスペースをどこにするか尋ねています。とりあえずデフォルト(~/workspace)でいいのでOKします。OKすると、開発用の画面が立ち上がります。
このようこそ画面は得るものがないのでさっさと閉じます(ヘルプ>ようこそで見れます)
Python開発用プラグインPyDevのインストール
このプラグインはeclipse上のUIからインストールすることができます。
まずはeclipseのメニューからヘルプ>新規ソフトウェアのインストール...を選択すると、
このような画面が開きます。これは何のプラグインをインストールか尋ねている画面ですが、まずはPyDevプラグインを置いているサイト(リポジトリ)を追加するために追加ボタンを押します。
名前は自動判定してくれるので、ロケーションに以下のURL(PyDevプラグインを置いているサイト)を入力してOKします。
http://pydev.org/updates
OKすると元の画面に戻るのですが、先の追加により真ん中のリストボックスにチェックできる項目が二つほど出現します。これがPyDevのプラグインとそのオプションプラグインです。なお出現には数十秒程度時間がかかることがあるので、すぐに出ない場合は少し待ってください。
チェックできるようになったら、両方チェックして次へを押します。
進んだ画面は依存関係などで入るプラグインも含めた実際にインストールされるプラグインの確認です。次へで構いません。
進んだ先の画面は各プラグインのライセンスの使用許諾画面です。ライセンスに問題がなければ、「使用条件の条項に同意します」を選択して完了してください。ちなみにEclipse Common Licenseはオープンソースライセンスの一種で、wikipedia(日本語)の説明がこちらです。
するとダウンロードが始まり、画面をしばらく見てると...
この警告が表示されます。ようは作った人が誰だかを示す電子署名をわざわざ入れてないものを発見したということです。オープンソースではよくあることと割り切れればOKを押してください。ソースレベルで誰がコミットしたものか分からなくなるようなことは滅多にないと思うので、バイナリレベルで電子署名がない=不正なものであることは稀だと思いますが。
そして次は署名はあるけどその署名の証明書が正式な証明機関が発行(?)したものでない、これ信用しますか?という質問です。正式な証明機関は普通無料で証明書を発行しないので、特にオープンソースではそういうケースが多いです。許容できれば全て選択を押してOKしてください。あとは待っているとインストールは終わります。
再始動するか聞かれるので、再始動するを選択してください。
しばらくするとスプラッシュ画像が表示されたのち、またワークスペースを聞かれるのでOKしてください。また待っていると、起動終了します。これでC/C++/Pythonの開発環境として動作可能な状態になります。
もう動作はするのですが、後少しPythonの実行環境を設定しておきます。メニューからウィンドウ>設定を選択してください。
この画面で、左のPydevからインタープリタ-Pythonを選択し、Auto Configを押してください。
するとパスをトラバースして現在の環境から適切な設定をしてくれます。とりあえずOKです。
後はもうOKするだけです。
今後UbuntuのaptからPythonのパッケージを入れた場合も、さっきの画面で一旦除去して再度AutoConfigすることでまた適切な設定になります。
以上でPythonで開発する準備が整いました。
Hello, World!
最後にHello, World!だけしておきます。
メニューからファイル>新規>プロジェクト...を選択して、プロジェクトを作ります。
するとプロジェクトの種類を聞かれるので、PyDevプロジェクトを選択して次へ進みます。
次はプロジェクトの設定を聞かれるので、プロジェクト名をhello、バージョンを2.6(好み)に設定して、完了を押します。
これでPyDev(Python)プロジェクトが作られるのですが、画面がC/C++用の開発画面のままなので、Python用の開発画面に変更するか聞かれます。はい、を選択してください。
この画面(パースペクティブ)がPython開発用の画面です。次はhello.pyファイルを作るため、左のhelloプロジェクトを開いてsrcファルダを右クリックして、新規>Pydevモジュールを選択します。
するとどんなファイルを作るか聞かれるので、パッケージは空欄のまま、名前がhello、テンプレートがモジュール: メインを設定して完了を押します。
すると、選択されたテンプレートを元にhello.pyが作られ、その編集画面が開きます。
後はpassをprint "Hello, World!"に置き換えて保存すれば(Ctrl+Sなど)プログラムは完成します。
そして左からhello.pyを選択した状態から右クリックメニューで実行>Python実行を選択すると...
こんなんでてきます。
その人を表す特徴的な単語
gwibberにあるデータからなんか統計処理できないかと考えてみた。
お題
Twitterで(勝手に)フォローしてる人固有の特徴的な単語上位3つを挙げる
結果
頻度の高い方順に5人抽出しました。
ID | 1 | 2 | 3 |
---|---|---|---|
mitukiii | 金沢 | screen | mitukiii |
repeatedly | gakisp | Andrei | 学歴 |
SubaruG | const | decltype | √ |
ponkotuy | eneloop | mAh | ポンコツ |
littlestone71 | hakone | 丸 | 四 |
なんとなくそういうイメージな人からどうしてそうなったのかよく分からない人までいますが、おおよそ違和感のない感じになっています。
方法は
といった感じ。
以前はこの後にきちゃなくて遅いソースを載せていたのですが、gwibberからのデータが大量でも処理できるよう、データベースに格納するようにしたら、すっかりスパゲッティになってしまいました。とりあえずgithubに移動してあります。
https://github.com/nekomusha/public/tree/hatena20110117/twitter_statistics/src
実行にはPython用O/R mapperであるSQLAlchemyが必要です。
*1:「gwibberでtwitter」id:nekomusha6:20110112:1294826232
*2:「ubuntu & pythonで形態素解析」id:nekomusha6:20110112:1294782745
*3:その人がその単語をつぶやいた回数(TF)と全人数をその単語をつぶやいたことのある人数で割ったもの(IDF)の積