競馬であそぶ 5

考えが政治に反映されなくても仕方ないが、最近は吐き気が。




9.   Win32::OLE と Win32::OLE::Variant  

本題の前に、一番最初に紹介した Perl モジュールの Config::Simple と ini ファイル について
簡単に書きます。
このファイルで保存用のパス設定、オッズデータの選択、取得タイムの設定と記録を行い ます。
先ず、JVSET.ini と名付けていますが、ini ファイル

[pass]
rcovP=h:/others/rcov/
rtdatP=h:/others/rtdat/
yobiP=h:/others/yobi/
oddsP=h:/others/odds/

[odds]
oz_tnfw=1
oz_uren=1
oz_utan=1
oz_wide=1
oz_3fuk=1
oz_3tan=1
oz_odds=0

[default]
FromTime=20050601000000
RACETime=20050601000000
YSCHTime=20050601000000

Config::Simple を使う目的は
 1. 最終的には、スクリプトを直接、触らずに済ませたい
 2. FromTime などを保存しておく場所が必要。但し、簡単に変更 できるように

パスは必ず設定しておいてください。エディタなどで書き換えておきます。
odds の部分で対応するところを 0 にすると、取得しません。(←説明追加)
ini ファイルへのスクリプトからの書き込みは、下記のように行います。

        $cfg->param("default.RACETime", $ltm->Value() ) ;
        $cfg->write() ;

取り込みは下のようにして、右側の値を取得します。下は[pass] の rcovP の値。
    $cfg->param("pass.rcovP")

Win32::OLE はPPM などで、インストールする必要があります。
コマンドラインから、ppm と打ち込んで起動した後、
ppm> install win32-ole
の要領ですね。Perl5 がインストールされていればコレだけです。多分、、

★ 以上で準備が完了 ★以下、本題。
前回からの修正部分については、Win32::OLE::Variant を使うことで解決 ということなのですが、
JVGets に関してはイマダ不明の部分があり、今回は JVRead を採りました。
これで支障あれば、もう一度JVGets を調べてみようと思います。
(解決。JVOPT の使い方の案内 参照 )

まず、毎週取得する非蓄積系のデータに対するスクリプトです。 細かい部分については、
JRA-VAN Data Lab. JVData 仕様書 と JV-Link インターフェース仕様書 を参照してください。

sub get_weekly {    # 非蓄積系データ取得
    my $ds = Variant( VT_BSTR, 'RACERCOV' ) ;
    my $ftm = Variant( VT_BSTR, $cfg->param("default.RACETime") ) ;
    my $op = Variant( VT_I4, 2 ) ;
    my $rco = Variant( VT_I4|VT_BYREF, 0 ) ;
    my $dco = Variant( VT_I4|VT_BYREF, 0 ) ;
    my $ltm = Variant( VT_BSTR|VT_BYREF, '' ) ;
    my $rtn = $jvd->JVOpen( $ds, $ftm, $op, $rco, $dco, $ltm ) ;
    my $i = 0 ;
    RTR: while ( $rtn > 400 and $rtn < 440 ) {
        $rtn = $jvd->JVOpen( $ds, $ftm, $op, $rco, $dco, $ltm ) ;
        $i++ ;
        last RTR if $i > 2 ;
    }
    if ( $rtn == 0 ) {
        $cfg->param("default.RACETime", $ltm->Value() ) ;
        $cfg->write() ;
        my $dir = $cfg->param("pass.rcovP") ;
        my $bsize = Variant( VT_I4, 5120 ) ;
        my $pbuf = Variant( VT_UI1, "\x00" x 5120 ) ;
        my $buff = Variant( VT_BSTR|VT_BYREF, \$pbuf ) ;
        my $fn = Variant( VT_BSTR|VT_BYREF, '' ) ;  # ファイル名
        my @dat = () ;      my $i = 0 ;
        my $flg ;
        while ( $flg = $jvd->JVRead( $buff, $bsize, $fn ) ) {
            next if $fn =~ /^H[16]/i ;      # 票データは除外
            next if $fn =~ /^[OB]/i ;       # アタマに O と B がつくのは除外
            if( $flg > 0 ) {
                $dat[$i] = $buff->Value() ;
                $i++ ;
            } elsif( $flg == -1 ) {
                my $fname = $dir . substr( $fn, 0, 12) . '.dat' ;
                open DAT, ">$fname" ;
                for( @dat ) {
                    s/\x00+//g ;    s/\r// ;
                    print DAT $_ ;
                }
                @dat = () ;             $i = 0 ;
                close DAT ;
                print "\t\t読み込み完了。→ $fn\n" ;
            } else {
                 print " 非蓄積系データ・読み込みエラー。$flg\n" ;
            }
        }
    } elsif ( $rtn == -1 ) {
        print "新しいデータはありません。\n" ;
    } elsif ( $rtn == -504 ) {
        print "サーバーメンテナンス中。\n" ;
    } else {
        print "非蓄積系データ・DLエラ−。$rtn\n" ;
    }
    &jv_close() ;
}

