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件がイベントとして上がって来るイメージになるし、流用が効くようになりました。