記事一覧はこちら

数年前のツイートも出てくるようになったツイッターの検索機能を使う

Twitter Blog: Now showing: Older Tweets in search results つまり、ツイッターのツイート検索で昔のツイートも出てくるようになったよ という事。 APIからは使えないみたいなので、APIを作りました。 ただ、https://twitter.com/cookieが必要だから普通のツイッターアプリと同じようには無理。 検索キーワードはこれが使えるUsing the Twitter Search API | Twitter Developers

使い方は、第一引数に検索キーワード。 第二引数にhttps://twitter.com/のauth_tokenのcookie。ブラウザを開いて各自調べて下さい。正規表現的に

[0-9a-f]{40}
こんな文字列でした。 第三引数は検索タイプ。recentとrelevanceがあってtrueならrecent。 recentにしても日付順全てのツイートが出てくるのは最近一週間だけで、それ以前はrecentもrelevanceも同じようなツイートが返ってきます。 第四引数はmax_id。これで順番に受信する。

検索タイプがrecentで投稿日が一週間以内のツイートは条件にマッチする物が全て取得出来るけど、それ以外は飛び飛びでしか取得出来なかったりと完全ではない。 でもuntilキーワードを付けたりで工夫は出来る。Twitter / Search - 古アニMAX until:2010-11-10…けど完全に取る事は出来ないみたい。インデックスされてないだけでそのうち出来るようになるかな? Twitter / Search - from:jp_trends until:2011-05-31jp_trendsは2011/04/12にアカウントを取って即サービスインしたと思うけど、現時点(2013/02/08 18:05)では検索結果が0件。さてどうなるか。

$max_id=null;
$resultAll=[];
do{
    $results=tweetSearch("フルアニMAX","*****",true,$max_id);
    $resultAll+=$results->results;
    $max_id=$results->since_id;
    print "get ".count($resultAll)." items. ".end($results->results)->created_at." {$max_id}n";
}while(1<count($results->results) );
foreach($resultAll as $result){
    print $result->created_at." ".mb_substr($result->text,0,70,"ASCII")."n";
}
print "total ".count($resultAll)." items.n";
function tweetSearch($keyword,$oauthToken,$isRecent=true,$max_id=null){
    $options = array(
        'http'=>array(
            'method' => "GET",
            'header' => [
               "cookie: auth_token={$oauthToken};",
            ]
        )
    );
    $prams=[];
    $prams["src"]="typd";
    $prams["type"]=$isRecent?"recent":"relevance";
    $prams["include_available_features"]="1";
    $prams["include_entities"]="1";
    if($max_id!==null){
        $prams["max_id"]=$max_id;
    }
    $prams["count"]="100";
    $prams["q"]=$keyword;
    $context = stream_context_create($options);
    $retry=5;
    do{
        $result = @file_get_contents("https://twitter.com/i/search/timeline?".http_build_query($prams), false, $context);
        if($result!=""){
            break;
        }
    }while($retry--);
    $result=json_decode($result);
    $resultItems=explode('<li class="js-stream-item',$result->items_html);
    $results=(object)null;
    $results->results=[];
    $results->since_id="";
    foreach($resultItems as $resultItem){
        $add=(object)null;
        $add->user=(object)null;
        if(!preg_match('{data-item-id="(d+)"}',$resultItem,$match)){continue;}
        $add->id_str=$match[1];
        if(!preg_match('{<p class="js-tweet-text">(.+?)</p>}s',$resultItem,$match)){continue;}
        $add->text=$match[1];
        $add->text=preg_replace_callback('{<a .*?</a>}',function($p){
            $html=$p[0];$return=$html;
            if(preg_match('{data-expanded-url="(.+?)"}',$html,$match)){
                $return=html_entity_decode($match[1]);
            }else if(preg_match('{>(pic.twitter.com/w+)</a>}',$html,$match)){
                $return="http://{$match[1]}";
            }
            return $return;
        },$add->text);
        $add->text=strip_tags($add->text);
        if(!preg_match('{data-time="(d+)"}s',$resultItem,$match)){continue;}
        $add->created_at=date("c",$match[1]);
        if(!preg_match('{data-screen-name="(.*?)"}s',$resultItem,$match)){continue;}
        $add->user->screen_name=$match[1];
        if(!preg_match('{data-name="(.*?)"}s',$resultItem,$match)){continue;}
        $add->user->name=$match[1];
        if(!preg_match('{data-user-id="(.*?)"}s',$resultItem,$match)){continue;}
        $add->user->id_str=$match[1];
        $results->results[$add->id_str]=$add;
        $results->since_id=$add->id_str;
    }
    return $results;
}