2009年9月28日月曜日

NetWalkerでPythonでtwitterのつぶやきを取得

先日せっかくtwitterを始めたんですが、どうもtwitterのつぶやきは古くなると参照できなくなるらしい。独り言マニアの私としてはこれは非常に残念だ。やっぱりITならではの利点を生かして、リアルの独り言と差別化を図りたい。
と、そこでtwitterからPythonで独り言(いや、ちがった)つぶやきをテキストに落とすことにしました。
NetWalkerにはPythonは最初から入っていて、さらにPython専用開発環境(要は専用エディタ)IDLEも「追加と削除」で入ります。

プログラミングは当然NetWalkerで行います。閑散とした日曜郊外下り線電車の中で電子辞書風のデバイスいじってる私が、まさかPythonでプログラミングしてるとは思うまい。そんでふっと目を上げると前に座ってるお嬢さんと目があったんですが、何かすごい目を輝かせてこっち見てるんですよ。TV見てないのでわかりませんがNetWalkerってCMとか宣伝してるのか?若い人はNetWalker買うといいと思いますよ。

内容に入ります
Twitter APIの呼び出しには既に便利なモジュールがあるらしいのですが、さしあたりNetWalker買ったばかりで「GUIの追加と削除以外では何もインストールしたくない」ので、バッテリーインクルードだけで済ます事にします。実は、会社でも(仕事は.NET)「インターネット上のライブラリとか使わないで標準のクラスでやれ!(いや、標準のクラスで出来ると思いますよ)」とか「Googleしてコピペばっかりしてないでプログラミング×××とか書籍みろ!(いや、この本に出てるので読むと良いと思いますよ。)」とか言って嫌われています。


作成したtwittertest.pyは下の方に載せますが、使い方は以下の例の通りです。
twittertest.py test.txtで、最新20件のステータスを取得してtest.txtに出力します。一件の投稿の事をステータスって言うんだけど知ってた?
twittertest.py test.txt 3 で、1~3ページ。20件×3=60件出力します。セッション無いので新規投稿があると途中でズレると思いますが、新規投稿で追い出されると次ページに送られるだろうから欠落でなく重複になるはず!
twittertest.py test.txt 20 21 で、20~21ページを出力します。過去のデータ取得用のつもりでしたが日時指定しないと今月位しか取れない様です
出力項目はソースを見て戴いた通りですが、タブ区切りで以下の通りです。
行番号 単にデバッグのため付けた
ステータスID このIDで投稿へのリンク作れたと思う 多分
投稿者
日時 勝手に東京ローカル時間に変換済み
内容


さて、私と同様Python素人で、クラスとか細かいことはいいんだよ!サクッと接続の仕方だけ知りたいんだよ!
っていうお客様がいらっしゃるといけませんので、接続部分など抜き出して説明します。

接続部分のコード


user='XXXX'
password='XXXX'

pm=urllib2.HTTPPasswordMgrWithDefaultRealm()
pm.add_password(None,'twitter.com',user,password)
auth=urllib2.HTTPBasicAuthHandler(pm)
opener=urllib2.build_opener(auth)
urllib2.install_opener(opener)
r=urllib2.urlopen("http://twitter.com/statuses/friends_timeline.xml?page=1")
s=r.read()


注:ソースの右側が切れていますがコピーペーストすればちゃんと出る様です

このコードで、
フレンドタイムライン(ホーム画面で出る奴)を最新20件xml形式の文字列で変数sに取得できます。
xmlでなくrssやjsonがいいと言う人はURL末尾の.xmlを.rssや.jsonにすればオッケーです。
ポイントはadd_passwordメソッドですが、
引数1:realm ホントはサーバーがhttpヘッダーで「アクセスするにはこのレルムの認証が必要」と教えてくれて、それを指定するらしいが、Noneでデフォルトになると思われます。
引数2:hostなんですが、twitter.com指定しないと認証エラーになります。意味的にはレルムと同様認証領域を示すためなのか?わからん。
引数3 引数4 ユーザー パスワードです
なお、公式リファレンスの

