gouf
2/8/2015 - 8:41 AM

define_method メソッドでコードをシンプルに書く

define_method メソッドでコードをシンプルに書く

module XpathList
  module Yahoo
    COMPANY_XPATH = {
      name:     "//th[@class='symbol']/h1",
      category: "//table[@class='boardFinCom marB6']/tr[6]/td",
      unit:     "//table[@class='boardFinCom marB6']/tr[13]/td",
    }

    STOCK_XPATH = {
      per: "//div[@class='chartFinance']/div[5]/dl/dd[@class='ymuiEditLink mar0']/strong",
      pbr: "//div[@class='chartFinance']/div[6]/dl/dd[@class='ymuiEditLink mar0']/strong",
      recent_high_price: "//div[11]/dl/dd[@class='ymuiEditLink mar0']/strong",
      recent_low_price:  "//div[12]/dl/dd[@class='ymuiEditLink mar0']/strong",
      high_price: "//div[@class='innerDate']/div[3]/dl/dd[@class='ymuiEditLink mar0']/strong",
      low_price:  "//div[@class='innerDate']/div[4]/dl/dd[@class='ymuiEditLink mar0']/strong",
      price: "//td[@class='stoksPrice']"
    }

    def base_url
      'http://stocks.finance.yahoo.co.jp/stocks'
    end
  end
end

Rubyを用いてのクローリングについて(6388)|teratail を見て、別の書き方はないものかと試してみたかった

モジュールにハッシュ値の定数を定義する方法にしたけれど、YAML に書き出してそれを読み込む方法もあるかもしれない

(こうした、Web ページを対象にした情報収集は、「あのページを見に行ってこのページに移動して」となるのが辛いところのような気がする)

require 'nokogiri'
require 'open-uri'
require_relative './xpath_lists'

class CompanyInfo
  include XpathList::Yahoo


  def initialize(ticker_code)
    @stock = stock_info(ticker_code)
    @company = company_info(ticker_code)
  end

  COMPANY_XPATH.each do |key, value|
    define_method(key) do
      @company.xpath(value).text
    end
  end

  STOCK_XPATH.each do |key, value|
    define_method(key) do
      @stock.xpath(value).text
    end
  end

  def print
    puts name
    puts category
    puts unit
    puts 'PER:'        + per
    puts 'PBR:'        + pbr
    puts '年初来高値:' + recent_high_price
    puts '年初来安値:' + recent_low_price
    puts '高値:'       + high_price
    puts '安値:'       + low_price
    puts '株価:'       + price
  end

  private

  def scrape_stock_info(html, index)
    get_content(html, 'dd', 'ymuiEditLink mar0', index, '/strong').delete(',')
  end

  def company_info(ticker_code)
    url = "#{base_url}/profile/?code=#{ticker_code}"
    nokogiri_doc(url)
  end

  def stock_info(ticker_code)
    url = "#{base_url}/detail/?code=#{ticker_code}"
    nokogiri_doc(url)
  end

  def nokogiri_doc(url)
    html = open(url)
    Nokogiri::HTML(html.read, nil, 'utf-8')

  rescue OpenURI::HTTPError
    # empty string
    ''
  end
end

company_info = CompanyInfo.new('4689')
company_info.print
# =>
#   ヤフー(株)
#   情報・通信
#   100株
#   PER:(連) 18.58
#   PBR:(連) 3.47
#   年初来高値:668
#   年初来安値:384
#   高値:428
#   安値:421
#   株価:425