ATNDでTwitter連携を設定している人のTwitterIDを抜き出すスクリプト書いたよ
ATNDがTwitterと連携できるようになりましたね。そこで、イベントの参加者のTwitterIDを抜き出すスクリプト書きましたよ。
object ATNDEventTwitterList { def main( args:Array[String] ) = { args.headOption.foreach { eventId => ATNDApi.event( eventId ) foreach { event => val users = event.users val tmax = users.map{ _.twitterId }.flatten.map{ _.length }.max val fmt = "%6d : %s : %-" + tmax + "s : %s" println( event.title ) users.map { u => fmt format( u.userId, if( u.join ) "参加" else "補欠", u.twitterId.getOrElse("-"), u.nickname ) } foreach { println } } } } }
こんなの作っておいて、eventIdを渡すと...
ozaki@yuroyoro-MacBook $ scala ATNDEventTwitterList 5871 [~/sandbox/.../yuroyoro/atnd] Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8 わかる!JavaVM ― 2時間でわかる?JavaVM入門 4600 : 参加 : yuroyoro : yuroyoro 5038 : 参加 : - : 神速 32447 : 参加 : rinfield : rinfield 22669 : 参加 : - : shinobu.aoki 27977 : 参加 : matobat : matobat 6049 : 参加 : kazunori_279 : kazunori_279 4945 : 参加 : - : Yamashiro0217 ...
こんな感じになるわけです。
ATNDのAPIでは、まだ参加者のTwitterIDを取得することができないので、ユーザーのページのHTMLからTwitterIDをクロールしてます。なので、イベントの参加者数だけリクエストが飛びます...。
これ使ってリマインダ送ったり、補欠から繰り上がったら通知するサービスとかできそうですね。ってかATNDがそのうち実装するか。
JVM勉強会の参加者にmentionsでリマインダ送ろうかと思ったけど、スパム報告されるかもしれないのでまだやってません。
ソースです
yuroyoro's
gist: 508039 — Gist
import java.util.Date import java.text.SimpleDateFormat import java.net.URL import scala.xml._ import scala.xml.parsing.XhtmlParser import scala.io.Source case class User( userId:Int, nickname:String, twitterId:Option[String], join:Boolean = true ) class Event( eventId:String, eventXml:Node ) { lazy val usersXml = XML.load( new URL( "http://api.atnd.org/events/users/?event_id=%s" format eventId )) val sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'+09:00'") def value( tag:String ) = eventXml \ tag text def optionValue( tag:String ) = (eventXml \ tag ).headOption.map{ v => v text }.filter{ _.nonEmpty } def dateValue( tag:String ) = optionValue( tag ) map { d => sdf.parse(d) } def intValue( tag:String ) = optionValue(tag) map { _.toInt } getOrElse(0) def doubleValue( tag:String ) = optionValue(tag) map{ _.toDouble } getOrElse(0.0) val title:String = value("title") val catchs:String = value("catch") val description:String = value("description") val eventUrl:String = value("event-url") val startedAt:Option[Date] = dateValue("started-at") val endedAt:Option[Date] = dateValue("ended-at") val url:String = value("url") val limit:Int = intValue("limit") val address:String = value("address") val place:String = value("place") val lat:Double = doubleValue("lat") val lon:Double = doubleValue("lon") val ownerId:Int = intValue("owner-id") val ownerNickname:String = value("owner-nickname") val accepted:Int = intValue("accepted") val waiting:Int = intValue("waiting") val updatedAt:Option[Date] = dateValue("updated-at") lazy val users: Seq[User] = usersXml \\ "user" map { u => val id = u \ "user-id" text val tid = ATNDApi.twitterId( id.toInt ) filter { _ != "-" } User( id.toInt, u \ "nickname" text, tid, ( u \ "status" text ) == "1" ) } lazy val joins = users.filter{ _.join } lazy val waitings = users.filter{ _.join == false } } object ATNDApi { private def loadEventXml( eventId:String ) = XML.load( new URL("http://api.atnd.org/events/?event_id=%s" format eventId )) \\ "event" headOption def event( eventId:String ):Option[Event] = loadEventXml( eventId ) map { xml => new Event( eventId, xml ) } def twitterId( id:Int):Option[String] = { XhtmlParser( Source.fromURL( new URL("http://atnd.org/users/%s" format id ) )) \\ "dl" filter { dl => (dl \ "dt" text) == "Twitter ID" } filter { dl => (dl \ "dt" text) == "Twitter ID" } map { dl => dl \ "dd" text } headOption } } object ATNDEventTwitterList { def main( args:Array[String] ) = { args.headOption.foreach { eventId => ATNDApi.event( eventId ) foreach { event => val users = event.users val tmax = users.map{ _.twitterId }.flatten.map{ _.length }.max val fmt = "%6d : %s : %-" + tmax + "s : %s" println( event.title ) users.map { u => fmt format( u.userId, if( u.join ) "参加" else "補欠", u.twitterId.getOrElse("-"), u.nickname ) } foreach { println } } } } }