今回選考させて頂いた業者さんは、『Foreland Forex』です。
選考基準は、以下の通りです。
①過去のデータを開示されていること 。
②ランク付けされていること 。
③日本語であること。
【試行①】
先回紹介した方法でスクレイピングしてみた結果は、以下の通りです。
日付部分のデータが歯抜けになっているし、ランクが消えています。
このままでは、使用しづらいので別の方法を考えてみました。
【試行②】
先回紹介したサイト(勉強用メモ-WEBから情報の抜き出し(スクレイピング、スパイダリング))に記載のある別の方法を選択してみました。
選考基準は、以下の通りです。
①なるべく簡単にスクレイピング処理が可能なこと。
②Windows上で単独で作動可能なこと。
③どうせなら、マルチプラットフォームを意識した言語を学習したい。
④日本人の諸先輩方がたくさんいる(参考になるサイトがたくさんある)言語であること。
上記を考えると、①③④を満たし、EXEに加工できることから②を満たすため、[RUBY]となりました。
【設計概要】
やりたいことをまとめてみました。(以下 sp=スクレイピング)
①サイトから必要な情報をspしたい。
②spした内容を、【日付】【国名】【行事名】【ランク】【前回】【予想】【結果】としてCSVファイルに保存したい。【日付】は、【年】【月】【日】【時】【分】と分割保存したい。
③spした内容に欠落部がある場合に補正したい。
④【時】を0~23時のフォーマットにしたい。
⑤サーバータイムに変更したい。
⑥夏時間に対応させたい。
⑦バックナンバーを一括spしたい。それをまとめたい。
【コード】
上記のやりたいことを元にコードを作成してみると・・
下記は一部コード表示が化けています。コードダウンロード
#! ruby -Ks require 'rubygems' require 'hpricot' require 'open-uri' require 'csv' ##################################################################### #ファイルの作成 def GetDate( address ="", direct = "",gmt ="0",booldst = "false") thday = [] dayofweek = ["日","月","火","水","木","金","土"] cnv = CSV.readlines('Conversion.csv') begin #HPを開いてdocに格納 doc = Hpricot( open(address).read ) #発行日取得 daydate = (doc/"h1.heading01").inner_html /\d+\.+\d+\.+(\d\d|\d)/ =~ daydate daydate = $& #発行日の分解day[0]:年 dya[1]:月 day[2]:日 day = daydate.split(/[.]/) #桁数の統一 rescue return false end 2.times { |i| if day[i+1].size == 1 then day[i+1] = "0" + day[i+1] end } #ファイル名の作成 if direct =="" failname = "CurrentDate.csv" else failname = direct +"/" + day[0] + day[1] + day[2] + ".csv" end CSV.open(failname , "w") do |csvfail| #docからtr要素を1行づつ抽出しtrdに格納 (doc/:tr).each do |trd| #配列をtrdate名で作成 trdate = [] #年の格納 trdate << day[0] #trdからth要素かつclass="eventdate"の値を抽出 trdate << (trd/"th.eventdate").inner_html.strip #もし上記条件が否定されたら if (trd/"th.eventdate").empty? #上記変数から値を代入 trdate = thday.clone else #上記変数に値を代入 thday = trdate.clone end #日時の書式変更分割 /\// =~ trdate[1] trdate << "$`" << "$'"#注意:この行の””は表示用 trdate.delete_at 1 #年の修正 if day[1] == "12" && trdate[1] == "1" then trdate[0] = trdate[0].to_i + 1 end #trdからtd要素をtddに1行づつ抽出 (trd/:td).each do |tdd| #trdからimg要素を抽出し、あれば"src"の値をtrdateに格納する trdate << (tdd/:img).attr("src").strip if not (tdd/:img).empty? #trdからtdd要素を抽出し、あればそのテキストをtrdateに格納する trdate <= 24 then dtime = 1; dhour -= 24; end mktimes = Time.local(trdate[0].to_i,trdate[1].to_i,trdate[2].to_i,dhour,trdate[4].to_i) mktimes += dtime*24*60*60 #サーバータイムに変換 mktimes -= gmt.to_i*60*60 #夏時間変換 if booldst == "true" && GDST(mktimes) == true then mktimes += 60*60 end trdate[1] = mktimes.mon trdate[2] = mktimes.day trdate[3] = mktimes.hour end end #ランク覧の空欄に0を挿入 if trdate[7] == "" then trdate[7] = "0" end #trdateがからでなければcsvfailに書き込み csvfail << trdate if not trdate[0].nil? end end return true end ########################################################################## #既存ファイルの確認(有:true 無:false) def Selectfail( failname = "20070917.csv" ,direct = "./tmp" ) #カレントディレクトリの移動 Dir.mkdir(direct) unless FileTest.exist?(direct) Dir.chdir(direct) #ファイルの確認(bool型) getf = FileTest.exist?(failname) Dir.chdir("../") return getf end ########################################################################### #既存ファイル名の成形 def namefail(no = 0) #No3の日付作成 fday = Time.local(2007, 8, 27) fday += 7 * no * 60 * 60 * 24 p "%04d"%fday.year + "%02d"%fday.month + "%02d"%fday.day + ".csv" return "%04d"%fday.year + "%02d"%fday.month + "%02d"%fday.day + ".csv" end ############################################################################ #過去のデータの取得 def HistDate(direct = "./tmp",gmt ="0",booldst = "false") count = 3 #無限ループ loop do failname = namefail(count) break if Selectfail(failname) == false count +=1 end if count >170 then count +=6 end loop do address = "http://www.foreland.co.jp/marketreport/calendar_detail_id_marketcalendar_" + count.to_s + ".html" p address break if GetDate(address,direct,gmt,booldst) == false && count >=180 count +=1 #sleep(3) end end ########################################################################### #既存ファイルの削除 def Inzfaile(failname = "HistoricalDate.csv") #ファイルの確認(bool型) if FileTest.exist?(failname) then begin File.delete(failname) rescue p "古いファイルが削除できません" return false end end return true end ########################################################################## #ファイルの結合 def Joinfail(direct = "./tmp") #ファイルの初期化 failname = "HistoricalDate.csv" if Inzfaile(failname) == false then return end #書き込み用ファイルを開く sumdate = CSV.open(failname,"w") #ディレクトリの移動 Dir.chdir(direct) count =3 loop do begin getdate= 0 fname = namefail(count) CSV.open(fname,"r") do |gdate| sumdate << gdate if not gdate[0].nil? end count += 1 rescue p "完了" break end end Dir.chdir("../") sumdate.close end ########################################################################## #過去のデータの取得 def GetHistDate(direct = "./tmp",gmt ="0",booldst = "false") HistDate(direct,gmt,booldst) Joinfail(direct) end ########################################################################## #最新のデータを取得 def CurrentDate(gmt ="0",booldst = "false") add ="http://www.foreland.co.jp/marketreport/calendar_detail.html" GetDate(add,"",gmt,booldst) end ########################################################################## #分義 def Hab(gmt ="0",booldst = "false") CurrentDate(gmt,booldst) if not getf = FileTest.exist?("HistoricalDate.csv") then GetHistDate("./tmp",gmt,booldst) ; return ; end end ########################################################################## #夏時間 def GDST(dtime) check = false mon_s = 3 week_s = 2 mon_e = 11 week_e = 1 lastmonth = Time.local(dtime.year ,mon_s ,1) lastmonth -= 24*60*60 day_s = week_s * 7 - lastmonth.wday stime = Time.local(dtime.year , mon_s ,day_s) lastmonth = Time.local(dtime.year ,mon_e ,1) lastmonth -= 24*60*60 day_e = week_e * 7 - lastmonth.wday etime = Time.local(dtime.year , mon_e , day_e) if stime <= dtime && dtime <= etime then check = true end return check end ######################################################################## if ARGV[0].nil? then ARGV[0] ="0" end if ARGV[1].nil? then ARGV[1] ="false" end Hab(ARGV[0],ARGV[1])
【結果】
デフォルト設定での結果は、以下の様になります。
簡単に説明すると
①《A列~E列》
日付および時間を示します。ただし、《D列(時)》の(-1)は、無指定を意味します。
つまり、時間指定がないイベントを意味しています。
②《E列》
国名を示します。※下部添付内の『Conversion.csv』にて変更可能です。
③《G列》
イベント名
④《H列》
ランクを示します。※下部添付内の『Conversion.csv』にて変更可能です。
⑤《I列~K列》
【前回】【予想】【結果】を示します。
【使い方】
①GetEventDate.zipをダウンロードします。
②解凍すると、以下のファイルがあります。
【Coversion.csv】文字変換に使用するファイルです。お好みで変更してください。
【GetEventDate.bat】タイムゾーンの変更および夏時間の有無を設定できます。
※デフォルトは、変換しないように設定してあります。
【GetEventDate.exe】起動ファイルです。
【初期設定】
【GetEventDate.bat】を右クリック→編集で開き下記の設定を行います。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM 引数の設定を行います。
REM ①日本標準時とサーバータイムの差を記入する。
REM サーバータイムがGMT 0 の場合は、”9”を記入してください。
REM デフォルト”0”の場合は、日本時間を示す。(タイムゾーン変換を行いません)
REM ②サマータイムの設定を行います。"true"の場合は、サマータイム変換を実施します。
REM "false"の場合は変換を行いません。
REM ③記載例: EventDate.exe 【"タイム差"】 【"サマータイムの有無"】
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
【Coversion.csv】を開きB列をお好みで変更してください。
[B1~B5]ランクの表示[B6~B17]国名表示です。
【初作動】
【GetEventDate.bat】をクリックして作動させます。exeファイルをクリックしても作動しますがその場合は、パラメーターが、デフォルト状態になります。(日本時間で夏時間なし)
【結果】
【tmp】フォルダーが成形されてその中にバックナンバーがまとめられます。
【HistoricalDate.csv】バックナンバーの結合ファイルです。
【CrrentDate.csv】今週のカレンダーです。
【次回からの作動】
初作動以外は、【HistoricalDate.csv】がある場合、【CrrentDate.csv】のみ書き換えます。
【HistoricalDate.csv】を更新したい場合は、【HistoricalDate.csv】を削除後作動させてください。
【まとめ】
本来は、夏時間の有無やGMT変換が、できるようですが、OSの壁(Windows特有のタイムゾーン表示)が原因でうまく作動しませんでした。(対応策はあるようですが・・・)そのため、地道な方法を採用しました。また、調べているときこんなフレーズを目にしました。『C++ユーザーは、rubyを覚えないほうがいいよ!・・・戻れなくなるから・・・』C++ユーザーではありませんが納得です。MQL5のAPI移植は、C++を使用しましたがもう少し早くrubyと出会えていたら、もっと簡単に加工できたと思う今日この頃です。ONZ
0 件のコメント :
コメントを投稿