はじめに
競馬のデータ分析をテーマに、競走馬の成績や血統の情報を効率的に取得します。
目次
race_id_loader.py
ソースコード
import pickle
import re
from ..Constants.local_paths import data_dir_path
from .UI_helper import print_message
def load_race_ids(ym_list, master):
"""指定された年月リストに対応するレースIDをロード"""
ym_dict = group_months_by_year(ym_list)
race_id_dir = data_dir_path() / "RaceID"
race_id_list = []
missing_years = []
# 年ごとにレースIDファイルを取得
for year, months in ym_dict.items():
race_id_path = race_id_dir / f"race_id_{year}.pkl"
if not race_id_path.exists():
missing_years.append(year)
continue
# ファイルを開いてレースIDを取得
with open(race_id_path, "rb") as f:
race_ids = pickle.load(f)
# 各月に該当するレースIDを追加
for ym in months:
for item in race_ids:
date = item[1]
# 年月(yyyymm) + 日(dd)形式を確認
if re.fullmatch(ym + r"\d{2}", date):
race_id_list.append(item[0])
# 欠落年の警告表示
if missing_years:
print_message(
master,
f"以下の年のレースIDが見つかりません: {', '.join(missing_years)}。レース結果の取得・更新をしてください。",
)
return race_id_list
def group_months_by_year(ym_list):
"""年月リストを年ごとにグループ化(内包表記なし)"""
ym_strings = [f"{y}{str(m).zfill(2)}" for y, m in ym_list]
ym_dict = {}
# 年ごとにグループ化
for ym in ym_strings:
year = ym[:4]
if year not in ym_dict:
ym_dict[year] = []
ym_dict[year].append(ym)
return ym_dict
load_race_ids
関数の概要
group_months_by_year()
を使用し、年月リストを年ごとに分類。data_dir_path()
を用いてレースIDの保存ディレクトリを取得。- 各年のレースIDファイルを開き、指定された年月に対応するレースIDを抽出。
print_message()
を使用し、レースIDが見つからない年がある場合に警告を表示。
group_months_by_year
関数の概要
[yyyy, mm]
の形式で与えられた年月リストを年ごとに分類。dict
を使用して、各年のリストを管理。- 年月を
yyyymm
の文字列に変換し、年ごとにグループ化。
horse_html_fetcher.py
ソースコード
import pickle
from fake_useragent import UserAgent
from Libs.Constants.local_paths import data_dir_path
from Libs.Constants.URL_paths import UrlPaths
from .requests_helper import get_resp
from .UI_helper import print_message, update_progress
def horse_html_fetcher(race_id_list, master=None, overwrite=True):
print_message(
master,
"競争馬ページのHTMLを取得しています。...... ",
line_brake=False,
)
horse_id_list = horse_id_loader(race_id_list, master)
html_dir_path = data_dir_path() / "HTML" / "Horse"
html_dir_path.mkdir(parents=True, exist_ok=True)
if not horse_id_list:
return
user_agent = {"User-Agent": UserAgent().chrome}
total = len(horse_id_list)
for count, id in enumerate(horse_id_list, start=1):
# 保存パスを設定
html_path = html_dir_path / f"{id}_html.pkl"
# 既に保存済みのHTMLがある場合はスキップ
if not overwrite and html_path.exists():
continue
url = f"{UrlPaths.HORSE_URL}/{id}"
# 競走馬ページのHTMLを取得
resp = get_resp(url, user_agent)
if not resp:
continue
# HTMLデータを pickle で保存
with open(html_path, "wb") as f:
pickle.dump(resp, f)
# 進捗バーを更新
update_progress(master, count, total)
# 処理が終わったら進捗バーをリセット
update_progress(master, 0, 1)
print_message(master, "完了")
ped_html_fetcher(horse_id_list, master)
return horse_id_list
def ped_html_fetcher(horse_id_list, master=None):
print_message(
master,
"血統ページのHTMLを取得しています。...... ",
line_brake=False,
)
html_dir_path = data_dir_path() / "HTML" / "Ped"
html_dir_path.mkdir(parents=True, exist_ok=True)
user_agent = {"User-Agent": UserAgent().chrome}
total = len(horse_id_list)
print(total)
for count, id in enumerate(horse_id_list, start=1):
# 保存パスを設定
html_path = html_dir_path / f"{id}_html.pkl"
# 既に保存済みのHTMLがある場合はスキップ
if html_path.exists():
continue
url = f"{UrlPaths.PED_URL}/{id}"
# 血統ページのHTMLを取得
resp = get_resp(url, user_agent)
if not resp:
print(id)
continue
# HTMLデータを pickle で保存
with open(html_path, "wb") as f:
pickle.dump(resp, f)
# 進捗バーを更新
update_progress(master, count, total)
# 処理が終わったら進捗バーをリセット
update_progress(master, 0, 1)
print_message(master, "完了")
def horse_id_loader(race_id_list, master=None):
"""
レース結果データから馬IDを抽出して返す関数。
:param race_id_list: レースIDのリスト
:param master: GUIメッセージ用のオブジェクト
:return: horse_id_list(重複なし)
"""
# データディレクトリの指定
raw_result_dir_path = data_dir_path() / "Raw" / "Result"
horse_id_set = set()
# レースIDごとに処理
for race_id in race_id_list:
year = race_id[:4]
result_file_path = (
raw_result_dir_path / f"Result_{year}" / f"{race_id}_result_df.pkl"
)
# ファイル存在確認
if not result_file_path.exists():
print_message(master, f"ファイルが見つかりません: {result_file_path}")
continue # 次のレースIDを処理
# pklファイルを読み込む
try:
with open(result_file_path, "rb") as f:
df = pickle.load(f)
except Exception as e:
print_message(master, f"ファイル読み込みエラー: {result_file_path}, {e}")
continue
# horse_idを抽出してセットに追加
for horse_id in df["horse_id"].tolist():
if isinstance(horse_id, str) and horse_id.isdigit():
horse_id_set.add(horse_id)
# 結果をリストで返す
horse_id_list = list(horse_id_set)
return horse_id_list
horse_html_fetcher
関数の概要
horse_id_loader()
を使用して、レース結果データから競走馬のIDを抽出。data_dir_path()
を用いてHTMLデータの保存ディレクトリを作成。requests_helper.get_resp()
を利用し、競走馬のHTMLページを取得。pickle
を使用して取得したデータを保存。update_progress()
で進捗を管理し、ユーザーに通知。
ped_html_fetcher
関数の概要
horse_html_fetcher()
によって収集された競走馬IDリストを使用。- 指定された競走馬の血統ページ (
Ped_URL
) のHTMLデータを取得。 - データを
pickle
形式で保存。 update_progress()
を利用して進捗を管理。
horse_id_loader
関数の概要
- レース結果データ (
Result
) から競走馬のIDを抽出。 - 既存のデータから
horse_id
を取得し、リスト化。 pickle
で保存されたレース結果データをロードし、馬IDを抽出。
horse_parser.py
ソースコード
import pickle
from fake_useragent import UserAgent
from Libs.Constants.local_paths import data_dir_path
from Libs.Constants.URL_paths import UrlPaths
from .requests_helper import get_resp
from .UI_helper import print_message, update_progress
def horse_html_fetcher(race_id_list, master=None, overwrite=True):
print_message(
master,
"競争馬ページのHTMLを取得しています。...... ",
line_brake=False,
)
horse_id_list = horse_id_loader(race_id_list, master)
html_dir_path = data_dir_path() / "HTML" / "Horse"
html_dir_path.mkdir(parents=True, exist_ok=True)
if not horse_id_list:
return
user_agent = {"User-Agent": UserAgent().chrome}
total = len(horse_id_list)
for count, id in enumerate(horse_id_list, start=1):
# 保存パスを設定
html_path = html_dir_path / f"{id}_html.pkl"
# 既に保存済みのHTMLがある場合はスキップ
if not overwrite and html_path.exists():
continue
url = f"{UrlPaths.HORSE_URL}/{id}"
# 競走馬ページのHTMLを取得
resp = get_resp(url, user_agent)
if not resp:
continue
# HTMLデータを pickle で保存
with open(html_path, "wb") as f:
pickle.dump(resp, f)
# 進捗バーを更新
update_progress(master, count, total)
# 処理が終わったら進捗バーをリセット
update_progress(master, 0, 1)
print_message(master, "完了")
ped_html_fetcher(horse_id_list, master)
return horse_id_list
def ped_html_fetcher(horse_id_list, master=None):
print_message(
master,
"血統ページのHTMLを取得しています。...... ",
line_brake=False,
)
html_dir_path = data_dir_path() / "HTML" / "Ped"
html_dir_path.mkdir(parents=True, exist_ok=True)
user_agent = {"User-Agent": UserAgent().chrome}
total = len(horse_id_list)
print(total)
for count, id in enumerate(horse_id_list, start=1):
# 保存パスを設定
html_path = html_dir_path / f"{id}_html.pkl"
# 既に保存済みのHTMLがある場合はスキップ
if html_path.exists():
continue
url = f"{UrlPaths.PED_URL}/{id}"
# 血統ページのHTMLを取得
resp = get_resp(url, user_agent)
if not resp:
print(id)
continue
# HTMLデータを pickle で保存
with open(html_path, "wb") as f:
pickle.dump(resp, f)
# 進捗バーを更新
update_progress(master, count, total)
# 処理が終わったら進捗バーをリセット
update_progress(master, 0, 1)
print_message(master, "完了")
def horse_id_loader(race_id_list, master=None):
"""
レース結果データから馬IDを抽出して返す関数。
:param race_id_list: レースIDのリスト
:param master: GUIメッセージ用のオブジェクト
:return: horse_id_list(重複なし)
"""
# データディレクトリの指定
raw_result_dir_path = data_dir_path() / "Raw" / "Result"
horse_id_set = set()
# レースIDごとに処理
for race_id in race_id_list:
year = race_id[:4]
result_file_path = (
raw_result_dir_path / f"Result_{year}" / f"{race_id}_result_df.pkl"
)
# ファイル存在確認
if not result_file_path.exists():
print_message(master, f"ファイルが見つかりません: {result_file_path}")
continue # 次のレースIDを処理
# pklファイルを読み込む
try:
with open(result_file_path, "rb") as f:
df = pickle.load(f)
except Exception as e:
print_message(master, f"ファイル読み込みエラー: {result_file_path}, {e}")
continue
# horse_idを抽出してセットに追加
for horse_id in df["horse_id"].tolist():
if isinstance(horse_id, str) and horse_id.isdigit():
horse_id_set.add(horse_id)
# 結果をリストで返す
horse_id_list = list(horse_id_set)
return horse_id_list
horse_parser
関数の概要
- 競走馬の戦績ページのHTMLデータをロード。
BeautifulSoup
を用いてHTMLを解析。pandas.read_html()
を使用し、テーブルデータをDataFrame
に変換。- 取得したデータを
pickle
で保存し、進捗状況をupdate_progress()
で管理。
ped_parser
関数の概要
horse_parser()
によって収集された競走馬IDリストを使用。- 指定された競走馬の血統ページ (
Ped_URL
) のHTMLデータをロード。 BeautifulSoup
を用いてHTMLを解析し、血統データをDataFrame
に変換。- 取得したデータを
pickle
形式で保存し、進捗を管理。
コメント