Otama's Playground

AIで遊んだ結果などをつらつら載せていきます。

競馬予想AIのためのデータ収集!スクレイピングからデータベース保存まで

スクレイピング後のデータ保存、データ処理の効率を行うためにデータベースに保存することにしようと思います。

今回はデータベースのDDLとpythonスクリプトの作成、そして実際にデータベースを立ち上げて保存するまでを行います。

内容的には以下の記事の続きです。

otama-playground.com

保存するデータ

  • レースID
  • レース情報
  • レース結果
  • レースの払い戻しデータ

生データとしていったん文字列のままで入れてしまいます

データ構造

一旦こんな感じにします。不都合があれば後で変える

データ構造

テーブル定義

下記sqlの通り

github.com

運用方法

複数回同じページへのリクエストが発生してしまうのを防ぐため、以下のような3段階にします。

  1. レースIDテーブルにレースIDをポンポン入れていく
  2. レースIDテーブルから未処理のレースIDを取得し、一個一個スクレイピングしDB保存。
  3. DB保存まで終わったらスクレイピング済フラグを立てる

ソースコード

全部乗せると多いので以下のリポジトリに現状のコードをアップロードしました。少しだれたのでエラー制御とか甘いですが、許してください...

github.com

結果

レースIDテーブル

処理済みのレコードだけscraped_atが登録されます。

mysql> select * from raw_races limit 100,10;
+-----+------------------+---------------+---------------+
| id  | netkeiba_race_id | scraped_at    | created_at    |
+-----+------------------+---------------+---------------+
| 115 |     202404030101 | 1724596983971 | 1724580995896 |
| 116 |     202407020305 | 1724596985399 | 1724580995897 |
| 117 |     202407020102 | 1724596986607 | 1724580995898 |
| 118 |     202404020407 | 1724596987931 | 1724580995898 |
| 119 |     202407020402 |          NULL | 1724580995899 |
| 120 |     202404030312 |          NULL | 1724580995900 |
| 121 |     202401020111 |          NULL | 1724580995901 |
| 122 |     202407020412 |          NULL | 1724580995902 |
| 123 |     202401020406 |          NULL | 1724580995903 |
| 124 |     202407020209 |          NULL | 1724580995903 |
+-----+------------------+---------------+---------------+

レース情報テーブル

mysql> select * from raw_race_informations LIMIT 10;
+----+-------------+-------------+-----------------+--------------+--------------------+----------------+------------------+-------------------+-------------------------+--------------------------+
| id | raw_race_id | race_number | race_condition  | weather      | track_condition    | starting_time  | race_date        | event_name        | race_class              | race_type                |
+----+-------------+-------------+-----------------+--------------+--------------------+----------------+------------------+-------------------+-------------------------+--------------------------+
|  1 |          15 | 8R          | 芝左2200m       | 天候 : 晴    | 芝 : 良            | 発走 : 16:20   | 2024年8月4日     | 2回新潟4日目      | 3歳以上1勝クラス        | (混)(特指)(定量)         |
|  2 |          16 | 12R         | 芝左1200m       | 天候 : 晴    | 芝 : 良            | 発走 : 16:15   | 2024年8月11日    | 2回中京2日目      | 3歳以上2勝クラス        | (混)[指](定量)           |
|  3 |          17 | 3R          | 芝右1200m       | 天候 : 曇    | 芝 : 良            | 発走 : 10:55   | 2024年8月17日    | 2回札幌3日目      | 3歳未勝利               | (混)[指](馬齢)           |
|  4 |          18 | 8R          | 芝右2600m       | 天候 : 晴    | 芝 : 良            | 発走 : 13:45   | 2024年8月10日    | 2回札幌1日目      | 3歳以上1勝クラス        | (特指)(定量)             |
|  5 |          19 | 10R         | ダ右1700m       | 天候 : 曇    | ダート : 良        | 発走 : 15:01   | 2024年8月3日     | 1回札幌5日目      | 3歳以上2勝クラス        | (混)[指](ハンデ)         |
|  6 |          20 | 7R          | ダ右1000m       | 天候 : 晴    | ダート : 良        | 発走 : 13:15   | 2024年8月3日     | 1回札幌5日目      | 3歳以上1勝クラス        | (混)[指](定量)           |
|  7 |          21 | 11R         | 芝左 外1600m    | 天候 : 晴    | 芝 : 良            | 発走 : 15:45   | 2024年8月11日    | 3回新潟2日目      | 3歳以上オープン         | (国際)(特指)(別定)       |
|  8 |          22 | 11R         | ダ右1700m       | 天候 : 曇    | ダート : 稍重      | 発走 : 15:35   | 2024年8月4日     | 1回札幌6日目      | 3歳以上オープン         | (国際)(指)(別定)         |
|  9 |          23 | 2R          | ダ右1700m       | 天候 : 曇    | ダート : 良        | 発走 : 10:25   | 2024年8月17日    | 2回札幌3日目      | 2歳未勝利               | [指](馬齢)               |
| 10 |          24 | 2R          | ダ右1700m       | 天候 : 曇    | ダート : 良        | 発走 : 10:20   | 2024年8月3日     | 1回札幌5日目      | 3歳未勝利               | [指](馬齢)               |
+----+-------------+-------------+-----------------+--------------+--------------------+----------------+------------------+-------------------+-------------------------+--------------------------+

レース結果テーブル

人名とかのため載せません

レース払い戻しテーブル

mysql> select * from raw_race_payouts LIMIT 10;

+----+-------------+-------------+---------------------+-------------+----------+
| id | raw_race_id | payout_type | horse_number        | payout      | favorite |
+----+-------------+-------------+---------------------+-------------+----------+
|  1 |          15 | 単勝        | 4                   | 170         | 1        |
|  2 |          15 | 複勝        | 4;3;12              | 110;160;130 | 1;3;2    |
|  3 |          15 | 枠連        | 3 - 3               | 490         | 2        |
|  4 |          15 | 馬連        | 3 - 4               | 480         | 2        |
|  5 |          15 | ワイド      | 3 - 4;4 - 12;3 - 12 | 220;170;490 | 2;1;7    |
|  6 |          15 | 馬単        | 4 → 3               | 650         | 2        |
|  7 |          15 | 三連複      | 3 - 4 - 12          | 670         | 1        |
|  8 |          15 | 三連単      | 4 → 3 → 12          | 2,530       | 3        |
|  9 |          16 | 単勝        | 2                   | 440         | 2        |
| 10 |          16 | 複勝        | 2;1;9               | 150;180;140 | 2;4;1    |
+----+-------------+-------------+---------------------+-------------+----------+

最後に

今回はスクレイピングしてきた生データをデータベースに保存するところまで作業してみました。

TODO

  • レース結果に紐づくウマデータ、騎手データのスクレイピング
  • データベースに保存した生データに前処理を加えて学習しやすい形に成形する