RTR の部分は、たまにサーバーに弾かれたりするので対策したつもりですが、 未テストです。
他にも勘違いやミスがあるかもしれませんが、気がついたら自分で直すのココロあるよ。

次に、当日のオッズや馬体重その他のデータを取得するための基本スクリプトです。

sub get_sokuho {
    my ( $ds, $bs, $ps ) = @{ shift() } ;
    my $dsnum = substr( $ds, -2, 2) ;
    my $ymdbr = $dsnum < 17 ? $yymmdd : $yymmdd . $bbrr ;
    my $rtn = $jvd->JVRTOpen( $ds, $ymdbr ) ;
    my $i = 0 ;
    RTR: while ( $rtn > 400 and $rtn < 440 ) {
        $rtn = $jvd->JVRTOpen( $ds, $ymdbr ) ;
        $i++ ;
        last RTR if $i > 2 ;
    }
    if( $rtn == 0 ) {
        my $dir = $cfg->param( $ps ) ;
        unless ( $dsnum < 17 ) {
            mkdir "$dir$yymmdd" unless -d "$dir$yymmdd" ;
            $dir .= $yymmdd . '/' ;
        }
        my $bsize = Variant( VT_I4, $bs ) ;
        my $pbuf = Variant( VT_UI1,  "\x00" x $bs ) ;
        my $buff = Variant( VT_BSTR|VT_BYREF, \$pbuf ) ;
        my $fn = Variant( VT_BSTR|VT_BYREF, '' ) ;   # ファイル名
        my $flg ;
        my $i = 0 ;
        my @dat = () ;
        while ( $flg = $jvd->JVRead( $buff, $bsize, $fn ) ) {
            if( $flg > 0 ) {
                $dat[$i] = $buff->Value() ;
                $i++ ;
            } elsif( $flg == -1 ) {
                my $plus = $dsnum < 17 ? 12 : 16 ;
                my $fname = $dir . substr( $fn, 0, $plus ) . '.dat' ;
                open DAT, ">$fname" ;
                for ( @dat ) {
                    s/\x00+//g ;    s/\r// ;
                    print DAT $_ ;
                }
                close DAT ;
                @dat = () ;     $i = 0 ;
                print "\t\t読み込み完了。→ $bbrr: $dsnum: $fn\n" ;
            } else {
                print " 速報・読み込みエラー。 $flg\n" ;
            }
        }
    } elsif( $rtn == -1 ) {
        if ( $dsnum < 17 ) {
            print "速報・該当データがありません。$rtn\n" ;
        } else {
            print "該当オッズデータがありません。$bbrr:$dsnum\n" ;
        }
    } elsif ( $rtn == -504 ) {
        print "サーバーメンテナンス中。\n" ;
    } else {
        print "速報・OPENエラー。$rtn\n" ;
    }
    &jv_close() ;
}

引数に応じてオッズと他情報とを分けています。面倒ならもっと簡単に作ったほうがいいかも
しれません。
オッズの場合、取得用のパスの中に日付のディレクトリを作っていたりします。

最後に、蓄積系の中から開催スケジュールを取り上げます。

sub get_schedule {  # 開催スケジュール取得
    my $ds = Variant( VT_BSTR, 'YSCH' ) ;
    my $ftm = Variant( VT_BSTR, $cfg->param("default.YSCHTime") ) ;
    my $op = Variant( VT_I4, 1 ) ;
    my $rco = Variant( VT_I4|VT_BYREF, 0 ) ;
    my $dco = Variant( VT_I4|VT_BYREF, 0 ) ;
    my $ltm = Variant( VT_BSTR|VT_BYREF, '' ) ;
    my $rtn = $jvd->JVOpen( $ds, $ftm, $op, $rco, $dco, $ltm ) ;
    if ( $rtn == 0 ) {
        $cfg->param("default.YSCHTime", $ltm->Value() ) ;
        $cfg->write() ;
        my $dir = $cfg->param("pass.rcovP") ;
        my $bsize = Variant( VT_I4, 512 ) ;
        my $pbuf = Variant( VT_UI1, "\x00" x 512 ) ;
        my $buff = Variant( VT_BSTR|VT_BYREF, \$pbuf ) ;
        my $fn = Variant( VT_BSTR|VT_BYREF, '' ) ;  # ファイル名
        my $flg ;
        my $i = 0 ;
        my @dat = () ;
        while ( $flg = $jvd->JVRead( $buff, $bsize, $fn ) ) {
            if( $flg > 0 ) {
                $dat[$i] = $buff->Value() ;
                $i++ ;
            } elsif( $flg == -1 ) {
                my $fname = $dir . substr( $fn, 0, 8) . '9999.dat' ;
                open DAT, ">$fname" ;
                for ( @dat ) {
                    s/\x00+//g ;    s/\r// ;
                    print DAT $_ ;
                }
                $i = 0 ;            @dat = () ;
                close DAT ;
                print "\t\t新しい開催スケジュール読み込み完了。\n" ;
             } else {
                 print " 開催スケジュール・読み込みエラー。 $flg\n" ;
            }
        }
    } elsif ( $rtn == -1 ) {
        print "新しい開催スケジュールはありません。\n" ;
    } elsif ( $rtn == -504 ) {
        print "サーバーメンテナンス中。\n" ;
    } else {
        print "開催スケジュール・DLエラ−。$rtn\n" ;
    }
    &jv_close() ;
}





