PythonからJV-Linkを操作する。
概要とまとめ
- JV-Linkをpython、win32comで操作する。
- JV-Linkは32bit ActiveXコントロールなのでpythonも32bit版が必要
- "win32com.client.Dispatch('JVDTLab.JVLink')"でインスタンス化
- 引数に値が返るメソッドは戻り値が引数でなくて、リスト形式で戻り値に返る。
(注意)JVGetは使い方分かりませんでした。JVReadは使えます。
きっかけ
20年振りに競馬とJRA-VAN Data Lab.利用したデータ解析(自作)を再開しようとおもったのが1年前。
EveryDB2というデータの取得と各種SQL DBへの登録というJRA-VAN Data Lab.を使ったデータ解析において一番面倒で生産性のない作業を肩代わりしてしてくれるソフトがあるのを知ったのも1年前。
そこから1年経過し、いざ始めようと思ったところEveryDB2は公開終了しておりダウンロードもできない状態になっていたので、JRA-VAN Data Lab.を使ったデータ解析で一番面倒で生産性のない作業に取り組むことにしました。
自分の環境
Anaconda3-2021.11-Windows-x86
32bit版(重要)のPythonなら使えると思います。
(注意)64bit版のAnaconda3-2021.11-Windows-x86_64.exeでは(多分)使用できないです。
初期化
win32.com.client.Dispath('XXX')の'XXX'部分がわからなかったのですが
'JVDTLab.JVLink'で良さそうです。
import win32com.client
Jvlink1 = win32com.client.Dispatch('JVDTLab.JVLink')
ReturnVal = Jvlink1.JVInit('UNKNOWN') #JVLinkの初期化
ReturnVal = Jvlink1.JVSetUIProperties() #1回設定すれば後はコメントアウトでOK
JVOpen
JV-Linkは、引数に値が戻ってくるメソッドが結構あります。JVOpenもその一つで
JVOpen(dataspec:str,fromtime:str,option:int,
readcount:int,downloadcount:int,lastfiletimestamp:str)
引数のうち"readcount,downloadcount,lastfiletimestamp"は呼び出し後に値が返ってくる格納用の変数となっています。
win32comで操作する場合は、ここに変数を指定をしても変数には値が格納されません。
使用する時は型が合った適当な値を入れれば大丈夫です。
returnval = Jvlink1.JVOpen(dataspec,fromtime,option, 0,0,'')
それでは"readcount,downloadcount,lastfiletimestamp"の値はどこにあるかというと、戻り値のreturnvalの中に本来の戻り値と共にリストとして返されます。
dataspec = 'RACE' #レース情報を取得
fromtime = 20220101000000 #YYYYMMDDhhmmss
option = 3 #セットアップデータ(ダイアログ表示有り)
returnval = Jvlink1.JVOpen(dataspec,fromtime,option, 0,0,'')
#returnval[0]:本来のメソッドの戻り値が格納される
#returnval[1]:readcountの値が格納される
#returnval[2]: downloadcountの値が格納される
#returnval[3]: lastfileteimstampの値が格納される
readcount = returnval[1]
downloadcount = returnval[2]
本来JVOpenはint型のエラーコードが戻りますが、win32com経由でJVOpenを呼び出した時は、
[エラーコード,readcount,downloadcount,lastfiletimestamp]
とリストで返ってきます。
全部を調べていませんが、JVOpen以外の他のメソッドも同じように戻り値部分に値が格納されるようです。
基本的にPythonでJVLinkを操作するにはここまで記載したことで実装できると思います。
蛇足かもしれませんが、以降はJVReadまでの全体的な流れまでは記載しておきます。
JVStatus
JVOpenで勝手にダウンロードが始まるのでJVStatusでダウンロード数を監視して終わるまで処理待ちします。
#JVopenのダウンロード完了待ち
while True:
returnval = Jvlink1.JVStatus()
print('\rDownloading',returnval,'/',downloadcount,end='')
if returnval <0 :
print('JVStatus Err=',returnval)
if downloadcount == returnval : #全ファイルダウンロードしたら完了
break
else :
time.sleep(2) # import time が必要。
JVRead
JVReadはbuffとfilenameが実行後に格納されるメソッドなので、JVOpenのようにbuffとfilenameは本来の戻り値と共にリストとして返されます。
Long JVRead( String 型 buff , Long 型 size , String 型 filename );
JVReadでは使わないレコード種別IDのデータも読み込まれるので、事前に使いたいレコード種別IDを列挙しておいて、それ以外のレコード種別IDのファイルの場合はJVSkipで読み飛ばすのがよいと思います。
#対象とするレコード種別IDをリストで列挙
target_recid=['RA','SE','HR','O1','O2','O3','O4','O5','O6','WF']
while True:
returnval =Jvlink1.JVRead("",102890,"")
if returnval[0] == 0 :
break #JVRead完了
elif returnval[0] == -1:
print("ファイル切り替わり")
elif returnval[0] < -1:
print("Error\nError Code=",returnval[0])
else :
#JVReadのデータのレコード種別IDを取得
rec_id = returnval[1][0:2] #レコード種別IDを取り出す
filename = returnval[2]
if (rec_id in target_recid):#読み込み対象のレコード種別IDである場合
buff = returnval[1]
#ここで処理を入れる
else : #読み込み対象外のレコード種別IDの場合ファイルを読み飛ばす。
Jvlink1.JVSkip()
その他
JVGetは使おうと思ったけどByteArrayのポインタを引数に渡すメソッドなんでどうやって実行すればいいのかわかりませんでした。
JVReadより処理が早いということですが、Pythonで無理矢理使う場合でも早いのか分からないですし結果はJVReadと同じなので、JVRead使えばよいかなと思います。
JVOpen/JVReadの高速化に関しては、大量のデータを読み込んだ場合に二次関数的に時間がかかるのが問題なので、10年とかのまとまったデータを処理する場合2年分の処理が終わったら一旦処理を中断し、fromtimeの値をアップデートしてJVOpen/JVReadを途中から再開するとかの方が早かったりするのでJVGet使うよりはそっちの方を個人的にはオススメします。
Discussion
EveryDB2は現在使用可能になっています。EveryDB2を使って更新して頂けませんか?
現在すでに独自のシステムを構築していて十分に運用している状況なのでEveryDB2を使った方法を個人的には必要としていないので更新は予定していないです。すみません。