仕事の依頼はこちらから 依頼フォーム

【Python】netkeibaのスクレイピング対策後のサンプルコード

以下の記事で11月初旬頃に行われたnetkeibaのスクレイピング対策の回避方法を紹介しました。

部分的に抜粋したコードを紹介しましたが、それでもうまくいかないとの報告がありましたらのでサンプルコードを本記事で紹介します。

目次

サンプルコード

これから紹介するサンプルコードのスクレイピングは以下の流れで行います。

STEP
HTMLタグの抽出

netkeibaは静的ページと動的ページが存在します。静的ページの場合はrequestsモジュール、動的ページの場合はseleniumモジュールを使用します。

応答速度の面からすべてのページでrequestsモジュールを使用できれば良いのですが、ページによってはJavaScriptが使用されているページ(動的ページ)があるため、requestsモジュールで必要な情報を取得できない場合にseleniumモジュールを使用します。

以上の2つのモジュールを使用するには以下のコマンドでインストールが必要です。

pip install requests selenium
STEP
HTMLの解析

HTMLページの解析にはbeautifulsoup4モジュールを使用します。また、解析器はlxmlモジュールを使用します。

HTMLタグの抽出にseleniumモジュールを使用する場合、HTMLの解析もseleniumモジュールで行うことができますが、今回はすべてのページでbeautifulsoup4モジュールを使って解析することとします。

解析器はPythonの標準でhtml.parserが用意されていますが、解析速度が速いことからlxmlモジュールを使用します。

以上の2つのモジュールを使用するには以下のコマンドでインストールが必要です。

pip install beautifulsoup4 lxml

なお、スクレイピング対策の回避方法の記事で紹介したようにrequestsモジュールを使ってスクレイピングを行うにはユーザーエージェントの偽装が必要ですので以下の記事を参考にしてサンプルコード内のUser-Agentの置き換えを行った上で実行してください。

サンプルコードのダウンロード

以下に公開するサンプルコードはGitHubよりダウンロードが可能ですのでぜひご活用ください。

https://github.com/scraproace/netkeiba_sample

レースの開催日を取得するサンプルコード

以下のURLから2024年10月のレースの開催日一覧を取得するサンプルコードを紹介します。

https://race.netkeiba.com/top/calendar.html?year=2024&month=10

開催日程の各月のページからその月にレースが開催される日付(カレンダー内にリンクがある日付)をリストで取得します。

import re

from bs4 import BeautifulSoup
import requests


URL = 'https://race.netkeiba.com/top/calendar.html?year=2024&month=10'


def get_kaisai_dates(url: str) -> list[str]:
    headers = {
        'User-Agent': 'Your User-Agent'  # 置換必要
    }

    r = requests.get(url, headers=headers)
    r.raise_for_status()

    soup = BeautifulSoup(r.content, 'lxml')

    kaisai_dates = []

    for a_tag in soup.select('.Calendar_Table .Week > td > a'):
        kaisai_date = re.search(r'kaisai_date=(.+)', a_tag.get('href')).group(1)
        kaisai_dates.append(kaisai_date)

    return kaisai_dates


if __name__ == '__main__':
    kaisai_dates = get_kaisai_dates(URL)
    print(kaisai_dates)

'''
['20241005', '20241006', '20241012', '20241013', '20241014', '20241019', '20241020', '20241026', '20241027']
'''

レースIDを取得するサンプルコード

以下のURLから2024年10月27日のレースID一覧を取得するサンプルコードを紹介します。

https://race.netkeiba.com/top/race_list.html?kaisai_date=20241027

開催レース一覧のページからその日に開催されるレースIDをリストで取得します。レースIDを取得することでそのレースの結果ページなどのリンクを推測できるようになります。

import re

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait


URL = 'https://race.netkeiba.com/top/race_list.html?kaisai_date=20241027'


