Twitter 自動フォロー&リムーブスクリプト in Scala

Twitterbot用に自動フォロー&リムーブを行うスクリプトを書いてみました。
※正確にはスクリプトを書くための便利オブジェクトの定義。

今回は定義したシングルトンオブジェクトをREPL上で:loadして、特定の関数を呼び出すことで実行しています。

言語 -Scala-
ライブラリ -twitter4j- http://twitter4j.org/ja/index.html
参考サイト様 -NI-Lab.'s ヅラッシュドット- http://www.nilab.info/zurazure2/001125.html

実装
import twitter4j._
import twitter4j.http._
import scala.io._
import scala.collection.mutable._

/*
 * MyTwitter
 *
 */
object MyTwitter{

    /*
     * First, regist your app at https://twitter.com/apps/new
     *
     */
    def authorizeApplication(){
        val consumerKey = readLine("Input consumerKey...>")
        val consumerSecret = readLine("Input consumerSecret...>")

        val factory = new TwitterFactory
        val twitter = factory.getOAuthAuthorizedInstance(consumerKey, consumerSecret)
        val requestToken = twitter.getOAuthRequestToken

        println(requestToken.getAuthorizationURL)
        println("Access this URL and authorize your app, then you see a PIN-CODE.")
        val pin = readLine("Input PIN-CODE...>")

        var accessToken: AccessToken = null
        if(pin.length > 0){
               accessToken = twitter.getOAuthAccessToken(requestToken, pin)
        } else {
               accessToken = twitter.getOAuthAccessToken
        }

        val userId = twitter.verifyCredentials.getId
        val token = accessToken.getToken
        val tokenSecret = accessToken.getTokenSecret
        println("****************************************************")
        println("UserId = " + userId)
        println("Token = " + token)
        println("TokenSecret = " + tokenSecret)
    }

    /*
     * Get a twitter instance
     *
     */
    def getTwitterInstance(fileName: String): Twitter = {
        val info = getTokenFromFile(fileName)
        val factory = new TwitterFactory
        val accessToken = new AccessToken(info._4, info._5)
        factory.getOAuthAuthorizedInstance(info._1, info._2, accessToken)
    }

    def getTokenFromFile(fileName: String): (String, String, String, String, String) = {
         println(fileName)
        try{
            val source = Source.fromFile(fileName)
            val lines = source.getLines.toList
            lines match {
              case List(consumerKey, consumerSecret, userId, token, tokenSecret)
                  => (consumerKey, consumerSecret, userId, token, tokenSecret)
              case _ => null
            }
        } catch {
            case _ => null
        }
    }

    /*
     * Balance following and followers
     *
     */
    def balanceFriends(account: String){
        val twitter = MyTwitter.getTwitterInstance(account)
        val followers = twitter.getFollowersIDs.getIDs
        val friends = twitter.getFriendsIDs.getIDs
        val outgoings = twitter.getOutgoingFriendships(-1).getIDs
        println("following: " + friends.length + " / follower: " + followers.length)

        var notFollowList = new ListBuffer[Int]
        // フォロワーのうち未フォローのユーザを抽出
        followers.foreach(follower => if(false == friends.contains(follower)
          && false == outgoings.contains(follower)) notFollowList += follower)
        // 未フォローのユーザをフォロー
        notFollowList.foreach(notFollow => createFriend(twitter, notFollow))
        var onlyFollowList = new ListBuffer[Int]
        // 片思いのユーザを抽出
        friends.foreach(friend => if(false == followers.contains(friend)
          || outgoings.contains(friend)) onlyFollowList += friend)
        // 片思いのユーザをリムーブ
        onlyFollowList.foreach(onlyFollow => destroyFriend(twitter, onlyFollow))
    }

    def createFriend(twitter: Twitter, notFollow: Int){
        try{
                val user = twitter.createFriendship(notFollow)
                println("follow " + user.getScreenName)
                Thread.sleep(INTERVAL)
        } catch {
                case _ => println("error occured while following - " + notFollow)
        }
    }

    def destroyFriend(twitter: Twitter, onlyFollow: Int){
        try{
                val user = twitter.destroyFriendship(onlyFollow);
                println("remove " + user.getScreenName);
                Thread.sleep(INTERVAL)
        } catch {
                case _ => println("error occured while removing - " + onlyFollow)
        }
    }

    val INTERVAL = 10000L
}
実行してみる

scala> :load .\MyTwitter.scala

import twitter4j._
import twitter4j.http._
import scala.io._
import scala.collection.mutable._
defined module MyTwitter

事前準備:OAuth認証トークンの取得
既に取得済みならここは不要

scala> MyTwitter.authorizeApplication

Input consumerKey...>
Input consumerSecret...>
[Sun Sep 05 11:16:34 JST 2010]Will
use class twitter4j.internal.logging.StdOutLoggerFactory as logging factory.
[Sun Sep 05 11:16:34 JST 2010]Will use twitter4j.internal.http.HttpClientImpl as
 HttpClient implementation.
http://api.twitter.com/oauth/authorize?oauth_token=hogehoge
Access this URL and authorize your app, then you see a PIN-CODE.
Input PIN-CODE...>
****************************************************
UserId = hoge
Token = foo
TokenSecret = bar

(ここでconsumerKey, consumerSecret, userId, token, tokenSecretをこの順番で一行ごとにファイル保存
 ※まだ自動化してない……)

scala> MyTwitter.balanceFriends("ファイル名")

follow hoge
follow hogehoge
remove foo
remove bar
remove foobar

最近、Scalaを始めて入門書を読み終えたので文法に慣れるために早速書いてみました。
Javaに比べてかなりシンプルに書けますね。
特に balanceFriends() の実装。クロージャを使ったforeach関数の書き方はJavaにはなくて新鮮です。


ソースはgithubにも上げています。
http://github.com/noire722/scala_scripts/blob/master/MyTwitter.scala
ところで、コンソールの出力内容をはてダでうまく表示するにはどうすればいいんだろう。
コード表記を使ってるので一部の単語がハイライトされている…