Twitter検索用 IRC Bot
$ scala -version
2.9.0.RC1
使用ライブラリ
PircBot 1.5.0
http://www.jibble.org/pircbot.php
HatoChanBot.scala
import scala.xml._ import java.io._ import org.jibble.pircbot._ object HatoChanBot { def main(args: Array[String]) { val bot = new HatoChan bot.init bot.setAlreadyPosted(load(Conf.DAT_FILE_NAME)) while (true) { save(Conf.DAT_FILE_NAME, bot.crawl) Thread.sleep(Conf.CRAWL_INTERVAL) } } // deserialize def load(fileName: String): List[String] = { try { val dat = new ObjectInputStream(new FileInputStream(fileName)) val posted = dat.readObject.asInstanceOf[List[String]] dat.close return posted } catch { case _ => Nil } } // serialize def save(fileName: String, posted: List[String]) { val dat = new ObjectOutputStream(new FileOutputStream(fileName)) dat.writeObject(posted) dat.close } } class HatoChanBot(var alreadyPosted: List[String] = Nil) extends PircBot { def init() { this.setName(Conf.IRC_NICK) this.setLogin(Conf.IRC_NICK) this.setVersion(Conf.IRC_MAIL) this.setMessageDelay(Conf.IRC_MSG_DELAY); this.setEncoding(Conf.IRC_ENCODING) this.connect(Conf.IRC_HOST, Conf.IRC_PORT) this.joinChannel(Conf.IRC_CHANNEL) } def crawl(): List[String] = { val src = io.Source.fromURL(Conf.URL, Conf.IRC_ENCODING).getLines.mkString val xml = XML.loadString(src) val entries = xml \\ "entry" for (entry <- entries) { val twitterId = "@" + (entry \ "author" \ "name").text.replaceAll("""\s\(.*\)""", "") val content = (entry \ "content").text.replaceAll("""<.*?>""", "") val msg = twitterId + ": " + content if (alreadyPosted.contains(msg) == false) { this.sendNotice(Conf.IRC_CHANNEL, msg) this.alreadyPosted :::= List(msg) } } return this.alreadyPosted } def setAlreadyPosted(posted: List[String]) { this.alreadyPosted = posted } }
IRCにSend済みの発言Listをシリアライズして保持&チェックすることで、IRCで同じ内容の発言をすることを防いでます。
クロール対象は http://search.twitter.com/ の検索結果ページの XML-Feed。
XMLの解析には id:yuroyoro さんの下の記事を参考にしました。
ScalaでWebAPIをたたいてXMLを処理するための定型パターンのまとめ 〜ゆろよろ日記
http://d.hatena.ne.jp/yuroyoro/20091027/1256611681
Conf.scala
object Conf{ val URL = "http://search.twitter.com/search.atom?q=iPad2" val DAT_FILE_NAME = "posted.dat" val CRAWL_INTERVAL = 1000 * 60 * 3 // 逮捕されないように常識的な値を設定 val IRC_NICK = "hato_chan" val IRC_MAIL = "hato_chan@mail.poppo.jp" val IRC_HOST = "foo.bar.ne.jp" val IRC_PORT = 6660 val IRC_CHANNEL = "#hatochan" val IRC_MSG_DELAY = 5000 // IRCサーバにkickされないように常識ry val IRC_ENCODING = "UTF-8" }
設定用シングルトン
(後で普通のテキストの設定ファイルにします…)