【スクレイピング】netkeibaから競走馬の競争成績を取得|競馬AI作成:③-4

競馬AI

本記事の目的

本記事は、下記事項を目的としています。

目的
  • 「netkeiba.com」から競走馬の競争成績を取得する

競走馬の競争成績

作業概要

以降では、下記の手順で「netkeiba.com」から競走馬の競争成績を取得します。

  • ①競走馬IDリストを作成

    ※データ取得先のURLを作成するために必要となります。

  • 競走馬の競争成績を入手

①競走馬IDリスト作成

horse_id_list = race_result['競走馬ID'].unique()

解説

競走馬の競争結果のURLは、下記の構成になっています。

そのため、複数の競走馬データを取得するには、まず競走馬IDを取得する必要があります。

前回の記事で作成した「race_result」に競争馬IDが含まれているので、本処理ではそこから競走馬IDを抽出します。

変数名 説明
race_result DataFrame レース結果

「race_result」の取得方法については、↓の記事で紹介しているのでまずは読んでみてください。

実行結果

②競走馬の競争成績を入手

#メソッド:競走馬の競争成績を取得
def get_horse_result(horse_id_list):
    
  #初期値を設定
    horse_result = pd.DataFrame()
    date_id_list = []
    area_id_list = []
    race_id_list = []
    jockey_id_list = []
    win_horse_id_list = []
    
    for horse_id in tqdm(horse_id_list):#・・・・・・・・・・・・・・・・・・・・・・(※1)
        time.sleep(1)# ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・(※2)
     
        try:
            #競争成績を取得
            url = 'https://db.netkeiba.com/horse/result/' + horse_id
            df = pd.read_html(url)[0] #・・・・・・・・・・・・・・・・・・・・・・・(※3)
            
            #競走馬IDを追加
            df['競走馬ID'] = [horse_id] * len(df)
            
            #WEBデータを解析・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・(※4)
            html = urllib.request.urlopen(url).read()
            soup = BeautifulSoup(html, 'html.parser')
            a_all = soup.find_all('a')
            
            cnt = 0        
            for a in a_all:
                try:
                    href = a.attrs['href']
                    text = a.text
                    href_split = href.split('/')
                    
                    #「日付ID」を取得・・・・・・・・・・・・・・・・・・・・・・・・・(※4)
                    if 'race' in href and 'list' in href and len(href) == 20:
                        date_id_list.append(href_split[-2])
                        
                    #「競馬場ID」を取得 ・・・・・・・・・・・・・・・・・・・・・・・・(※4)
                    elif 'race' in href and 'sum' in href and len(href) == 22:
                        area_id_list.append(href_split[-3])
                        
                    #「レースID」を取得 ・・・・・・・・・・・・・・・・・・・・・・・・(※4)
                    elif 'race' in href and len(href) == 19:
                        race_id_list.append(href_split[-2]) 
                        
                    #「騎手ID」を取得 ・・・・・・・・・・・・・・・・・・・・・・・・・(※4)
                    elif 'jockey' in href and len(href) == 14:
                        jockey_id_list.append(href_split[-2])
                                                                
                    #「勝ち馬ID」を取得 ・・・・・・・・・・・・・・・・・・・・・・・・(※4)
                    if 'horse' in href and len(href) == 18:
                        cnt = cnt + 1   
                        if cnt > 1:
                            win_horse_id = href_split[-2]

                            #テキストに「(」が含まれている場合は、win_horse_idに置換する
                            if '(' in text:
                                win_horse_id = horse_id   
                            win_horse_id_list.append(win_horse_id)
                      
                except:
                    pass
            
            #データフレームに取得した競争成績を追加
            horse_result = horse_result.append(df)
             
        except Exception as e:
            print(e)  
            
    #データフレームから不要な列を削除する
    drop_list = ['映像', '馬場指数', 'タイム指数', '厩舎コメント', '備考', '賞金']
    horse_result = horse_result.drop(drop_list, axis=1)
    
    #データフレームに列を追加する
    horse_result['日付ID'] = date_id_list
    horse_result['競技場ID'] = area_id_list
    horse_result['レースID'] = race_id_list
    horse_result['騎手ID'] = jockey_id_list
    horse_result['勝ち馬ID'] = win_horse_id_list
         
    return horse_result

メソッドの引数と戻り値

カテゴリ 変数 説明
引数 horse_id_list list 取得対象の競走馬ID
戻り値 horse_result DataFrame 競走馬の競争成績

解説

プログレスバーを表示する(※1)

