follow、被followの比率を円グラフで表示
Twitter APIで戻ってくるXMLをパーズして、それから何がしかの情報を取ってくる場合、もしかしてSAXを使うべきじゃないだろうかと思った。XPathとかって、ある階層のノードをまとめて引っ張ってきてイテレートするにはいいけど、例えばuser/nameとuser/idと別々にイテレートするとか、なんか変。そもそもuserのプロパティに欠けがあったら対応が取れなくなるし。といって、userごとにまた処理を分けるのも、めんどい。
単にXMLで書かれたデータをオブジェクトにマップするだけなら、頭から順にタグのイベントを発生させてくれるだけのSAXのほうがシンプル。
で、SAXで書いてみた。実行結果はHTMLで吐いて、円グラフをGoogle Chart APIで描く。円グラフはfollow数と、被follow数の比率を示している。follow、被followの割合って、その人がTwitter上でどういう存在かを示す1つの指標になると思って可視化してみたかった。ボット系が極端に被follow率が高いとか、有名な人が被follow率が高めというのは予想通りだったけど、両者が均等という人が多いのが意外だった。みんなfollow返ししてるのね。
HTML生成にnokogiri使えよって感じ。そもそも結果全体をtableで囲むとかもないわ。ほんとは流行のcanvasを使ってみたかったけど、Googleのサービスがやたら反応が速いし手軽だったので、これでいいじゃんって感じ。
require 'open-uri' require 'nokogiri' class User attr_accessor :username, :followers, :friends, :image_url attr_reader :ratio def initialize @username = "" @followers = 0 @friends = 0 @image_url = "" @ratio = 0 end def calc_ratio unless @friends == 0 @ratio = @followers.to_f / @friends.to_f else @ratio = 0 # instead of infinity end end end class Piechart @@api = "http://chart.apis.google.com/chart?cht=p3&chd=t:" def initialize(a, b) total = a + b @a = sprintf("%.2f", (100 * (a.to_f / total))) @b = sprintf("%.2f", (100 * (b.to_f / total))) end def create_query query = @@api+@a+","+@b+"&chs=250x100&chl=Following|Followed" query += "&chco=ff0000|0000ff" # color query = "<img src=\"" + query + "\"/>" end end class MyDocument < Nokogiri::XML::SAX::Document def initialize @users = [] @str = "" @u = User.new end def start_element(name, attributes = []) if name == "user" @u = User.new end end def characters(str) @str = str end def end_element(name, attributes = []) case name when "name" then @u.username = @str when "profile_image_url" then @u.image_url = @str when "followers_count" then @u.followers = @str.to_i when "friends_count" then @u.friends = @str.to_i when "user" then @u.calc_ratio @users << @u end end def end_document print "<table border=\"1\">\n" @users.each do |u| # print u.username, ":", u.friends, "/", u.followers, "--> " # printf("%.2f\n", u.ratio) pie = Piechart.new(u.friends, u.followers) print "<tr><td><img src=\"", u.image_url, "\"></td>" print "<td>", u.username, "</td><td>", pie.create_query, "(", u.friends, ") </td></tr>\n" end print "</table>\n" end end # Create a new parser parser = Nokogiri::XML::SAX::Parser.new(MyDocument.new) # Feed the parser some XML #parser.parse(File.read(ARGV[0])) option = "?page=1" username = ARGV.shift parser.parse(open("http://twitter.com/statuses/friends/"+username+".xml"+option))