auth=urllib2.HTTPBasicAuthHandler()
auth.add_password(None,'twitter.com',user,password)
opener=urllib2.build_opener(auth)

だと、認証エラーが出るですよ。こっちはレルムとかちゃんと処理しないとあかんのかも。

それではスクリプト全文です。
Windowsしかわからんという人のために先に使用例説明すると、
  1. 例えばホームフォルダにpyフォルダを作成する(/home/ユーザーID/pyですな)
  2. gedit(付属のテキストエディタ)にソースコードを貼り付けて、pyフォルダにtwittertest.py エンコードutf-8で保存
  3. 端末(コマンドプロンプトですな)でpyフォルダに移動する(cdコマンドは同じです)
  4. chmod 777 twittertest.pyで読み書き実行誰でもOKにする(こまけぇ事はいいんだよ!)
  5. ./twittertest.py test.txtで実行する


追記です2009年10月24日 NetWalkerでPythonでtwitterのつぶやきを取得の補足に件数が多くて失敗する場合の補足情報を書きましたので併せてご覧下さい。
追記ここまで



#!/usr/bin/python
# -*- coding: utf-8 -*-
import urllib2
import xml.etree.ElementTree as ET
import StringIO
import email.utils
import time
import sys
import codecs

#twitterのユーザーIDtパスワード
user='XXXX'
password='XXXX'
host="twitter.com"

def main():
n1=1
n2=1
argv=sys.argv
argc=len(argv)
if argc<2:
print 'usage:'+argv[0]+' outputfile'
print 'usage:'+argv[0]+' outputfile PageTo'
print 'usage:'+argv[0]+' outputfile PageFrom PageTo'
quit()
elif argc==4:
n1=int(argv[2])
n2=int(argv[3])
elif argc==3:
n2=int(argv[2])
outputfile=argv[1]

pm=urllib2.HTTPPasswordMgrWithDefaultRealm()
pm.add_password(None,host,user,password)
auth=urllib2.HTTPBasicAuthHandler(pm)
opener=urllib2.build_opener(auth)
urllib2.install_opener(opener)
lt=[]
for i in range(n1,n2+1):
r=urllib2.urlopen('http://'+host+'/statuses/friends_timeline.xml?page='+str(i))
s=r.read()
lt2=Status.parse(s)
if len(lt2)==0:
break
lt.extend(lt2)

f=codecs.open(outputfile,'w','utf-8')
ln=1
for r in lt:
f.write( str(ln)+"\t"+r.statusid+"\t"\
+r.screenname+"\t"+time.asctime(r.localdate)\
+"\t"+r.text+"\n")
ln+=1
f.close()

class Status:
@classmethod
def parse(cls,s):
lt=[]
so=StringIO.StringIO(s)
et=ET.parse(so)
root=et.getroot()
items=root.findall('./status')
for item in items:
r=Status()
r.createdate=item.find('./created_at').text
r.statusid=item.find('./id').text
r.text=item.find('./text').text
r.source=item.find('./source').text
r.userid=item.find('./user/id').text
r.name=item.find('./user/name').text
r.screenname=item.find('./user/screen_name').text
r.location=item.find('./user/location').text
r.description=item.find('./user/description').text
r.profileimageurl=item.find('./user/profile_image_url').text
r.url=item.find('./user/url').text
r.protected=item.find('./user/protected').text

#convert japan local time
edate=email.utils.parsedate(r.createdate)
l=list(edate)
l.insert(9,+9)
edate=tuple(l)
date=email.utils.mktime_tz(edate)
r.localdate=time.localtime(date) #japan local time
r.gmdate=time.gmtime(date) #GMT time

lt.append(r)
return lt

main()



注:ソースの右側が切れていますがコピーペーストすればちゃんと出る様です

0 件のコメント:

コメントを投稿