スクレイピング scrAPI with String#scrape

2007/09/06

scrAPIを使う際にとても便利になるStringクラス拡張。
grepのような感覚でCSSセレクタをたどっていけるようになります。

String#scrape

Stringクラスに以下のようなString#scrapeを入れておくとscrAPIがすごく便利に使えるようになります。
require 'scrapi'
class String
  def scrape(pattern, options = {}, &block)
    options = {:extract=>options} unless options.is_a?(Hash)
    options[:parser_options] =
    {:char_encoding=>'utf8'}.merge(options[:parser_options]||{})
    extract =
          options.delete(:extract) || block && :element || :text
    scraped = Scraper.define do
      process pattern, "matches[]"=>extract
      result :matches
    end.scrape(self, options) || []
    block ? scraped.map{|i| block.call(i)} : scraped
  end
end

これを使って今度は外為レートを取得するスクレイピングをやってみます。

外為レート取得アプリをつくる

こちらでやっている「ひまわり証券株式会社 ブログパーツ FXレートウォッチャー」のスクレイピングと同じことをやってみます。
前回のRailsアプリケーションを改造します。
まず、String#scrapeをapplication.rbに入れます。

application.rb
class ApplicationController < ActionController::Base
  session :session_key => '_scraping_session_id'
end

require 'rubygems'
require 'scrapi'
class String
  def scrape(pattern, options = {}, &block)
    options = {:extract=>options} unless options.is_a?(Hash)
    options[:parser_options] =
     {:char_encoding=>'utf8'}.merge(options[:parser_options]||{})
    extract =
          options.delete(:extract) || block && :element || :text
    scraped = Scraper.define do
      process pattern, "matches[]"=>extract
      result :matches
    end.scrape(self, options) || []
    block ? scraped.map{|i| block.call(i)} : scraped
  end
end


コントローラ(scraping_controller.rb)
String#scrapeを使って、現在時刻(@now)、通貨ペア(currency)、現在値(rate)、前日比(change)を取得します。
通貨ペア(currency)、現在値(rate)、前日比(change)は、ビューで使いやすいようArray#zipで@fxにまとめます。
このへんはほんとはモデルつくってやるべきなんだけど、今回はスクレイピングが目的なので、そのままGO。
require 'open-uri'

class ScrapingController < ApplicationController

  def index
    @now = nil
  end

  def scrape
    html = NKF.nkf('-w', open(params[:url]).read)
    @now = html.scrape("tr td")[0]
    currency = html.scrape("tr td.tdborder-center:nth-child(1)")
    rate = html.scrape("tr td.tdborder-center:nth-child(2)")
    change = html.scrape("tr td.tdborder-right")
    change.shift
    @fx = currency.zip(rate, change)
    render :action => 'index'
  end
end


ビュー(index.rhtml)
@nowと@fxをもとに、テーブルを表示。▲は+に、▼は-に変換。
<h1>Scraping#index</h1>
<%= start_form_tag(:action => 'scrape') %>
<%= text_field_tag('url',
   'http://fx.himawari-group.co.jp/price/blogparts.html') %>
<%= submit_tag("ScrAPIで外為レート抽出") %>
<% if @now != nil -%>
  <br /><hr />
  <%= @now -%>
  <table border="1">
  <tr><th>通貨ペア</th><th>現在値</th><th>前日比</th></tr>
  <% @fx.each{|f| -%>
    <tr>
    <td><%= f[0] -%></td>
    <td><%= f[1] -%></td>
    <td><%= f[2].sub(/▲/, "+").sub(/▼/, "-") -%></td>
    </tr>
  <% } -%>
  </table>
<% end -%>
<%= end_form_tag %>


実行結果はこのようになります。
scraping

Ruby and Rails | コメント(0) | トラックバック(0)
トラックバック
トラックバックURL:
コメントをどうぞ
名前 (入力しなければ「通りすがり」):

メールアドレス (入力しても公開されません):

URL (入力すればリンクが張られます):


コメント:

(コメントにタグなどを使ってもタグがそのままが表示されます)