def get_race_ids(url: str) -> list[str]:
    driver = webdriver.Chrome()
    wait = WebDriverWait(driver, 30)

    try:
        driver.get(url)

        wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#RaceTopRace')))

        soup = BeautifulSoup(driver.page_source, 'lxml')

        race_ids = []

        for a_tag in soup.select('.RaceList_DataItem > a:first-of-type'):
            race_id = re.search(r'race_id=(.+)&', a_tag.get('href')).group(1)
            race_ids.append(race_id)
    finally:
        driver.quit()

    return race_ids


if __name__ == '__main__':
    race_ids = get_race_ids(URL)
    print(race_ids)

'''
['202405040801', '202405040802', '202405040803', '202405040804',
..., '202404040810', '202404040811', '202404040812']
'''

レースの出馬表を取得するサンプルコード

以下のURLから2024年10月27日に行われた天皇賞(秋)の出馬表を取得するサンプルコードを紹介します。

https://race.netkeiba.com/race/shutuba.html?race_id=202405040811&rf=race_submenu

レースの出馬表のページから出馬表をリストで取得します。なお、お気に入り列以降の列は除外しています。

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait


URL = 'https://race.netkeiba.com/race/shutuba.html?race_id=202405040811&rf=race_submenu'


def get_shutuba_table(url: str) -> list[list[str]]:
    driver = webdriver.Chrome()
    wait = WebDriverWait(driver, 30)

    try:
        driver.get(url)

        wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.ShutubaTable')))

        soup = BeautifulSoup(driver.page_source, 'lxml')

        shutuba_table = []

        header_tr_tag = soup.select_one('.ShutubaTable > thead > tr:first-of-type')

        # .split('\n')[0]を入れないとオッズがオッズ\n\n更新となる
        shutuba_table.append([th_tag.text.strip().split('\n')[0] for th_tag in header_tr_tag.select('th')[:11]])

        for tbody_tr_tag in soup.select('.ShutubaTable > tbody > tr'):
            row = []
            for i, td_tag in enumerate(tbody_tr_tag.select('td')[:11]):
                # 印列のみ別処理
                if i == 2:
                    row.append(td_tag.select_one('.selectBox').text.strip())
                else:
                    row.append(td_tag.text.strip())

            shutuba_table.append(row)
    finally:
        driver.quit()

    return shutuba_table


if __name__ == '__main__':
    shutuba_table = get_shutuba_table(URL)
    print(shutuba_table)

'''
[
    ['枠', '馬番', '印', '馬名', '性齢', '斤量', '騎手', '厩舎', '馬体重(増減)', 'オッズ', '人気'],
    ['1', '1', '--', 'ベラジオオペラ', '牡4', '58.0', '横山和', '栗東上村', '514(-4)', '13.3', '4'],
    ...
    ['8', '15', '--', 'ニシノレヴナン ト', 'セ4', '58.0', '田辺', '美浦上原博', '490(0)', '415.8', '15']
]
'''

レースの結果を取得するサンプルコード1

以下のURLから2024年10月27日に行われた天皇賞(秋)の結果を取得するサンプルコードを紹介します。

https://race.netkeiba.com/race/result.html?race_id=202405040811&rf=race_submenu

レースの結果・払戻のページから結果表をリストで取得します。

from bs4 import BeautifulSoup
import requests


URL = 'https://race.netkeiba.com/race/result.html?race_id=202405040811&rf=race_submenu'


def get_result_table(url: str) -> list[list[str]]:
    headers = {
        'User-Agent': 'Your User-Agent'  # 置換必要
    }

    r = requests.get(url, headers=headers)
    r.raise_for_status()

    soup = BeautifulSoup(r.content, 'lxml')

    result_table = []

    for tr_tag in soup.select('#All_Result_Table tr'):
        result_table.append([data_tag.text.strip() for data_tag in tr_tag.select('th, td')])

    return result_table


if __name__ == '__main__':
    result_table = get_result_table(URL)
    print(result_table)

