Hatena::Grouprubyist

うんたらかんたらRuby RSSフィード

2008-12-03Nokogiriを使ってみた

Nokogiriを使ってみた

| Nokogiriを使ってみた - うんたらかんたらRuby を含むブックマーク はてなブックマーク - Nokogiriを使ってみた - うんたらかんたらRuby

fizzbuzzをやってみた - うんたらかんたらRuby - Rubyist

anarchy golf - FizzBuzz

golfでは、67位なんだけど早さでは何位なんだろうかと思って

scrapeしてsortしてみようと思い立った。



ここら辺(Ruby Scraping - FrontPage)をみながら

xpathとかcssセレクタとかを簡単に扱えるらしい。」ということで

Nokogiri(tenderlove's nokogiri at master — GitHub)をインストールしてみることに。


インストール

gem install nokogiri

で簡単に入れれるらしい。

Building native extensions.  This could take a while...
ERROR:  While executing gem ... (Gem::Installer::ExtensionBuildError)
    ERROR: Failed to build gem native extension.

でもエラー。。

gemを更新して再度やったらうまくいった。

gem update --system


早速使ってみる

xpathで簡単にデータが取得できるのはわかったけど、

このhtmlanarchy golf - FizzBuzz)には

idとかclassとかが適切に設定されていないので

Rubyの結果だけを抜き出せるようなxpathが書けない。


htmlの構造は↓みたいな感じになってる。

 html

 body

 a Ruby(言語名)....

 table Rubyの結果

 a Perl(言語名)....

 table Perlの結果

  ・

  ・

  ・

悩んだ結果、「言語名のaタグ」の後に「結果のtableタグ」が必ずくるので

それぞれ別々の配列に取得して、使う時に同じindexを使えば

欲しい言語の結果が取り出せそう。


書いてみた

require 'rubygems'
require 'nokogiri'
require 'open-uri'
  
abort('no argument err.') if ARGV.size == 0

doc = Nokogiri::HTML(open('http://golf.shinh.org/p.rb?FizzBuzz#Ruby'))

#言語名を配列にセット
prog_names = []
doc.xpath('/html/body/h3/a[@href]').each do |nsa|
  href = ""
  href = nsa.get_attribute("href")
  if href =~ /\/l\.rb\?.*/
    prog_names << nsa.inner_text
  end
end

#tableタグを配列にセット
#tables最後のtable要素は「Language Ranking」が含まれる。(言語名より1つ多い)
tables = []
tables = doc.xpath('/html/body/table')

rank_info = Hash.new
prog_names.each_with_index do |prog, i|
  if ARGV[0].upcase == prog.upcase
    p prog
    tables[i].xpath('tr').each do |tr|
      user = tr.xpath('td[2]').inner_text
      time = tr.xpath('td[4]').inner_text
      if user != "" && time != ""
        rank_info[user] = time
      end
    end
  end
end

puts "Rank User Time"
puts "------------------------------"
rank_info.sort_by {|key, val| val}.each_with_index{|x, n| puts "#{n + 1} #{x[0]} #{x[1]}"}

引数で指定した言語の結果を早さ順に並べ替えます。


結果

$ ruby noko.rb ruby
"Ruby"
Rank User Time
------------------------------
1 leonid (alnum) 0.0003
2 Duane Bailey 0.0071
3 Matthew 0.0118
4 crazyjimbo 0.0171
5 khtokage 0.0197
6 yuya 0.0296
7 rawwell 0.0302
8 flagitious(alnum) 0.0344
9 rickrickrick 0.0355
10 shrapnel 0.0373
11 rochefort 0.0373
12 Steve Cooper 0.0432
13 mokos 0.0487
14 lw 0.0491
15 smly 0.0492


以下略

なんとか、11位(同順で10位。ここは考慮できてない)。


疑問点

今回は、sorthashを利用したけど、構造体の配列みたいなので本当はやりたい。

でもよくわかんない(2次元配列とかのソートが)。

user名でソートとかを簡単にするには、多次元配列のソートを書かないといけないのかな。

簡単にできる方法はないのかな。

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20081203