JRAのCNAMEパラメータを縦に取得!Power Queryでリスト展開とループ処理【ソースコード公開】
三流プログラマーのKen3です。
今回は、JRAのオッズ取得に向けた「CNAMEパラメータ」の抽出に再チャレンジします。
前回までは開催ごとの取得でしたが、今回はさらに一歩踏み込んで、**「開催場所」×「馬券の種類(単勝・馬連・3連複など)」×「レース番号」**の組み合わせで、縦一列にCNAMEをズラッと書き出す処理を作りました。

「手作業でやると面倒な繰り返し処理」こそ、Power Queryの真骨頂です。
今回のライブ動画(2倍速推奨)
先に完成形ソースコード
解説の前に、まずは動くコードを載せておきます。
今回は2つのクエリ(関数側とメイン処理側)を使います。
1. 関数側クエリ:開催と種類別にCNAME取得
空のクエリを作成し、名前を必ず「''開催と種類別にCNAME取得''」に変更してから、詳細エディターに貼り付けてください。
// 関数化して開催地別、馬券の種類別のCNAMEを返す 2026/01/31テスト
// 関数で引数を受け取り、テーブルを返す
(str開催地CNAME as text, str開催地と開催日 as text, str馬券種類 as text) as table =>
let
// JRAホームページからソースを取得する POST送信で結果を受け取る
strURL = "https://www.jra.go.jp/JRADB/accessO.html",
// 引数で受け取った開催地のCNAMEをパラメーターとする 26/01/25修正
strCNAME = "cname=" & str開催地CNAME,
strPARA = Text.ToBinary(strCNAME),
strHEAD = [#"Content-Type"="application/x-www-form-urlencoded"],
ソース = Web.Contents(strURL, [Headers = strHEAD, Content = strPARA]),
文字列 = Text.FromBinary(ソース, 932),
HTMLソース = Lines.FromText(文字列),
// 現在時刻を取得し、文字列に変換
現在時刻 = DateTime.ToText(DateTime.LocalNow()),
LISTの頭に時刻を追加 = {"取得時刻"} & {現在時刻} & HTMLソース,
// LISTをテーブルに変換して、フィルターをかける
テーブルに変換済み = Table.FromList(LISTの頭に時刻を追加, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
// 馬券の種類でフィルターをかける
フィルターされた行 = Table.SelectRows(テーブルに変換済み, each Text.Contains([Column1], "Action") and Text.Contains([Column1], str馬券種類)),
// 5.2 doActionのパラメーターを抜き出し CNAMEを取得
条件3_1 = "doAction('/JRADB/accessO.html', '",
条件3_2 = "'",
CNAMEを追加 = Table.AddColumn(フィルターされた行, "CNAME", each Text.BetweenDelimiters([Column1], 条件3_1, 条件3_2)),
//5.1 レース番号の作成 ダミーの連番インデックス列を追加します (0から始まる連番が振られます)
インデックス列の追加 = Table.AddIndexColumn(CNAMEを追加, "Index", 0, 1),
//インデックス列が0からなので、+1してColumn2を作成します
レース番号を追加 = Table.AddColumn(インデックス列の追加, "レース番号", each Number.ToText([Index] + 1) & "レース"),
//場所を追加する
追加された場所 = Table.AddColumn(レース番号を追加, "今週の開催地", each str開催地と開催日),
//馬券の種類を追加する
追加された種類 = Table.AddColumn(追加された場所, "馬券の種類", each str馬券種類),
//不要な列を削除する
列削除 = Table.RemoveColumns(追加された種類,{"Column1", "Index"}),
//最終的な結果
結果 = 列削除
in
結果
2. メイン処理クエリ
こちらが実行用です。名前は何でも構いません。
//--- JRAオッズのTOPページを取得する パワークエリ 26/01/31テスト
// メイン処理:開催日を取得し、リスト展開してループ処理へ渡す
let
// JRAホームページからソースを取得する POST送信で結果を受け取る
strURL = "https://www.jra.go.jp/JRADB/accessO.html",
strPARA = Text.ToBinary("cname=pw15oli00/6D"),
strHEAD = [#"Content-Type"="application/x-www-form-urlencoded"],
ソース = Web.Contents(strURL, [Headers = strHEAD, Content = strPARA]),
文字列 = Text.FromBinary(ソース, 932),
HTMLソース = Lines.FromText(文字列),
テーブルに変換済み = Table.FromList(HTMLソース, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
フィルターされた行 = Table.SelectRows(テーブルに変換済み, each Text.Contains([Column1], "Action") and Text.Contains([Column1], "回")),
条件2_1 = "accessO.html', '",
条件2_2 = "');"">",
Column2を追加 = Table.AddColumn(フィルターされた行, "CNAME", each Text.BetweenDelimiters([Column1], 条件2_1, 条件2_2)),
// Column3を作成 '</i>' と '</a></div>' の間のテキスト(開催場所)を抽出
条件3_1 = "</i>",
条件3_2 = "</a></div>",
Column3を追加 = Table.AddColumn(Column2を追加, "開催", each Text.BetweenDelimiters([Column1], 条件3_1, 条件3_2)),
// 最終的な結果の整形
結果 = Column3を追加,
削除された列 = Table.RemoveColumns(結果,{"Column1"}),
// ★ここがポイント:馬券の種類をリストで追加
追加されたカスタム = Table.AddColumn(削除された列, "馬券の種類", each { "単勝","馬連","3連複" }),
// ★リストを展開して行を増やす
T開催取得 = Table.ExpandListColumn(追加されたカスタム, "馬券の種類"),
// ソースのクエリー結果(テーブル)をレコードのリストに変換
lst処理リスト = Table.ToRecords(T開催取得),
// ループ処理:List.Transformで順番に関数を呼び出す
テーブル一覧 = List.Transform(
lst処理リスト,
each 開催と種類別にCNAME取得(_[CNAME], _[開催], _[馬券の種類])
),
// 結合:テーブルのリストを一つにつなげる
t_all = Table.Combine(テーブル一覧)
in
t_all
今回のポイント解説
1. リストを追加して「行展開」が便利すぎる
Power Queryで「ある列の値に基づいて行を複製したい(例:S, M, Lサイズなど)」という場合、リスト形式で列を追加して展開する方法が非常に便利です。
今回はメイン処理で以下のように書いています。
each { "単勝","馬連","3連複" }こうすることで、1つの開催場所に対して3行(単勝用、馬連用、3連複用)のデータが自動生成されます。
「先輩たちがよく言っている『リスト追加して行展開すれば楽じゃん』というのはこのことか!」と実感しました。
このあたりの実際の操作は、動画の以下の部分で実演しています。
[11:09 リストを追加して行展開の実演を見る](https://www.youtube.com/watch?v=tC_84sHW3dg&t=669s)
2. 「3連複」の罠
コードを書いている最中にハマったのが「3連複」の文字です。
JRAのサイト上では「3連複」(半角数字の3)で処理されている部分と、表示上の「三連複」(漢数字)が混在しており、フィルタリング条件を間違えるとデータが空になって焦ります。
私がライブ中に冷や汗をかいたシーンはこちら(笑)。
[29:34 3連複の漢字と数字の違いにハマる](https://www.youtube.com/watch?v=tC_84sHW3dg&t=1774s)
残された課題(バグ報告)
無事に動いたように見えますが、実は重大なバグ(仕様上の考慮漏れ)があります。
「土曜日に日曜日の前日発売分を取得すると、メインレース(11R)しかないのに、1レース目として出力されてしまう」**
レース番号を単純に「Index + 1」で振ってしまっているため、データが1行しかないと、それが何レースであっても「1レース」と名付けてしまうのです。これは三流プログラマーあるあるですね……。
[41:31 不具合発覚!視聴者の「おいおい」という声が聞こえる瞬間](https://www.youtube.com/watch?v=tC_84sHW3dg&t=2491s)
このあたりの修正や、無駄なループ処理(同じページを何度も読みに行っている)の改善は、次回の課題とします。
関連リンク
- [URL:https://www.youtube.com/playlist?list=PLBFC80A8658C305CE:title=Ken3のJRAオッズ取得関連 再生リスト]
試行錯誤の様子も含めて楽しんでいただければ幸いです。もし「こうした方がいいよ!」というアドバイスがあれば、ぜひYouTubeのコメント欄で教えてください。