Twitterの最近のブログ記事

twitterボットの開発中にできた要らないポストをまとめて削除する方法。


import simplejson
import twitter

api = twitter.Api(username='foo', password='bar')
timeline = api.GetFriendsTimeline()
for t in timeline:
    status = api.DestroyStatus(t.id)










結構便利。
詳しくはGoogle Codeか、API仕様を。

twitter用のボット"twnvls"を書いてみた。
http://twitter.com/twnvls

これはtwitter上でリレー小説をつくるというもので、
投稿者が@twnvls宛にポストした内容を拾って
twnvls名義でポストする。
(当然オリジナルの投稿者もわかるようにする)

一日分のポストはLoudTwitterでまとめて
はてなダイアリーに残す。

初めたばかりなのでまだポストは全然ないが^^;
まぁゆるゆると見守って行きましょうかねと。


作り的には、丁度今GAEでPythonを使ってるので
Python用のtwitterモジュールを使用した。
このモジュールを使うにはsimplejsonも必要。

使い方はいたって簡単。

import simplejson
import twitter

api = twitter.Api(username='foo', password='bar')
replies = api.GetReplies()








これで'foo'宛のリプライが取得できる。
タイムラインを取得したければ、

user_timeline = api.GetUserTimeline()
public_timeline = api.GetPublicTimeline()





とやればよい。

気をつけないといけないのは
GetReplyメソッドでは新しいリプライから順に取得されること。
今回は古い順に処理したいのでソートしたいが、
apiには取得順を変更するインタフェースはないので
アプリ側で対処する必要がある。

Pythonでは辞書型リスト(いわゆる連想配列/Perlで言うところのハッシュ)を
スタックとして使えるので、今回はそれを使うことにする。

stack = []
for r in replies:
    p = []
    p.append(r.id)
    p.append(r.user.GetScreenName())
    p.append(r.text)
    stack.append(p)











これでstackには新>旧の順で格納される。
ポストする時にはstackからpopすれば旧>新の順で取り出せる。

MAX_CHAR = 140    # twitterの文字数制限
i = 0
length = len(stack)
while i < length:
    s = stack.pop()
    id = s[0]
    user = s[1]
    text = s[2][len('@foo'):].lstrip()    # リプライの先頭にある"@foo"と文頭のスペースを削除  

    postuser = ' [@' + user + ']'
    posttext = text[0:MAX_CHAR-len(postuser)] + postuser    # MAX_CHAR内で収まるよう成形

    status = api.PostUpdate(posttext)
    i = i + 1



















基本的にはこれでできる。

あとはGetReplyメソッドがその時点の最新20件を返すので
同じリプライを二重投稿してしまう可能性があり、それを防止しないとならない。

やり方はいろいろあるだろうが、
今回はPostUpdateした時点でid等をアーカイブしておき(これを便宜上アーカイブファイルと呼ぶ)、
GetReplyした時にアーカイブファイルと突き合わせ、
アーカイブ内にあれば既に投稿済みと判断してスキップすることにした。

apiを使ってチェックする方法もあるが、
twitterのapi制限にひっかかりそうだし、twitter側にも負荷をかけるので今回はやめた。

アーカイブファイルが大きくなるとレスポンスが悪化する恐れがあるが、
アーカイブを整理するなどして対策はできるだろうと。


と、言う訳で完成版がこれ。


# coding:utf-8

import sys
import os
import simplejson
import twitter

max_char = 140  # Max character length of twitter api

arcfilename = ".twnvls_archive"
try:
  arcpath = os.environ["TWNVLS_ARCHIVE_DIR"] + arcfilename
except:
  arcpath = os.path.join(os.path.dirname(__file__),arcfilename)

# Open archive file
try:
  fa = open(arcpath, "a+")
  farc = fa.read()  # Once read all of archive file
except:
  sys.stderr.write("IOError:File %s can't open" % arcpath)
  sys.exit()

# Constract twitter api instance
USERNAME = "username"
PASSWORD = "password"
api = twitter.Api(username=USERNAME, password=PASSWORD)

# Get replies
try:
  replies = api.GetReplies()
except:
  sys.stderr.write("TwitterApiError:User %s can't get replies" % USERNAME)
  sys.exit()
  