10.   使ってナンボ  

Perl/Tk も Win32::OLE も凄いが。

前回までで Perl モジュールを活用したデータ表示や「取得に挑戦」も終わりました。

必要なデータはそれぞれみな違うので、これで終わりにしようと思ったのですが、モジュー
ル群。特に、Win32::OLE に関しては、競馬データであそぼうとする人にとって、もしかする
とかなり有力なツールになるんじゃないかと思います。

好きなとき好きなだけ好きな方法で、それも簡単なスクリプトを操作するだけでできてしまう
というのは、凄いんじゃないですか?
sSeia もここまで可能とは思っていませんでした。
こんな Perl を CGI だけの為に使うのはいかにも惜しい!ということで、一応動く スクリプト
を置いときます。
サブルーチンは使えると思いますョ。ついでに、ini ファイルも一緒に。

(2005.07.07) JVD_OLE (リンクを切りました)

(2005.07.13) JVD_OLE 追加・修正最終版 (リンクを切りました)


上の説明で抜けている部分(←かなりある)も、スクリプト本体を見れば解決すると思 います。
この二つを自分用に書き換えれば、少なくとも JVData の取得に関しては、パーフェクトか
なと思います。
ホントに使ってナンボのものなんですから。
しかし、これも Perl/Tk を併用すれば、もっともっと使いやすくなりそうですね。

★追加説明★
以下の追加・修正を含めたものを、上に置きました。コレ以降は次のシリーズで。

(2005.07.07)
JVSET.ini のパスを書き換えれば、このスクリプトを使うことは十分可能ですが、実用面を考える
と蓄積系と非蓄積系(の週データ)が同じ rcovP に収まるのはおかしいので、ini ファイルのパス
に stockP とかの行を新しく用意して、蓄積系は違うディレクトリに保存するのがいいでしょう。

当然、スクリプトの蓄積系(get_stock)のほうも、下のように書き換える必要があります。
        my $dir = $cfg->param("pass.stockP") ;
このように、ディレクトリも自在に設定できます。

それから、このスクリプトでは票数その他の自分にとって不要と思われるデータは取得しないよう
にしていますが、もしそうしたデータが必要であれば、 該当する next if の行を外す他、 サイズの
上限を調べて変更しないとダメな場合がありますので注意。

JRA-VAN Data Lab. JVData 仕様書JV-Link インターフェース仕様書要参照。

(2005.07.08)
このまま使う場合は、レース日入力のあと、当日のレース場コードが表示される ほうが便利。
スクリプトの最初の方に
my @ba_of = ( '    ', '札幌', '函館', '福島', '新潟', '東京', '中山', 
                '中京', '京都', '阪神', '小倉' ) ;
と定義しておいて、新しいサブルーチンを下のほうに作ります。

sub schedule {      # 開催レース場を配列に。引数(年月日で 8桁)
    my $ymd = shift ;           my @ans ;
    my $yyyy = substr( $ymd, 0, 4 ) ;
    my $dir = $cfg->param("pass.rcovP") ;
    my $fname = "${dir}YSNW$yyyy" . '9999.dat' ;
    open DAT, $fname ;
    SCH: while ( <DAT> ) {
        my ( $kubn, $rday, $jcd ) = unpack '@2 A1 @11 A8 @19 A2', $_ ;
        last SCH if $kubn == 1 ;
        next unless ( $kubn == 2 or $kubn == 3 ) ;
        if ( $ymd eq $rday ) {
            my $jdt = sprintf "%s(%d)", $ba_of[$jcd], $jcd ;
            push @ans, $jdt ;
        }
    }
    close DAT ;
    return @ans ;
}

次に サブルーチン get_bbcd を下のように変更します。

sub get_bbcd {
    my $bbcd ;
    my @hrt_jo = &schedule( $yymmdd ) ;
    print "\n" ;
    print ' ' x 17 ;
    print "  レース年月日が正しいか確認してください。"  unless @hrt_jo ;
    for ( @hrt_jo ) {
        print "     $_" ;
    }
    print  "
            ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
            ┃  レース場コードを入力してください。終了は 99    ┃
            ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
    \n\n\t\t ==> " ;
    chomp( $bbcd = <STDIN> ) ;
    exit if $bbcd == 99 ; 
    return $bbcd ;
}

これで、レース場名とレース場コードが表示されるようになります。

(2005.07.11)
やはり、修正ありますね。
開催スケジュールを含む蓄積系と、週データの非蓄積系の「読み込みエラー」の部分は 要らない
ようですね。取得行ごとに煩わしい表示(-3)が続く場合があります。
前章でのサンプルスクリプトの取消線で消した部分 ですが、修正して おいてください。
まだまだ、ありそうですが。


INDEXへ トップページへ