twitter APIの実行回数制限に触れないようにリツイートをまとめる


(追記 2013-07-09)
Twitter API 1.1では以下のような面倒な方法をとる必要はありません。

"retweeted_status"からRT元の情報を取得できます。

検索系APIで取得した情報にはリツイートに関する情報が含まれていないため、ある投稿をRTしたものをひとつにまとめることができません。


そこで、自力で手間ひまかけて下の画像のようにまとめました。



【目次】
  1. 前提 (愚痴)
  2. 自力でリツイートをまとめる
  3. 注意点
  4. まとめ


前提 (愚痴)

そもそも検索系APIリツイート情報も一緒に提供してくれれば、これから行う面倒な作業は必要ありません。
下記が検索系APIからの取得例です。

PHP
$url = "http://search.twitter.com/search.json?q=%23kirumin";
print_r(json_decode(file_get_contents($url), true));


【実行結果】
Array
(
[completed_in] => 0.158
[max_id] => 1.5889220392047E+17
[max_id_str] => 158892203920470016
[next_page] => ?page=2&max_id=158892203920470016&q=%23kirumin
[page] => 1
[query] => %23kirumin
[refresh_url] => ?since_id=158892203920470016&q=%23kirumin
[results] => Array
(
[0] => Array
↓↓↓ ここから、投稿1件分の情報 ↓↓↓
(
[created_at] => Mon, 16 Jan 2012 12:10:34 +0000
[from_user] => sutara_lumpur
[from_user_id] => 6412382
[from_user_id_str] => 6412382
[from_user_name] => すたら
[geo] =>
[id] => 1.5888384396795E+17
[id_str] => 158883843967946753
[iso_language_code] => ja
[metadata] => Array
(
[result_type] => recent
)

[profile_image_url] => http://a0.twimg.com/....jpg
[profile_image_url_https] => https://si0.twimg.com/....jpg
[source] => <a href="http://jigtwi.jp/?p=1" rel="nofollow">jigtwi</a>
[text] => RT @satodashoji: 『雪山にパンダ!?スキー場の名推理!!』の巻。... #kirumin
[to_user] =>
[to_user_id] =>
[to_user_id_str] =>
[to_user_name] =>
)
↑↑↑ ここまで、投稿1件分の情報 ↑↑↑

[1] => Array
(
...
)

)

[results_per_page] => 15
[since_id] => 0
[since_id_str] => 0
)


これが、もし下記のようなら、ほんと助かるのですが…。