# Make stack(list)
# NOTE : replies is sorted from newer to older.
#        So, to post twitter, 1st,Make stack. 2nd,Pop from stack.
stack = []
for r in replies:
  try:
    # Skip already posted replies (by checking archive file)
    farc.index("%s %s" % (r.id, r.created_at_in_seconds))
    continue
  except:
    pass

  p = []
  p.append(r.id)
  p.append(r.created_at_in_seconds)
  p.append(r.created_at)  
  p.append(r.user.GetScreenName())
  p.append(r.text)
  stack.append(p)


# Post twitter
i = 0
length = len(stack)
while i < length:
  s = stack.pop()
  id = s[0]
  created_at_in_seconds = s[1]
  created_at = s[2]
  user = s[3]
  text = s[4][len("@"+USERNAME):].lstrip()  # Delete reply name "@~" & left space

  postuser = " [@" + user + "]"
  posttext = text[0:max_char-len(postuser)] + postuser

  status = api.PostUpdate(posttext)
  # Add to archive file
  arctext = "%s %s %s %s\n" % (id, created_at_in_seconds, created_at, user)
  fa.write(arctext)	

  i = i + 1


fa.close()






















今のところは動いてるみたい^^;
今後は自動フォロー機能でも追加しようかな。

twitter をコマンドラインからも使おうと思ったら
一番早いのは公式にもあるようにcurlを使う事だ。

これなら(少なくともOSX.5では)何もインストールする必要はない。
しかし結果が全てXMLで表示される(というかRSSを表示してるだけ)
のでターミナルだと見づらい。
シェルスクリプト書いXMLパーサかますとかやってもいいけど面倒くさい。
後々の使い道は広そうだけど・・・。

そういうのはその内やるとして、もう少し手軽に使えて結果が見やすいのがいい、
と思って探したら perl で書かれたものが見つかったので使ってみる。

準備としてまずNet::Twitterモジュールをインストールする。

$ sudo perl -MCPAN -e shell
CPAN> install Net::Twitter 




次に$HOMEに.twitterというファイルを作り、
YAML形式でユーザ名とパスワードを記述する。
パーミッションは0600にする。
スクリプトを適当なディレクトリに配置したら実行。

$ twitter.pl public_timeline
RSS_AFP: Obama calls for urgent action on economic crisis http:\/\/tinyurl.com\/5zcdpq
でちゅのば: ホッティーおちつくわー
ドジっこmine: @quoggenzockerおお、お疲れ様ですー。
Chris Daniel: Awake. Trying to decide what to do today.
ユッキラキラ☆: @pgo 8つあります。
jordimolinera: Ei... bon dia!
kanatam: 帰宅して晩御飯中。今日はお惣菜。コロッケ買ってきたら、黒豆コロッケだった・・・豆いらねー!甘い。



 







これだと表示されるのがユーザ名と発言内容だけなので見やすい。
勿論ポストもできる。

ただし日本語等の非英語文字が化ける。
調べてみると私の環境には JSON 関係がインストールされていなかった。
なので JSON(と JSON::PP と JSON::XS)を CPAN でインストールする。

$ sudo perl -MCPAN -e shell
CPAN> install JSON
CPAN> install JSON::PP
CPAN> install JSON::XS






モジュールをインストールしたら再び実行。

$ twitter.pl public_timeline
moi: 这些东西,这些被认定为真实的东西真的存在(或存在过)吗?几十亿人,几百年,真有几个人真就去调查了解过了?还不是传扬出来的么?但是人人皆信了。
Dawn News: Eight killed, 10 injured in India blast: 
Saturday, 08 Nov, LUCKNOW: At least eight people were killed .. http://twurl.nl/heefm2
OnYourWeb_net: http://OnYourWeb.net Drug & Alcohol Recovery Club. Relapse Prevention & Sober L.. http://bit.ly/Wu2x
lpggass: BOP 頑張ってるなぁ、パーレィはいらんけどデロリアンは触ってみたいのぅ。
k_rion: アニメ見るたびに入江がかっこよくなっているのは何故?











文字化けは直った。
これならシェルで色々やってる時にちょっとTL見たりポストしたりできる。
いちいちブラウザに切り替えなくても済むのも楽。

先のcurlもそうだけど、使い方次第で色々応用が効きそうだ。