先物投資をやっているのですが、毎日4本値を調べるのが面倒。
スクレイピングの練習がてら取得するスクリプトを書いてみました。
スクレイピングを使えば、取得したい情報を抜き出して、好きな形に整形してメールでもslackでもブログに投稿でも好きなことができます。
プログラミングで身近に実利を感じやすい分野でもあります。
参考書籍はこれ。

- 作者: 佐々木拓郎,るびきち
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2014/08/23
- メディア: 単行本
- この商品を含むブログ (10件) を見る
Rubyでクローラ、スクレイピングを学びたいと思ったらこれ一択。
取得してくるサイトは松井証券の先物情報ページです。
このサイトでから取得したいのは、225先物とtopixの4本値
- 始値
- 高値
- 安値
- 終値(現在値)
の4つです。
このページは単純なHTMLなので、HTMLを解析するだけで情報が取得できます。
方法としては
- wgetを使って正規表現で抜き出す
- HTMLパーサーを使って情報を抜き出す
2通りの方法が考えられます。
HTMLパーサーを使った方が簡単なので、今回は後者の方法を選択します。
HTMLをパースするgemはnokogiriを使います。
まずはkonogiriのインストール。
gem install nokogiri
うまくいかない場合は公式tutorialを見ながらinstallしてください。
pryで色々叩きながら試します。
まずはnokogiriを使える状態にします。
[1] pry(main)> require 'nokogiri' => true [2] pry(main)> require 'open-uri' => true
取得したいページがあるurlを変数に入れておきます。
[3] pry(main)> url = 'http://finance.matsui.co.jp/stocks/matsui/contents/futuresList.aspx' => "http://finance.matsui.co.jp/stocks/matsui/contents/futuresList.aspx" [4] pry(main)>
nokogiriにかけます!
doc = Nokogiri::HTML(open(url))
docの中に解析されたHTMLが格納されています。
解析されたHTMLからどうやって4本値を取得するか?
今回はxpathを使います。
xpathを調べるにはchromeを使えば簡単です。
1. 取得したい情報の上で検証を押す
2. 青くハイライトされたHTMLの上でcopy→xpath
を押せばクリップボードにxpathがコピーされた状態になります。
このxpathをつかってdocの中から抜き出したい要素をしていします。
これは現在地をぬきだす場合です。
doc.xpath('/html/body/div[1]/main/div[2]/article/div[2]/div[2]/div[1]/div/div[1]/div/table/tbody/tr[1]/td/b')
これだとnokogiriのオブジェクトが返ってくるのでinnner_textメソッドを使って情報のみ取得します。
[6] pry(main)> doc.xpath('/html/body/div[1]/main/div[2]/article/div[2]/div[2]/div[1]/div/div[1]/div/table/tbody/tr[1]/td/b').inner_text => "19,480.00"
カンマと小数点は不要なので、正規表現で削除します。
[8] pry(main)> doc.xpath('/html/body/div[1]/main/div[2]/article/div[2]/div[2]/div[1]/div/div[1]/div/table/tbody/tr[1]/td/b').inner_text.gsub(/(\d{0,3}),(\d{3})/, '\1\2').to_i => 19480
できあがったコードはこれです。
slackのweb hook urlはご自分のものに差し替えてください。
225先物とtopix先物の4本値を取得してslackに通知するスクリプトです。
また、yahooからトヨタとSUBARUの株価の4本値を取得しています。
require 'nokogiri' require 'open-uri' require 'pry' require 'slack/incoming/webhooks' class FourValue def initialize(url, name) @doc = Nokogiri::HTML(open(url)) @name = name end attr_accessor :name, :opening_price_path, :high_price_path, :low_price_path, :closing_price_path def opeing_price format_integer(@doc.search(@opening_price_path)) end def high_price format_integer(@doc.search(@high_price_path)) end def low_price format_integer(@doc.search(@low_price_path)) end def closing_price format_integer(@doc.search(@closing_price_path)) end def format_integer(nokogiri_format) nokogiri_format.inner_text.split.first.gsub(/(\d{0,3}),(\d{3})/, '\1\2') end def four_value_headers p @name p '始値 高値 安値 終値' end def four_value(topix = nil) if topix p "#{opeing_price} #{high_price} #{low_price} #{closing_price}" else p "#{opeing_price.to_i} #{high_price.to_i} #{low_price.to_i} #{closing_price.to_i}" end end end matsui_url = 'http://finance.matsui.co.jp/stocks/matsui/contents/futuresList.aspx' sakimono_225 = FourValue.new(matsui_url, '225') sakimono_225.opening_price_path = '/html/body/div[1]/main/div[2]/article/div[2]/div[2]/div[1]/div/div[2]/div/table/tbody/tr[1]/td' sakimono_225.high_price_path = '/html/body/div[1]/main/div[2]/article/div[2]/div[2]/div[1]/div/div[2]/div/table/tbody/tr[2]/td' sakimono_225.low_price_path = '/html/body/div[1]/main/div[2]/article/div[2]/div[2]/div[1]/div/div[2]/div/table/tbody/tr[3]/td' sakimono_225.closing_price_path = '/html/body/div[1]/main/div[2]/article/div[2]/div[2]/div[1]/div/div[1]/div/table/tbody/tr[1]/td/b' slack_url = 'https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxx' slack = Slack::Incoming::Webhooks.new(slack_url) slack.icon_emoji = ':yen:' slack.post "#{sakimono_225.name}\n#{sakimono_225.four_value_headers}\n#{sakimono_225.four_value}" sakimono_topix = FourValue.new(matsui_url, 'topix') sakimono_topix.opening_price_path = '/html/body/div[1]/main/div[2]/article/div[2]/div[6]/div[1]/div/div[2]/div/table/tbody/tr[1]/td' sakimono_topix.high_price_path = '/html/body/div[1]/main/div[2]/article/div[2]/div[6]/div[1]/div/div[2]/div/table/tbody/tr[2]/td' sakimono_topix.low_price_path = '/html/body/div[1]/main/div[2]/article/div[2]/div[6]/div[1]/div/div[2]/div/table/tbody/tr[3]/td' sakimono_topix.closing_price_path = '/html/body/div[1]/main/div[2]/article/div[2]/div[6]/div[1]/div/div[1]/div/table/tbody/tr[1]/td/b' slack.post "#{sakimono_topix.name}\n#{sakimono_topix.four_value_headers}\n#{sakimono_topix.four_value(topix = true)}" yahoo_url = 'https://info.finance.yahoo.co.jp/history/?code=7203' toyota = FourValue.new(yahoo_url, 'トヨタ') toyota.opening_price_path = "div#main tr:nth-child(2) > td:nth-child(2)" toyota.high_price_path = "div#main tr:nth-child(2) > td:nth-child(3)" toyota.low_price_path = "div#main tr:nth-child(2) > td:nth-child(4)" toyota.closing_price_path = "div#main tr:nth-child(2) > td:nth-child(5)" slack.post "#{toyota.name}\n#{toyota.four_value_headers}\n#{toyota.four_value}" yahoo_url = 'https://stocks.finance.yahoo.co.jp/stocks/history/?code=7270.T' subaru = FourValue.new(yahoo_url, 'SUBARU') subaru.opening_price_path = "div#main tr:nth-child(2) > td:nth-child(2)" subaru.high_price_path = "div#main tr:nth-child(2) > td:nth-child(3)" subaru.low_price_path = "div#main tr:nth-child(2) > td:nth-child(4)" subaru.closing_price_path = "div#main tr:nth-child(2) > td:nth-child(5)" slack.post "#{subaru.name}\n#{subaru.four_value_headers}\n#{subaru.four_value}"
コメントを残す