arcanum_jp’s blog

おっさんの日記

Twitter botが作りたい。(Twitter4Jの検索チップ)

Twitter4Jで検索する場合、Queryクラスに条件を入れて、検索して、まだ検索残りがあったら検索して・・・って結構面倒です。こんな感じになると思います。この処理をメソッド化して再利用化したとしても、検索途中で終わらせる場合とか、多様な検索に向いていないので、ちょっと困りもの。かといってコピペは悪と育った世代にはこのコードをアプリケーションに散りばめるなんて・・・

Twitter twitter = ...

int page = 1;
while(true){
  sleep(2000);	// API制限に引っかからないようちょっと待つ

  // 検索
  Query query = new Query("ガンダム");
  query.setPage(page);
  QueryResult qres = twitter.search(query);
  if(qres.getTweets().isEmpty()){
    break;
  }

  // 検索結果を溜め込む
  for (Tweet tweet : qres.getTweets()) {
    ... ここに検索されたツイートの処理
  }
  page++;

}

 で、検索自身を再利用しましょうということで、こんなクラスを作ってみました。

public abstract class TwitterSearch {

  private Query _query;

  public TwitterSearch(Query query){
    _query = query;
  }

  private boolean _isstop;
  public void stop(){
    _isstop = true;
  }

  public void execute(Twitter twitter){

    int page=1;
    _query.setPage(1);	//1ページ開始
    while(true){

      try {
        Thread.sleep(2000);    // API制限に引っかからないようちょっと待つ
        // もう終わりなら終わり(禅問答)
        if(_isstop){
          break;
        }

        // 検索
        QueryResult qres = twitter.search(_query);
        if(qres.getTweets().isEmpty()){
          break;
        }

        // 検索結果を処理してもらう
        for (Tweet tweet : qres.getTweets()) {
          tweet(tweet);
        }
        page++;
        _query.setPage(page);
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }

  }

  public abstract void tweet(Tweet tweet);

}

 例外の処理とか、適当です。使い方は、無名クラスで生成するなりなんなりと・・・

Query query = new Query("ガンダム");
query.setSinceId(DBから引っ張ってきた、最後に検索したツイートのIDとか);
TwitterSearch ts = new TwitterSearch(query){
  public void tweet(Tweet tweet){

    String sql = "INSERT INTO TWEET ...";
    DB.execute(sql);   // ツイートを永続化したり
 
    if(もうおなかいっぱい){
      stop();
    )

  }
};
ts.execute(twitter);

 これで、検索部分を隠蔽化しつつ、検索された1件がイベントとして上がって来るイメージになるし、流用が効くようになりました。