本処理では、「tqdm」を使用することでプログレスバーを表示させています。

処理状況が分かるようになるので、処理時間が長いループ処理の際に利用することをおすすめします。

for race_id in tqdm(race_id_list):#・・・・・・・・・・・・・・・・・・・・・・・・・・・・(※1)

時間間隔を設定する(※2)

スクレイピングする際には、Webサイトへの負荷を考慮する必要があります。

Webサーバーに負荷をかけると、他のユーザーがそのWebサイトを参照できなかったり、ひどい場合はサーバーが落ちてしまう場合もあります。
そのような迷惑をかけないためにも、クローラーは間隔をあけてWebサーバーにアクセスするといった対応が必要となります。最低1秒以上は間隔をあけるようにしましょう。

Pythonオンライン学習サービス PyQ

上記のように、スクレイピングする際には最低1秒以上は間隔を空けましょう。

 time.sleep(1)#・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・(※2)

レース結果を取得する(※3)

スクレイピングする際には、まずは欲しい情報のHTMLを確認します。

「欲しいデータを選択 → 右クリック → 検証」の順に操作することで、HTMLを確認できます。

そうすると、今回入手するデータは<table>タグであることが分かります。

この場合は、pandasの「read_html」を使用することで簡単にレース結果を入手できます。

df = pd.read_html(url)[0]  #・・・・・・・・・・・・・・・・・・・・・・・・・・・ (※3)

「日付」「開催場所」等のID情報を追加する(※4)

入手したデータを機械学習で使用する際には、数値以外が使えないケースがあります。

なので本処理では、「日付」「開催場所」「レース名」「騎手」「勝ち馬(2着馬)」のID情報を取得します。

ここで「日付」のHTMLを確認してみると、

  • <a>タグにおける「href属性」に、ID情報が含まれている

ということが分かります。

他項目についても同様の特徴が見られため、この情報をもとにID情報を取得しています。

この箇所は長いので、処理の流れを簡単に紹介しておきます。

(※4)の処理の流れ
  • 1. 「urllib」でWebデータを取得
  • 2. 「BeautifulSoup」で、全ての<a>タグの情報を抽出
  • 3. 「href属性」の特徴(含まれる文字列、文字列の長さ)から、IDを抽出
            #WEBデータを解析・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・(※4)
            html = urllib.request.urlopen(url).read()
            soup = BeautifulSoup(html, 'html.parser')
            a_all = soup.find_all('a')
            
            cnt = 0        
            for a in a_all:
                try:
                    href = a.attrs['href']
                    text = a.text
                    href_split = href.split('/')
                    
                    #「日付ID」を取得・・・・・・・・・・・・・・・・・・・・・・・・・(※4)
                    if 'race' in href and 'list' in href and len(href) == 20:
                        date_id_list.append(href_split[-2])
                        
                    #「競馬場ID」を取得 ・・・・・・・・・・・・・・・・・・・・・・・・(※4)
                    elif 'race' in href and 'sum' in href and len(href) == 22:
                        area_id_list.append(href_split[-3])
                        
                    #「レースID」を取得 ・・・・・・・・・・・・・・・・・・・・・・・・(※4)
                    elif 'race' in href and len(href) == 19:
                        race_id_list.append(href_split[-2]) 
                        
                    #「騎手ID」を取得 ・・・・・・・・・・・・・・・・・・・・・・・・・(※4)
                    elif 'jockey' in href and len(href) == 14:
                        jockey_id_list.append(href_split[-2])
                                                                
                    #「勝ち馬ID」を取得 ・・・・・・・・・・・・・・・・・・・・・・・・(※4)
                    if 'horse' in href and len(href) == 18:
                        cnt = cnt + 1   
                        if cnt > 1:
                            win_horse_id = href_split[-2]

                            #テキストに「(」が含まれている場合は、win_horse_idに置換する
                            if '(' in text:
                                win_horse_id = horse_id   
                            win_horse_id_list.append(win_horse_id)

実行結果

参考図書

本記事の内容は、以下の図書を参考にしています。

本書は、スクレイピング以外にも

  • データベースへの登録方法
  • 機械学習
  • ディープラーニング

等も内容に含まれています。

Python初心者にも理解しやすい内容になっているので、ぜひ参考にしてください。

本書の特徴
  • Python初心者でも理解できるくらい具体的に説明されている
  • ソースコードも併せて紹介されているため、コード記述の際に躓きづらい

次回の内容

次回は、「netkeiba.com」から競走馬の競争成績を取得する方法を紹介します。

コメント

タイトルとURLをコピーしました