1. はじめに
ボートレースの情報を扱う上で、公式サイトや各種データサイトをスクレイピングして、レースごとの開催情報を蓄積し分析に活かすという流れは、非常に有用です。
しかしながら、各レースにはグレード(SG・G1・G2・G3・一般戦など)や特別な冠レース(レディース戦・マスターズリーグ・ルーキーシリーズ・ヴィーナスシリーズなど)が存在し、開催場や開催日程の表記方法もサイトごとにバラバラです。
そのままの形では分析しづらいので、「何月何日から何月何日まで開催されているのか」「どのボートレース場で開催されているのか」「どのようなグレードのレースか」をきちんと整理したデータを構築する必要があります。
今回取り組んだのは、HTMLをパースしてレースごとの詳細情報を取得し、それらをpandasのデータフレームへと落とし込んだ上で、グレードや開催場などの追加情報を画像タグや正規表現から抽出するという工程です。
さらに、開催日が「MM/DD – MM/DD」といった表記になっているケースが多かったため、開始日と終了日を別々の列にして「YYYYMMDD」形式に整形する作業も行いました。
最後に、レディース戦・マスターズリーグ・ルーキーシリーズといった区分を判別し、それぞれに色付け(カテゴライズ)を行うことで、レース一覧表の一元管理・可視化をしやすくしています。
2. なぜ色付け(カテゴライズ)が必要か
ボートレースのレース分析を深めていくと、「女子戦が得意な選手」や「ベテラン勢が中心となるマスターズリーグでの成績がいい選手」など、グレードやレース種別ごとに特徴が明確に分かれることに気づきます。
また、投票する際にも、「これはレディース戦なので、女子選手のみで構成される」「ルーキーシリーズだから若手選手が多く、スタート力勝負になりやすい」などの背景を知っておくと、配当面や展開面でのヒントになります。
色付け(あるいはラベル付け)しておくことで、
- 一覧表示したときに視覚的に把握しやすい
- 分析の際にも「レディース戦だけ抽出」「ルーキーシリーズだけを対象に成績を比較」といったフィルタ処理が簡単になる
というメリットがあります。
3. HTMLパースによるレース情報の取得
3.1 取得対象データの例
公式HPなどから取得したレース情報としては、以下のような要素をイメージしています。
- 開催日(例:09/24 – 09/29 のように範囲表記)
- 大会タイトル(例:「第○回G1 ○○杯」など)
- ボートレース場(例:大村、浜名湖、住之江など)
- グレード(SG / G1 / G2 / G3 / 一般 / その他特殊戦など)
これらの情報は、HTML上にテキストで書かれているだけでなく、画像タグとして埋め込まれている場合も多いため、通常のスクレイピングではテキスト部分しか取得できず、工夫が必要になります。
3.2 pandasのデータフレームでの管理
Pythonでスクレイピングする際、まずは requests
モジュールでHTMLを取得し、BeautifulSoup
や lxml
などを使ってタグ解析を行います。
タグ名やクラス名で該当箇所を特定できる場合は比較的楽ですが、今回のように一部情報(ボートレース場名やグレードなど)が画像ファイル名や画像のalt属性にしか記載されていない場合は、正規表現を用いてタグの属性を抜き出す方法が有効です。
取得した各レース情報を、pandasのデータフレームに以下のようにして格納しました。
レースタイトル 開催日 ボートレース場 グレード 開始日 終了日 色付け
-----------------------------------------------------------
○○記念G1 09/24-09/29 大村 G1 20230924 20230929 レディース戦
△△ルーキーシリーズ 09/26-10/01 浜名湖 一般 20230926 20231001 ルーキーシリーズ
...
こうしておけば、Pythonのコード内で df['レースタイトル']
などの列をアクセスしやすく、後述の色付け作業もフラグ管理がしやすくなります。
4. 日付データの分割と整形
4.1 開催日の表記フォーマット
多くの場合、「MM/DD – MM/DD」という表記で示されることが多いですが、月をまたぐケース(例:09/30 – 10/05)や、公式サイトによってはスペースや全角文字が混在しているケースもあります。
そのため、以下のようなステップで日付の分割・整形を行いました。
- 「-」で左右に分割し、開始日(Left)と終了日(Right)に分ける
- 開始日と終了日の年月を考慮し、年間をまたぐ場合はどう扱うか(ボートレースは年末に開催され、年始に終了する場合などもある)
- YYYYMMDD形式に統一する(Pythonのdatetimeなどを用いるか、文字列操作で簡単に行う)
実際のPythonコード例(イメージ)では、以下のように処理しました。
date_str = "09/24-09/29" # 例
start_str, end_str = date_str.split("-") # -> "09/24", "09/29"
# 年の推定: 直近の開催と仮定し、2023年とする(厳密には開催年を取得する必要あり)
year = "2023"
# "09/24" -> "0924" を "20230924" に変換
start_mmdd = start_str.strip().replace("/", "")
end_mmdd = end_str.strip().replace("/", "")
start_date = year + start_mmdd # "20230924"
end_date = year + end_mmdd # "20230929"
# これをデータフレームの新しい列に代入
df.loc[i, '開始日'] = start_date
df.loc[i, '終了日'] = end_date
4.2 年度跨ぎや月跨ぎの考慮
- 9月末から10月頭にかかる開催なら、開始日は「20230930」、終了日は「20231005」のようになる。
- 12月下旬から翌年1月初旬にかかる開催なら、年度を判別する追加処理が必要。
- 公式サイトなどで「開催年度」や「西暦何年大会」などが掲載されている場合は、そこから年情報を取得して合わせるのが理想的。
こういった細かい例外にも柔軟に対応できるよう、単純な文字列操作だけでなく、正規表現やdatetimeモジュールを状況に応じて使い分けています。
5. 画像タグの正規表現処理
5.1 画像タグの例
公式サイト上で、ボートレース場やグレード名は以下のようなimgタグで表現されている場合があります。
<img width="45" height="16" alt="大村" src="/static_extra/pc/images/text_place1_24.png"/>
<img width="45" height="16" alt="16" src="/static_extra/pc/images/text_place1_24.png"/>
ここで alt="大村"
という文字列がボートレース場を示していたり、alt="16"
が何らかのIDを示していたりします。
また、グレード(SG, G1, G2, G3, 一般)に相当する画像タグが用意されている場合もあり、ページを眺めながら正規表現で抽出できるルールを定義していきます。
5.2 正規表現の書き方
たとえば、alt="(.*?)"
の部分をキャプチャするような形でマッチさせると、Pythonで言えば re.search(r'alt="(.*?)"', html_string)
などで抽出が可能です。
取得した文字列を、たとえば「大村」や「16」といったボートレース場IDに紐づけたり、グレード(SG, G1, G2, G3, 一般など)をマッピングしたりします。
もし以下のように複数のタグが連続していたり、同じ行に複数存在したりする場合は、re.findall()
を使って一括抽出して、最初に出現する文字列を採用する、もしくはタグごとにパースして情報を統合する、といった工夫をします。
<td class="is-p10-0 is-G1a"></td>
<img width="45" height="16" alt="大村" src="..."/>
最終的に、「ボートレース場=大村」「グレード=G1」と認識させて、データフレームに「場」「グレード」という列を追加します。
6. 色付け(カテゴライズ)の実装
6.1 分類条件の決定
今回の例では、以下のようなルールを仮定しています。
- レディース戦:タイトルや大会名に「レディース」「女子」「レディ」などの文字列が含まれる
- マスターズリーグ:タイトルに「マスターズ」「シニア」など
- ルーキーシリーズ:タイトルに「ルーキーシリーズ」や「ヤング」「新人」など
- それ以外:上記に該当しない一般戦・Gレース
現実にはタイトル表記がバラバラだったり、特殊な冠名がついていたりするので、実務上はより多くの正規表現パターンや手動ラベル付けも組み合わせる必要があります。
6.2 データフレームへの追加
レディース戦に該当すれば df.loc[i, '色付け'] = 'レディース戦'
のように書き込んでいきます。複数のパターンが該当するなら優先度をつける、あるいはカンマ区切りで両方入れる、といった運用も可能です。
最終的には、先ほどのデータフレーム例に「色付け」という列が加わる形です。
レースタイトル 開催日 ボートレース場 グレード 開始日 終了日 色付け
-----------------------------------------------------------
○○記念G1 09/24-09/29 大村 G1 20230924 20230929 レディース戦
△△ルーキーシリーズ 09/26-10/01 浜名湖 一般 20230926 20231001 ルーキーシリーズ
...
7. 今後の展望
今回の作業を経て、レース一覧に「色付け」情報を加えることで、レディース戦やルーキーシリーズに特化した成績分析が一段としやすくなりました。
たとえば今後は下記のような展開が考えられます。
- レディース戦だけを抽出して、女子選手の勝率・スタート傾向・配当の傾向などを比較
- マスターズリーグではベテラン勢のイン逃げ率が高いのか、あるいは差し決着が多いのかを統計的に洗い出す
- ルーキーシリーズだけ集計し、若手選手の成長度や特徴をモデル化する
- 場×グレード×カテゴリの掛け合わせで、「大村のマスターズリーグは他場に比べてどう違うか」など深掘り分析が可能
さらに、日付のYYYYMMDD整形を行ったことで、時系列の扱いが格段に楽になります。
「年間を通して特定のシリーズがいつ開催されやすいか」「同じ期間でも場が違うと開催日が重複するのか」といったことを可視化する際に、日付が数値型として扱えるのは非常に大きなメリットです。
8. まとめ
本記事では、公式サイトのHTMLをパースしてボートレースのレース一覧を作成し、さらに日付整形や画像タグからのグレード・ボートレース場情報の取得、そしてレディース戦・マスターズリーグ・ルーキーシリーズなどの色付け(カテゴライズ)を行う流れを紹介しました。
- HTMLパースと正規表現を駆使することで、テキスト情報はもちろん、imgタグのalt属性といった表層的には見えにくい部分のデータも抽出
- 日付フォーマット整形(MM/DD – MM/DD → YYYYMMDD)により、分析対象として取り扱いやすい形にした
- グレードやシリーズといったレースの特徴を列追加し、さらに色付け(カテゴライズ)でレースの見やすさやフィルタリングを向上
これらの取り組みによって、より詳細なレース分析や予想モデルの構築が行いやすくなります。
今後は、ここで作ったデータをベースにして、「どのシリーズでどの選手が強いのか」「グレード別の高配当率はどう違うのか」といった深掘り分析を進め、より高度な予想モデルを作ることも検討できるでしょう。
また、現在はPythonのpandasデータフレームで管理していますが、データ量が増えてきたらRDBやクラウド上でのデータ管理に移行し、自動化バッチを組んで定期的に情報を更新する仕組みづくりも目指せます。
本記事が、ボートレースのレース情報収集・整形・可視化やシリーズ分類に興味をお持ちの方のお役に立てれば幸いです。
引き続き、データエンジニアリングや機械学習の観点からも、今回のデータを活用して面白い分析に挑戦し、発見を共有していきたいと思います。
コメント