2026年初頭AIの進歩が凄まじく、AIを使った何かをやってみたいと競馬予想AIを作ってみたシリーズの第4回です
今回はJV-LinkをPythonで使ってJRA-VANの過去データを取り込み、毎日の差分を自動で回せる形にするところまでです
前回までの記事はこちら→#1-はじめに / #2-スクレイピング / #3-note自動投稿
競馬のデータ分析をするなら最有力になるJRA-VAN Data Lab.
2026年3月の#2で、JRA-VAN Data Lab.を契約してJV-Linkまで調べたものの、対応している言語はVBやC++の32bit版で、64bit版や私が多く利用するPythonは入っておらず、諦めてデータはnetkeibaのスクレイピングで集める方針にしていました
が、なんと2026年8月にそのJV-Linkに64bit版が出たらしく、Pythonの開発ガイドも入っていました
そこでClaude Codeと一緒にデータの取り込みを作り直し、初回のセットアップ以外は人の手を介さずに回せるようになりました
目次
JV-Linkは2026年8月から64bit版とPythonに対応した
2026年8月4日のSDK Ver5.0.0で64bit版のJV-Linkが出て、Python用の資料もSDKに入りました
64bitのPythonから、pywin32でそのまま呼べます
実は以前も32bit版のPythonを入れる手順や、レジストリを書き換えて回避する方法を有志があれこれ試してくれていて、非推奨ではありつつも使う方法はありましたが、ついに公式手順で使えるようになったのはありがたい
Pythonについては、開発者向けのメーリングリストで「ご要望の多かったPythonの開発ガイドを新規に追加いたしました」と告知されています
Pythonの資料は64bit版のSDKにだけ入っていて、中身は次の3つ
- 開発ガイド(イベント Python)第1.0.0版
- サンプルプログラム sample1_Python3.14
- JV-Data構造体のPython版 JVData_Struct.py
ヘルプセンターの「サポートしている開発環境」は2023年11月付のままで、Pythonはまだ載っていません
※2026年11月時点の情報
PythonからJV-Linkを呼ぶまでの準備
用意するのは、Data Lab.の契約・64bit版のJV-Link・利用キー・64bitのPythonとpywin32です
STEP
SDKの64bit版を落とす
64bit版のダウンロードリンクはトップページになくて少しわかりにくいですが、今から始めるなら64bit版推奨
開発者コミュニティのSDKのページに、Ver5.0.0の64bit版と32bit版が並んでいます
STEP
64bit版のJV-Linkを入れる
SDKの中の JV-Link\JV-Link.exe から入れます
32bit版しか入っていないと、Pythonで Dispatch("JVDTLab.JVLink") を呼んだところで「クラスが登録されていません」と出て止まります
STEP
JV-Link設定で利用キーを入れる
利用キーが空のままだと、JVOpenが-303を返します
64bit版の公開のお知らせにもあるとおり、32bit版と64bit版には別々の利用キーが要ります
1つの契約で利用キーは2つ出ますが、同じキーを両方に入れると-301です
32bit版を2台のパソコンで使っている人は、64bit版に回すキーの空きが無いので、契約がもう1つ要ります
STEP
Pythonとpywin32を用意する
pywin32は、WindowsのCOMの仕組みをPythonから呼ぶライブラリです
JV-Link(JRA-VAN APIにあたる部品)も、このCOMで動きます
私はPython 3.13の64bit版で動かしています
公式の環境構築の手順はPython 3.14とVisual Studio 2026を使う形ですが、venvに pip install pywin32 で足りました
準備ができたら、次の3行で確かめます
JVInitが0を返せば、64bit版のJV-LinkをPythonから呼べています
import win32com.client
jv = win32com.client.Dispatch("JVDTLab.JVLink")
print(jv.JVInit("UNKNOWN")) # 0 なら呼べている
JVInitはサーバーとは通信しないので、利用キーが正しいかはJVOpenを呼んだときに分かります
"UNKNOWN" はソフトのIDで、開発中でIDが決まっていなければこれを渡します
ソフト作者の登録をしていない私も、これで動かしています
過去データ取得の流れと、公式どおりでは詰まった3つ
過去データは5つのメソッドを順に呼んで取ります
- JVInitで初期化する
- JVOpenで、データの種類と期間を指定して開く(過去データはoption=4のセットアップ)
- JVStatusで、ダウンロードが終わるのを待つ
- JVReadで、0が返るまで1件ずつ読む
- JVCloseで閉じる
最小の形にすると、こうなります
import time
import pythoncom
import win32com.client
jv = win32com.client.Dispatch("JVDTLab.JVLink") # 64bit 版の JV-Link が要る
if jv.JVInit("UNKNOWN") != 0:
raise SystemExit("JVInit に失敗")
# RACE(レース・成績・払戻など)を 2010年の1年ぶんだけ開く。option=4 はセットアップ
# 最初の1回はダイアログが出るので「持っていない」を選ぶ
args = ("RACE", "20100101000000-20110101000000", 4, 0, 0, "")
rc, read_count, download_count, last_ts = jv.JVOpen(*args)
if rc == -301: # ダイアログで選んだ直後は -301 が返ることがある。閉じて呼び直す
jv.JVClose()
rc, read_count, download_count, last_ts = jv.JVOpen(*args)
if rc != 0:
raise SystemExit(f"JVOpen に失敗 ({rc})")
# ダウンロードするファイルがあれば、終わるまで待つ
if download_count > 0:
while True:
n = jv.JVStatus()
if n < 0:
raise SystemExit(f"JVStatus に失敗 ({n})")
if n >= download_count:
break
pythoncom.PumpWaitingMessages()
time.sleep(1)
counts = {}
while True:
ret = jv.JVRead("", 110000, "")
code = ret[0]
if code > 0:
record = ret[1].encode("cp932") # Shift_JIS の固定長に戻す
kind = record[:2].decode("ascii") # 先頭2バイトがレコードの種類(RA、SE、HR など)
counts[kind] = counts.get(kind, 0) + 1
elif code == -1: # ファイルの切れ目
continue
elif code == 0: # すべて読み終えた
break
elif code == -3: # まだダウンロード中
pythoncom.PumpWaitingMessages()
time.sleep(0.5)
else:
raise SystemExit(f"JVRead に失敗 ({code})")
jv.JVClose()
print(counts)
RACEは、レース・成績・払戻などが入ったデータの種類です
ここでは2010年の1年ぶんだけを開いています
JVReadが返す1つ目の値は状態です
2つ目はレコード
- 0より大きい: レコードの長さ(2つ目にレコードが入っている)
- 0: すべて読み終えた
- -1: ファイルの切れ目
- -3: まだダウンロード中
バッファの110,000バイトは、いちばん長いレコード(H6、102,890バイト)が入る大きさで、SDKのサンプルと同じ値にしています
JV-Linkの呼び方と戻り値の受け方は、実際に動かしている私のツールと同じです
この最小の形も、11月3日にPython 3.13で流して確かめました
2010年の1年ぶんを読むのに約30秒(ファイルはダウンロード済み)で、払戻(HR)の3,454件はその年のJRAのレース数と同じです
実際のツールはこれにデータベースへの書き込みや再開の記録が加わった形
JVGetsはメモリが漏れるのでJVReadにした
最初は公式のPythonサンプルにならって、JVGetsで読んでいました
pywin32からJVGetsを呼ぶと、1件ごとにメモリが漏れます
渡したバッファも、返ってきたバッファも解放されないまま
漏れを測った環境(Python 3.12・pywin32 312・64bit版のJV-Link 5.0.0)では、110,000バイトのバッファで1件あたり108KB、空のバッファでも0.3KBずつ漏れました
10月24日のセットアップは、約56万件読んだところでMemoryError
仕様書のJVGetsの解説にも、「JVGets ではメモリの解放を行わないので、アプリケーション側で読み出しの度に解放する必要があります」との記述
VBならEraseで消せます
pywin32から解放する手段は、見つかりませんでした
※JV-Linkインターフェース仕様書 4.9.0.1 の28ページ、SDKに入っているPDFで確認
公式もJVGetsだけを勧めているわけではありません
サンプル(sample1_Python3.14 の Form2.py)には、JVReadの行がコメントで並んでいます
開発ガイドにも「JVGets ではなく JVRead を使って読み出すことも可能です」とあります
両方が示してあって、既定がJVGetsなだけでした
JVReadはJV-Linkの中で解放するので、漏れません
代わりに文字列がUnicodeで返ってくるので、cp932でバイト列に戻してから固定長のまま切ります
戻したバイト列が、JVGetsで読んだものと同じになることも確かめました
仕様書では、JVReadは中で文字コードを変換するぶん遅く、その対策として後からJVGetsが足されたと説明されています
速さならJVGetsです
それでもPythonから使うなら、漏れないJVReadを選びます
cp932まわりで迷ったときのことは、Pythonの文字化けとcp932の話にまとめてあります
メモリが増え続けて落ちるなら、まずJVGetsを疑ってみてください
全期間を一度に開くと遅いので1年ずつにした
RACEの2010年以降を1回のJVOpenで開いたら、読み出しが遅くなりました
| 開き方 | ファイル数 | 1件の読み出し |
|---|
| 2010年以降を1回で開く | 3,119 | 16〜30ms |
| 1年ぶんだけ開く | 158 | 0.1ms |
※どちらもJVGetsで読んでいたときの計測
1年ずつ開いても合計は同じ3,119ファイルで、重複も抜けもありませんでした
仕様書のJVOpenの「既知の障害について」には、データの種類を複数まとめて指定すると「対象ファイル数が多い場合に JVRead の処理時間が遅くなる」と書かれています
回避策は種類を1つずつ指定するか、fromtimeに開始と終了の両方を入れること
開始と終了は半角のハイフンでつなぎます(例: 20100101000000-20110101000000)
option=4のセットアップでも、この形で期間を区切れます
私のところではRACEの1種類だけでも遅くなったので、終了時刻をつけて1年ずつ開くことにしました
区切り方は前の回の終了を次の開始にして、最後の1回だけ終了時刻なしで今まで
開発ガイド(本編)4.2.3の【蓄積系ソフトセットアップデータ取得におけるFROM タイム指定】にある分け方です
終了時刻を付けられない種類(TOKU・DIFN・HOSN・HOYU・COMM など)だけは、1回で開きます
セットアップのダイアログは「持っていない」を選ぶ
option=4の名前は「ダイアログ無しセットアップ」
それでもプロセスごとに最初の1回、「スタートキット(CD/DVD-ROM)を持っている(推奨)」「持っていない」を選ぶダイアログが出て止まります
APIでも設定でも、これは消せませんでした
仕様書の書き方は「初回のみダイアログを表示します」
私の環境では、その「初回」がプロセスごとでした
同じプロセスで2回目に開くときは出ず、起動し直すとまた出ます
ここで「持っている(推奨)」を選ぶと、-501で止まります
スタートキットの提供は2022年3月で終了済みで、仕様書でも案内は「持っていない」のほう
「持っていない」を選べば、先へ進みます
手で選んだ直後のJVOpenだけ、-301(認証エラー)が返ることもありました
利用キーは正しく入っていました
すぐ呼び直すと通っています
私のツールには、このダイアログに自動で答える処理も入れてあります
途中で止めても続きから読める
1ファイル読み終えるごとに「取り込み済み」と記録しておき、次に開いたときはそのファイルをJVSkipで飛ばします
仕様書の「JVRead/JVGets の中断・再開」にある方法
ダウンロードしたファイルはJV-Linkの保存先(私の環境では C:\ProgramData\JRA-VAN\Data Lab)に残るので、やり直しても再ダウンロードは起きません
保存先と、ファイルを残すかどうかは、JV-Link設定で確かめられます
AIで仕事を減らしたい方へPR
AI鬼管理|Claude Code活用の業務自動化トレーニング
Claude Code を業務の自動化に使うためのトレーニングです
いきなり申し込む形ではなく、まずは無料の業務効率化診断(オンライン面談)から始められます
無料の業務効率化診断を見てみる
Notta|AI自動文字起こし
会議や動画の音声を自動で文字にするサービスです
議事録や書き起こしの手作業を減らしたいときに
Nottaを見てみる
毎日の差分取得は自動化できる 条件はログオンしたWindows
ログオンしたWindowsの上なら、ふだんの差分取得はダイアログなしで通ります
新しいバージョンの告知が出た日だけは、人が押すまで止まります
画面の無い環境、たとえばWindowsのサービスやLinuxのVPSで動かす方法は、公式には用意されていません
毎日の差分はoption=1(通常データ)で、前回の続きから開きます
セットアップと違って、こちらはダイアログが出ません
私のツールでも、毎日の差分取得はダイアログなしで通っています
ただし、JV-Linkはほかにもダイアログを出すことがあります
無人で回すときに止まる原因は、次の5つです(4つはダイアログ、1つはエラー)
| 止めるもの | 出るとき | 対処 |
|---|
| セットアップの取得元(スタートキット) | option=4のJVOpen、プロセスごとに最初の1回 | 「持っていない」を選ぶ |
| 新しいJV-Linkの告知 | 新しいバージョンが出ているときのJVOpen | 設定で消す方法は仕様書に無い |
| JRA-VANからのお知らせ | お知らせがあるときのJVOpen・JVRTOpen | JV-Link設定の「JRA-VAN からのお知らせを表示する」を外す |
| 払戻ダイアログ | 設定で表示にしているとき | 設定で外す |
| 保存先フォルダが無い | JVOpenのとき(-211で止まる) | 先に作っておく |
※JV-Linkインターフェース仕様書(13・17・18・20・21ページ)と、私の環境での確認から
毎日の差分で気をつけるのは、新しいバージョンの告知だけです
告知のダイアログで新しいバージョンのダウンロードを選ぶと、そのJVOpenは-1(該当データ無し)を返します
エラーにはなりません
その日の差分を取りこぼしていないかは、ログで見ておくと安心です
設定で消せない告知のダイアログがあるので、タスクスケジューラに登録するときは「ユーザーがログオンしているときのみ実行する」を選んでおくのがおすすめです
告知が出ても、画面のあるセッションなら押して先へ進められます
私はこの設定で、毎日20時に差分取得を回しています
初回のセットアップも、画面の前で流すのが無難です
画面の無い環境からセットアップを呼ぶとJVOpenが返ってこないとの報告が、開発者コミュニティに出ています(32bitのPythonでの報告)
11月3日の時点でも、スタッフからの答えはありません
もう1つの条件はWindowsそのもの
JV-LinkはWindows専用で、ARM版のWindowsにも対応していません
LinuxのVPSでは動かないので、JRA-VANのデータを取るにはWindowsが1台要ります
私は10月の終わりに、取り込みをWindows ServerのVPSへ移しました
Data Lab.の動作環境に書かれているのはWindows 10・11の日本語版だけですが、VPSでも毎日の差分取得は回っています
利用キーは1つの契約で2つ出るので、手元のPCとVPSで1つずつ使い分けています
VPSではRDPを閉じるときにサインアウトせず「切断」にします
サインアウトすると、「ログオンしているときのみ実行する」のタスクが動かなくなるためです
取り込めたデータ JRAのレースは1986年以降で約14万件
11月3日に数えた時点で、1986年以降のJRAの馬ごとの成績は1,882,521件、坂路の調教は約1,200万件になりました
| 表 | 件数 |
|---|
| レース(JRA、1986年以降) | 140,519 |
| 馬ごとの成績(JRA、1986年以降) | 1,882,521 |
| 払戻 | 140,097 |
| 坂路調教 | 11,994,894 |
※レースの表には地方・海外のレースも入っていて、それを含めると242,916件
最初に取り込んだのは2010年以降です
RACEは3,119ファイルで、そのうち3,086ファイルのダウンロードに3分あまり
読み込みはデータベースへの書き込みまで含めて1年ぶん3〜5分ほどでした(票数と3連複・3連単のオッズは読み飛ばし)
そのあと10月30日に、同じやり方で1986〜2009年を足しました
こちらは全部の種類を合わせて約40分
中身は連載#2でnetkeibaから集めたデータと突き合わせています
10月17日以降に届いた分で、72レースの距離と発走時刻が全部一致
905頭の着順・単勝オッズ・馬体重も一致し、合わなかった5頭は取消・除外・中止の書き方の違いでした
netkeibaのレースID(12桁)は、JV-Dataの年・場コード・回次・日次・レース番号を並べた値と同じです
netkeibaで集めたデータが手元にある人は、このIDでJRA-VANのデータとつなげられます
ひとつ引っかかったのは文字コード
私の環境では2つの表で文字コードが違っていて、結合のときにそろえる一手間が要りました
値はJV-Dataの文字列のまま入れています
オッズの「0013」は1.3倍、タイムの「1351」は1分35秒1
数値に直すのは使う側でやる形にしました
まとめ つまずきやすいエラーとClaudeに書かせるときの注意
2026年3月に一度諦めたJRA-VANは、64bit版のJV-Linkが出たことで、64bitのPythonからそのまま過去データを取り込めるようになりました
公式どおりで詰まったのは、JVGetsのメモリ・全期間の開き方・セットアップのダイアログの3つ
どれも仕様書に手がかりがありました
つまずきやすいエラー
| 戻り値 | 意味 | 対処 |
|---|
| -303 | 利用キーが設定されていない | JV-Link設定で利用キーを入れる |
| -303(キーを入れていても出る) | JV-Linkの内部のサービスが止まっている | JV-Link設定を管理者で開いて内部機能を「起動」する |
| -301(「持っていない」を選んだ直後) | 認証エラー | 呼び直す |
| -301(32bit版と同じキーを入れた) | 認証エラー | JV-Linkを入れ直して利用キーを再発行する |
| -501 | スタートキットが無効 | ダイアログで「持っていない」を選ぶ |
| -502 | ダウンロードの失敗、混雑時のタイムアウトでも出る | 時間をおいて流し直す |
| -504 | メンテナンス中 | 時間をおく |
| -402・-403 | ダウンロードしたファイルが壊れている | JVFiledeleteで消して取り直す |
私の環境で出たのは-303・-301・-501で、ほかは仕様書のコード表からです
-303は利用キーを入れていても出ることがあります
JRA-VANのスタッフも10月27日の開発者コミュニティでの回答で、JV-Linkの内部のサービスが予期せず止まって-303や-211になる事象を認めています
原因はまだ分かっていません
当面の回避策として案内されているのは、認証の処理(JVOpenなど)を呼ぶ直前に、サービスが動いているかを確かめて起動しておくことです
サービス名は、私の環境の64bit版では JVLink64Agent でした
64bit版の設定画面で「設定情報の更新に失敗しました」と出て保存できないとの報告も10月の終わりに相次いでいます
開発者コミュニティにはPythonから-413が出たとの報告もありますが、私の環境では一度も出ていません
Claudeに書かせるときの注意
私のツールはClaude Codeと一緒に作り、SDKの仕様書・構造体・登録クラスのサンプルを読ませて組み立てました
JVGetsの漏れも、実データで測って突き止めています
一方で、SDKのページには次の注記があります
生成AIによるコードや説明に起因する不具合につきましては、サポート対象外となります— JRA-VAN Data Lab. 開発者コミュニティ「ソフトウェア開発キット(SDK)」
Claudeが書いたコードで詰まったら、問い合わせる前に、SDKに入っているData Lab.検証ツールで同じデータが取れるかを確かめてください
検証ツールで取れるなら自作の側、取れないなら未配信・通信の妨げ・ローカルのデータの破損を疑います
この切り分けも、SDKのページに書かれています
AIの答えをそのままサポートへのメールやフォーラムに貼るのはやめておきましょう
初回のセットアップだけ画面の前で済ませれば、あとは毎日の差分を回すだけです
まずは2010年の1年ぶんだけ開いて、件数が出るところまで試してみてください
📚 私のおすすめ本PR
ジャンルごとに私のおすすめからランダムで5冊を表示しています
コメント