twitter で 60 日以上発言が無い人を remove する - Djangoへの片思い日記
僕自身はFollowはまだ200人弱で、全然制限に引っかからないので困らないのだけど、面白そうなので自分でも書いてみる。
まずはAPIの選定。
http://watcher.moe-nifty.com/memo/docs/twitterAPI.txt
自分がフォローしているユーザーを拾うにはこれしかなさそう。
friends 自分の friend の一覧を(各 friend の最新ステータス付きで)取得する 引数 id を指定すれば、その id のユーザの friend の一覧を取得できる ただし、この API で取得できるデータは最大100件(100人分)である URL: http://twitter.com/statuses/friends.format (format は xml, json のうちのいずれかを指定)
100件以上の場合はpage指定して分けるしかない。
page=ページ番号 (オプション) (1ページを100件とみなしたときの)ページ番号を指定することで、指定ユーザの friend の一覧を100件単位で取得する 例: http://twitter.com/statuses/friends.xml?page=2 API実行時点で101件目から200件目に相当する(自分の)friend の一覧を XML 形式で取得する
とりあえず試しに取ってみる。
$ perl -MLWP::Simple -le 'getprint "http://twitter.com/statuses/friends.json?id=sugyan"' [{"following":false,"verified":false,"description":"...
たくさん出てきた。BASIC認証は必要ないらしい。これを使ってワンライナーで色々やってみよう。
まず、何度も色々ためしているとあっという間にAPI制限に引っかかってしまうので、一度データをローカルに保存してそれを使う。
$ wget "http://twitter.com/statuses/friends.json?id=sugyan" $ mv friends.json\?id=sugyan friends.json $ ls -l friends.json -rw-r--r-- 1 sugyan staff 134252 6 29 22:11 friends.json
というわけで、まずはJSONの解析。JSONモジュールを使う。
$ perl -MJSON -le 'print from_json <>' < friends.json ARRAY(0x8104c8) $ perl -MJSON -le 'print scalar @{from_json <>}' < friends.json 100
ちゃんと100件のデータが詰まっているらしい。
$ perl -MJSON -le 'print for @{from_json <>}' < friends.json HASH(0x8192d8) HASH(0x810738) HASH(0x84a920) ...
中身はハッシュのリファレンス。とりあえず1件だけ取り出して中身を見てみよう。Data::Dumperで覗いてみる。
$ perl -MJSON -MData::Dumper -le 'print Dumper shift @{from_json <>}' < friends.json $VAR1 = { 'friends_count' => 91, 'profile_background_tile' => bless( do{\(my $o = 0)}, 'JSON::XS::Boolean' ), 'status' => { 'source' => '<a href="http://d.hatena.ne.jp/Kiri_Feather/20071121">Tween</a>', 'favorited' => $VAR1->{'profile_background_tile'}, 'truncated' => $VAR1->{'profile_background_tile'}, 'created_at' => 'Mon Jun 29 10:04:43 +0000 2009', ...
情報大杉。。。ハッシュのキーだけに絞ろう。
perl -MJSON -le 'print for sort keys %{shift @{from_json <>}}' < friends.json created_at description favourites_count followers_count following friends_count id location name notifications profile_background_color profile_background_image_url profile_background_tile profile_image_url profile_link_color profile_sidebar_border_color profile_sidebar_fill_color profile_text_color protected screen_name status statuses_count time_zone url utc_offset verified
全部のrefを取ってみるとわかるけど、"status"に対応するvalueはさらにハッシュになっている。
$ perl -MJSON -le 'print for sort keys %{shift(@{from_json <>})->{status}}' < friends.json created_at favorited id in_reply_to_screen_name in_reply_to_status_id in_reply_to_user_id source text truncated
色々調べてみるとわかるけど、
$ perl -MJSON -le 'print shift(@{from_json <>})->{screen_name}' < friends.json daiki_kameya $ perl -MJSON -le 'print shift(@{from_json <>})->{status}->{created_at}' < friends.json Mon Jun 29 10:04:43 +0000 2009
というカンジで、自分がフォローしているヒトのidと最終POST日時を知ることができる。
取得した100件全員の最終POST日時を一覧表示したければ、
$ perl -MJSON -le 'print "$_->{status}->{created_at}: $_->{screen_name}" for @{from_json <>}' < friends.json Mon Jun 29 10:04:43 +0000 2009: daiki_kameya Mon Jun 29 00:06:52 +0000 2009: sakaik Mon Jun 29 13:06:54 +0000 2009: tsuka Mon Jun 29 12:13:29 +0000 2009: shohu33 Mon Jun 29 10:39:43 +0000 2009: haru860 Mon Jun 29 13:03:32 +0000 2009: tenja Mon Jun 29 11:45:47 +0000 2009: dameninngenn Mon Jun 29 13:07:59 +0000 2009: ksorano Mon Jun 29 01:50:56 +0000 2009: omega2 Sun Jun 28 21:26:31 +0000 2009: gunjisatoshi ...
とやることができる。
さて、しかしこの"created_at"、この形式の文字列だとどうにも困る。
Date::Parseモジュールを使うとepoch秒に置き換えることができる。
$ perl -MJSON -MDate::Parse -le 'print str2time($_->{status}->{created_at}) for @{from_json <>}' < friends.json 1246269883 1246234012 1246280814 1246277609 1246271983 ...
ということは、取得した100件のfriendsを最新POST順に並び替えることもできるわけで。
$ perl -MJSON -MDate::Parse -le 'print join ": ", @$_ for sort { $b->[0] <=> $a->[0] } map [str2time($_->{status}->{created_at}), $_->{screen_name}], @{from_json <>}' < friends.json 1246281071: furuhouse 1246280896: Yoshikazu 1246280879: ksorano 1246280872: voluntas 1246280836: tsuyoshikawa 1246280815: mdaisuke 1246280814: tsuka 1246280752: jugyo 1246280727: otenki_bot 1246280717: kekoyana ...
ちょっと長いけどシュワルツ変換を使って最新POST日時順に並べ替えて表示してみた。
http://perl-mongers.org/2008/05/schwartzian_transform_and_orcish_maneuver.html
…というわけで、「60日以上発言が無い人」というのは上記のようなsortをする必要も無く、ただgrepでフィルタリングすれば良いだけ。
例えば最近24時間でPOSTしていないヒトを列挙するのであれば
$ perl -MJSON -MDate::Parse -le 'print $_->{screen_name} for grep { str2time($_->{status}->{created_at}) < time - 60*60*24 } @{from_json <>}' < friends.json yapcasia KAZUTO1967 katsumic willpon kazukichop ...
というカンジでできる。60*60*24*60と数字を変えれば「60日以上発言が無い人」というフィルタリングが可能。
さて、ここまで出来たところで、ページングにチャレンジ。
実際にAPIからデータを取得して上記までのことをやろうとすると、LWP::Simpleモジュールを使用して以下のようになる。
$ perl -MJSON -MDate::Parse -MLWP::Simple -le 'print $_->{screen_name} for grep { str2time($_->{status}->{created_at}) < time - 60*60*24 } @{from_json get "http://twitter.com/statuses/friends.json?id=sugyan"}'
ここに、終了条件を加えてwhileループを回してやりたい。
終了する条件は、取得されたデータが0件になること。イメージとしてはこんなカンジ。
$ perl -MJSON -MLWP::Simple -le 'sleep(60), print $n while @{from_json get "http://twitter.com/statuses/friends.json?id=sugyan&page=".$n++}'
ということでwhile文を回しつつ60日以上発言が無い人を列挙していく。
while文を使っているとprint部分でforを使えないのでmapで代用する。
$ perl -MJSON -MDate::Parse -MLWP::Simple -le 'map { sleep(60); print $_->{screen_name} } grep { str2time($_->{status}->{created_at}) < time - 60*60*24*60 } @a while (@a=@{from_json get "http://twitter.com/statuses/friends.json?id=sugyan&page=".++$n})'
完成!!
…って、ここまで書いてようやく気付いたけど、これだとBASIC認証してないから非公開のユーザーについては判定できないや。
もしかすると60日以上前まで公開していてそこから非公開にしたユーザーが含まれてしまうかも。
ちゃんとBASIC認証してタイムラインを取得するには…
$ perl -MJSON -MDate::Parse -MLWP::UserAgent -le 'map { sleep(60); print $_->{screen_name} } grep { str2time($_->{status}->{created_at}) < time - 60*60*24*60 } @a while (@a=@{($r=HTTP::Request->new(GET=>"http://twitter.com/statuses/friends.json?id=sugyan&page=".++$n))->authorization_basic(@ARGV), from_json(LWP::UserAgent->new->request($r)->content)})' sugyan ********
こうか!?
あとは出力を使ってNet::Twitterとかでremoveすればいいと思います。もう疲れたw