Array
(
[completed_in] => 0.158
[max_id] => 1.5889220392047E+17
[max_id_str] => 158892203920470016
[next_page] => ?page=2&max_id=158892203920470016&q=%23kirumin
[page] => 1
[query] => %23kirumin
[refresh_url] => ?since_id=158892203920470016&q=%23kirumin
[results] => Array
(
[0] => Array
↓↓↓ ここから、投稿1件分の情報 ↓↓↓
(
[created_at] => Mon, 16 Jan 2012 12:10:34 +0000
[from_user] => sutara_lumpur
[from_user_id] => 6412382
[from_user_id_str] => 6412382
[from_user_name] => すたら
[geo] =>
[id] => 1.5888384396795E+17
[id_str] => 158883843967946753
[iso_language_code] => ja
[metadata] => Array
(
[result_type] => recent
)

[profile_image_url] => http://a0.twimg.com/....jpg
[profile_image_url_https] => https://si0.twimg.com/....jpg
[source] => <a href="http://jigtwi.jp/?p=1" rel="nofollow">jigtwi</a>
[text] => RT @satodashoji: 『雪山にパンダ!?スキー場の名推理!!』の巻。... #kirumin
[to_user] =>
[to_user_id] =>
[to_user_id_str] =>
[to_user_name] =>
--------------------------------
ほんのちょっと、この情報を付け加えてくれたら…(つД`)
[retweeted_status] => Array
(
[retweet_count] => 1
[id] => 1234
[screen_name] => satodashoji
[profile_image_url] => http://a0.twimg.com/....jpg
[text] => 『雪山にパンダ!?スキー場の名推理!!』の巻。... #kirumin
)
--------------------------------

)
↑↑↑ ここまで、投稿1件分の情報 ↑↑↑

[1] => Array
(
...
)

)

[results_per_page] => 15
[since_id] => 0
[since_id_str] => 0
)


自力でリツイートをまとめる


【追記】2012年1月19日
実際の運用で試した結果、ユーザ情報系のAPIもすぐに実行回数制限に達してしまうようです。


http://api.twitter.com/1/users/show/(ユーザ名).json
ユーザの顔写真の取得には別の方法が必要です。


おおまかな手順は、下記のとおりです。

  1. 検索系APIで投稿を取得する。
  2. 投稿を1件ずつチェックし、公式RTとおぼしきものを抜き出す。
  3. 被RTされたユーザの顔写真を、ユーザ情報系APIで取得する。
  4. 同じ投稿に対する公式RTをまとめる。


ソースコードはこんな感じです。
(大幅に省略しています)


//1. 検索系APIで投稿を取得する。
$url = 'http://search.twitter.com/search.json?q=%23kirumin';
if($status = @file_get_contents($url)){
$status = json_decode($status, true);

//2. 投稿を1件ずつチェックし、公式RTとおぼしきものを抜き出す。
for($i=0; $i<count($status['results']; $i++){
if(preg_match(
'/^RT @([\w_]+): (.*)$/u',
$status['results'][$i]['text'],
$match
)){

//3. 被RTされたユーザの顔写真を、ユーザ情報系APIで取得する。
$escaped_username = rawurlencode($match[1]);
$url2 = "http://api.twitter.com/1/users/show/$escaped_username.json";
if($image = @file_get_contents($url2)){
$image = json_decode($image, true);
$image = $image['profile_image_url'];
}

//4. 同じ投稿に対する公式RTをまとめる。
$retweeted_posts = array(
'id' =>$status['results'][$i]['id'],
'profile_image_url'=>$rt_img,
'from_user' =>$match[1],
'text' =>$match[2],
//公式RTしたユーザの情報
'retweet_users' =>array(array(
'from_user' => $status['results'][$i]['from_user'],
'profile_image_url' => $status['results'][$i]['profile_image_url']
))
);

}
}
}


注意点

上記のコードには、いくつもの欠陥があります。


  1. 本当にそれが公式RTであるのかを確認していない。
  2. 引用と全く同じ投稿文(原文)が本当に存在するのかを確認していない。
  3. 公式RTの原文として保存する際、id番号を原文ではなく公式RTのものを保存している。
  4. 原文の投稿日時、投稿を行ったアプリなどの情報が分からない。


しかし、これらの欠陥は大したことではありません(私のサイトの場合は)。
それよりも何よりも優先すべきなのは、


  1. twitter APIの実行回数制限に触れないようにすること。
  2. ツイートの取得・整形・表示までの所要時間を短くすること。


この2点です。


では、あらためて欠陥への対処を考えていきます。
まず、


本当にそれが公式RTであるのかを確認していない。
引用と全く同じ投稿文(原文)が本当に存在するのかを確認していない。
これは、どうしようもありません(^ ^;)
公式RTとおぼしき投稿のID番号を使って、下記のように、本当に公式RTされたものなのか、誰の、何番の投稿をRTしたのかを調べることもできます。

http://api.twitter.com/1/statuses/show/(投稿ID番号).json
しかし、これを何度も行っていると、twitter APIの実行回数制限に触れてしまいます(-_-;)
ツイート系のAPIは、どうも他の系統と比べて制限が厳しいようです。


ならば、制限が緩い(と思われる)検索系APIで調べてみましょう。


http://search.twitter.com/search.json?q=(本文)%20from:(ユーザ名)";

※『%20』は、半角スペースがURLエンコードされたもの。

しかしこれだと、古いツイートの情報を取得できません。
おそらく、1週間くらい前のものでも、無理です。( ゚д゚)ポカーン
そうなると、結局は前節のコードのように、公式RTと思われるものならチェックせずに使うしかなくなる場合が出てきます。
ならば、いっそのこと全くチェックしない方が処理が速くなります。


では次に


公式RTの原文として保存する際、id番号を原文ではなく公式RTのものを保存している。
これも原文の情報を取得できないために仕方のないことなのですが、特に問題はないと思います。
私が投稿のID番号を使うのは
  1. その投稿をリツイートする。
  2. その投稿に返信する。
この2つの場合です。
そして、私の確かめたところでは、公式RTの投稿ID番号に対してリツイートしたり返信したりした場合は、原文に対してそれを行ったものとみなされるようです。


最後に


原文の投稿日時、投稿を行ったアプリなどの情報が分からない。
別にそんなの知る必要ありませんが、なにか?
…と思ってらっしゃる方がほとんどなのでは (^ ^;)


まとめ

というわけで、自力でリツイートをまとめようとすると、すごく面倒くさいくせに、完全に正しくそれを行うことはできませんorz
是非、検索系APIの取得結果の情報項目の拡充を望みます。
…とはいえ、twitter様のデータベースにおんぶにだっこされている我々利用者(関連サービス制作者)としては、あまり贅沢な注文をしてはいけないのかもしれませんが…。
まあ、一応要望のメールを出してみます (^ ^;)


それにしても、twitterってどんな方法で利益を出してるんでしょうか。
まさか、PC用ページの右上にちっちゃく載せられてる広告バナーだけで成り立ってるわけでもないでしょうし…(-_-;)
ほかのメジャーなサイトにも共通することですが、さっぱり分からない謎です。