'''
[
    ['着順', '枠', '馬番', '馬名', '性齢', ..., '厩舎', '馬体重(増減)'],
    ['1', '4', '7', 'ドウデュース', '牡5', ..., '栗東友 道', '504(-4)'],
    ...
    ['15', '7', '13', 'シルトホルン', '牡4', ..., '美浦新開', '468(+4)']
]
'''

レースの結果を取得するサンプルコード2

以下のURLから2024年10月27日に行われた天皇賞(秋)の結果を取得するサンプルコードを紹介します。

https://db.netkeiba.com/race/202405040811

先ほどの「レースの結果を取得するサンプルコード1」のURLとは異なり、データベースページのレースの結果・払戻のページから結果表をリストで取得します。なお、プレミアム限定の列は除外しています。

from bs4 import BeautifulSoup
import requests


URL = 'https://db.netkeiba.com/race/202405040811/'


def get_result_table(url: str) -> list[list[str]]:
    headers = {
        'User-Agent': 'Your User-Agent'  # 置換必要
    }

    r = requests.get(url, headers=headers)
    r.raise_for_status()

    soup = BeautifulSoup(r.content, 'lxml')

    result_table = []

    for tr_tag in soup.select('.race_table_01 tr'):
        row = []
        for i, data_tag in enumerate(tr_tag.select('th, td')):
            # プレミアム限定列は除外
            if i in [9, 15, 16, 17]:
                continue

            row.append(data_tag.text.strip())

        result_table.append(row)

    return result_table


if __name__ == '__main__':
    result_table = get_result_table(URL)
    print(result_table)

'''
[
    ['着順', '枠番', '馬番', '馬名', '性齢', '斤量', '騎手', 'タイム', '着差', '通過', '上り', '単勝', '人気', '馬体重', '調教師', '馬主', '賞金(万円)'],
    ['1', '4', '7', 'ドウデュース', '牡5', '58', '武豊', '1:57.3', '', '14-14-13', '32.5', '3.8', '2', '504(-4)', '[西]\n友道康夫', 'キーファーズ', '22,323.4'],
    ...
    ['15', '7', '13', 'シルトホルン', '牡4', '58', '大野拓弥', '1:58.4', '1/2', '2-2-2', '34.6', '412.0', '14', '468(+4)', '[東]\n新開幸一', 'デ ィアレストクラブ', '']
]
'''

レースの払い戻しを取得するサンプルコード

以下のURLから2024年10月27日に行われた天皇賞(秋)の払い戻しを取得するサンプルコードを紹介します。

https://db.netkeiba.com/race/202405040811

データベースページのレースの結果・払戻のページから払い戻し表をリストで取得します。

from bs4 import BeautifulSoup
import requests


URL = 'https://db.netkeiba.com/race/202405040811/'


def get_pay_table(url: str) -> list[list[str]]:
    headers = {
        'User-Agent': 'Your User-Agent'  # 置換必要
    }

    r = requests.get(url, headers=headers)
    r.raise_for_status()

    soup = BeautifulSoup(r.content, 'lxml')

    pay_table = []

    for table_tag in soup.select('.pay_table_01'):
        for tr_tag in table_tag.select('tr'):
            # get_text('\n')とすることで<br>タグを\nに変換
            pay_table.append([data_tag.get_text('\n').strip() for data_tag in tr_tag.select('th, td')])

    return pay_table


if __name__ == '__main__':
    pay_table = get_pay_table(URL)
    print(pay_table)

'''
[
    ['単勝', '7', '380', '2'],
    ['複勝', '7\n4\n9', '200\n1,020\n1,000', '2\n9\n8'],
    ...
    ['三連単', '7 → 4 → 9', '397,100', '612']
]
'''

この記事が気に入ったら
フォローしてね!

シェアしていただけると嬉しいです!
  • URLをコピーしました!

コメント

コメントする

目次