0
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Python スクレピング 競馬サイトから出走馬の過去成績を取得

Last updated at Posted at 2020-03-22

背景

現在、競馬×機械学習のために、
ウェブページから競馬情報をスクレイピングすることに取り組んでいます。

入力内容に出走馬の過去の成績を組み込もうとしています。
そこで競馬のレース結果表から出走馬のページのURLを取得、アクセスし、
出走日の過去の成績を取得することにした。

##構想
ss図1.png

##サンプルコード

アイデアは以下の3点。
・取得方法をCSSセレクターで統一
・レース結果表から各馬のURLを取得し、そのURLに掲載されている過去成績を取得
・今回の出走馬は12頭だが、他の馬数でも取得できるように可変長変数を使用

この記事の前に、Python スクレピング 競馬サイトからレース環境を抽出を紹介させていただきました。
こちらはレース環境をBeautifulSoupを使いました。
しかしcssセレクターで統一して処理したほうが気持ちがいいので書き換えました。

scraping_of_race_and_past_horse_result.py
import requests
import lxml.html 
import csv

rlt = [] #結果
horse_URL = []#馬の名前を取得する

#スキャルピングでテキスト取得
def get_scarping_data(key_page,css_select_str,*URL):
    #取得したURLの個数分の情報を取得する
    for i in range(len(URL)):
        #URLから文字列を取得       
        r = requests.get(URL[i])#URLを指定 
        r.encoding = r.apparent_encoding #文字化けを防止
        html = lxml.html.fromstring(r.text) #取得した文字列データ
        # 項目を取得
        for css_id in html.cssselect(css_select_str):        
            #レース結果サイトのレース環境
            if key_page == "condition_in_race_page" :
                #Element番号のテキスト 
                css_id = css_id.text_content()
                #内包表記 抽出する際に"天気"は不変であるので条件指定
                css_id_ = [css_id for t in css_id if "天気" in css_id]
                css_id_ = css_id_[0].split('\xa0/\xa0')
                #リストに行のデータ(リストを追加)
                rlt.append(css_id_)
            #レース結果サイトのレース結果
            if key_page == "result_in_race_page" :
                #Element番号のテキスト 
                css_id = css_id.text_content()
                #改行("\n")をもとに分割する
                css_id = css_id.split("\n")
                #内包表記 空の要素を駆逐する 空文字を除く
                css_id_ = [tag for tag in css_id if tag != '']
                #1位はタイム記録なし #強引に加える必要がある 8番目に0
                if len(css_id_) != 13 : css_id_.insert(8,0)
                #リストに行のデータ(リストを追加)
                rlt.append(css_id_) 
            #レースした馬の過去成績サイト
            if key_page == "horse_race_data" : 
                #Element番号のテキスト 
                css_id = css_id.text_content()
                #取得したElement番号の
                css_id = css_id.split("\n")
                #内包表記 空と"\xa0"と"映像"を除去
                css_id_ = [tag for tag in css_id 
                if tag != '' and tag != "\xa0" and tag != "映像" and tag != "厩舎コメント" and tag != "備考" ]
                #リストに行のデータ(リストを追加)
                rlt.append(css_id_)        
    #抽出結果
    return rlt

#レースした馬のURLを取得
def get_scarping_past_horse_date(URL):            
    response = requests.get(URL)
    root = lxml.html.fromstring(response.content)
    #1~12までの馬の情報を取得
    for i in range(2,14):#2~13  13 - 2 + 1 = 12 
        css_select_str = "div#race_main tr:nth-child({}) > td:nth-child(4) > a".format(i)
        #レースした馬の情報を取得
        for a in root.cssselect(css_select_str):
            horse_URL.append(a.get('href'))
    #抽出結果
    return horse_URL

#まず本家のレースサイトからレース環境を取得
URL = "https://nar.netkeiba.com/?pid=race&id=p201942100701" 
#レース環境を取得
rlt = get_scarping_data("condition_in_race_page","div#main span",URL)
#レース結果を取得
rlt = get_scarping_data("result_in_race_page","#race_main > div > table > tr",URL)
#レースした馬のURLを取得
horse_URL = get_scarping_past_horse_date(URL)
print(len(horse_URL))#出走馬12に対し、出力結果は12
#取得した馬のURLから過去成績を取得
#項目(1行分)を取得
rlt = get_scarping_data("horse_race_data", "#contents > div.db_main_race.fc > div > table > thead > tr",horse_URL[0])
#項目以外の成績データ
rlt = get_scarping_data("horse_race_data", "#contents > div.db_main_race.fc > div > table > tbody > tr",*horse_URL)
#CSVファイルに保存
with open("scraping_of_race_and_past_horse_result.csv", 'w', newline='') as f: 
    wrt = csv.writer(f) 
    wrt.writerows(rlt) #抽出結果の書き込み

##実行結果
sss.png

##反省点
・レース結果から馬の情報が掲載されているURLを取得し、過去成績も取得できた。
・過去成績を取得できたが最新の情報も掲載されているので、レースした日を基準に遡った成績を取得する必要がある。
・取得できた情報をニューラルネットワークに入力できるレベルまで行っていない。
・レースした日を自動で取得する。毎回調べない
→方法として、レース情報数値(URLの末端の12桁)を規則性を考慮してインクリメント。

CSSセレクタの調べ方

スクレイピングするうえで、以下のコード(文字列)を使いこなす必要がある。
(#contents > div.db_main_race.fc > div > table > tbody > tr')
↑ここの部分をどのようにして取得するのかをまとめる。

how_to_search_css_sector.py
for h in html.cssselect('#contents > div.db_main_race.fc > div > table > tbody > tr'):#スクレイピング箇所をCSSセレクタで指定

初めはただコピペしたり、そっれっぽいコードを書いてトライしたが、うまく行かない。。。
調べてみるとCSSが絡んでいる。
欲しい項目はどのCSSセレクターで構成されたいるかを知るために、
ChromeのCopy Css Selectorのツールを使う。
無題4.png

インストールすると右クリックでCopy Css Selectorの項目ができる。
欲しい項目でCopy Css Selectorを実行し、テキストに張り付けて確認するとCSSセレクターを知ることができる。
※うまくいかないこともあるかもしれない。

無題4.png

他にもディベロッパー ツールを用いて、
欲しい情報範囲で Copy → Copy Selector でCCSセクターをコピーできる。
たまにうまくいきます。
無題5.png

この2つを駆使すれば、SCCセレクターを取得できるはずです。

0
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?