python初学者がボートレースのレース結果を取得して出力してみた。

記事
IT・テクノロジー
はじめまして!

中川です。

突然ですが、プログラミング言語を独学で習得するのってものすごくハードルが高いですよね。

でも、お金もないのでなんとか独学で乗り越えたい。

1人でも成長していきたい。

成長するには何かを作成するのが一番!

と、いうことで、これからはpythonでボートレース予想をして大金持ちになっていこうと思います。

まずレース結果一覧の画面のURLは

”ボートレスのサイト名”/owpc/pc/race/resultlist?jcd=”ボートレース場識別番号”&hd=”ボートレースの開催日”


と、なっているようです。

ボートレース場識別番号は全国24のボートレース場に1~24までの番号が割り振られたものです。

今回は住之江ボートレース場に絞って分析していくため識別番号は”12”となります。

またボートレースの開催日は例えば2022年4月17日にレースが開催されていた場合”20220417”となります。

と、いうことはここに住之江競艇場の開催日程を入力すれば結果を入手できます。

今回は設定したURLからBeautifulSoupライブラリを使用してwebスクレイピングによるデータ抽出を行っていきたいと思います。

まずは、今回お世話になるライブラリーさん達をインポートします。

import pandas as pd
import requests
import re
from bs4 import BeautifulSoup

そして、とりあえず住之江ボートレースの結果を抽出します。

url=""ボートレースサイト名"/owpc/pc/race/resultlist?jcd=12&hd=20220417"
res = requests.get(url)
soup = BeautifulSoup(res.text, "html.parser")
print(soup.find("span", class_='numberSet1_number').text)
#出力結果 1

すると 1 という数字が帰ってきます。

これはspanタグの'numberSet1_number'クラスにある一番最初の数字を取ってきて表示しています。

burogu_1.png

これをfor文を使って、またはリスト内包表記をつかってすべての数字を取得して表示します。

今回はfor文を使って表示しています。

for content in soup.find_all("span", class_='numberSet1_number'):
    print(content.text)

このようにすると上からずらっと60個の1~6の数字が表示されます。

また、

i=0
for content in soup.find_all("span", class_='numberSet1_number'):
    i += 1
    print(str(i) + '. '+ content.text)

のように書き換えると。

1. 1

2. 4

3. 5

4. 1

5. 4

6. 2

7. 1

のように表示され見やすくなります。

私は、あまり好きではないので使っていませんがenumerate関数をつかった表示方法もあります。

欲しい情報は12レース分の1~3着までの番号なのですが、3着目を表示した後すぐに1~2着の二連単の組み合わせが表示されて行っているため、ここを取り除きたいです。

不必要な情報は、4,5,9,10,14,15,19,20・・・番目の情報であることがわかりこれは、5-1, 5 , 5*2 -1, 5*2, 5*3 -1, 5*3・・・番目という数列になっていることがわかります。

つまり、5の倍数と5の倍数ー1の数字が不必要となります。

しかし、いちいち取り除いていては時間を要してしまいますのでfor文の性質を利用して、5の倍数と5の倍数ー1回目の処理をスキップしてしまえばいいのです。

特定の条件下の場合のみ処理をスキップする場合にはcontinue文を使います。

i=0
counter=0

for content in soup.find_all("span", class_='numberSet1_number'):
    i += 1

    if i%5==0 or i%5==4:
        continue
    counter += 1
    print(str(counter) + '. '+ content.text)

出力結果は
1. 1
2. 4
3. 5
4. 2
5. 1
6. 4
7. 4
8. 2
9. 6
10. 4
36. 3
と、なり、2連単を除く36個の情報が取得できました。

そして、これらを1着、2着、3着に分けてデータに格納したいので

ranking_1 = []
ranking_2 = []
ranking_3 = []

という風に着順ごとに分けてリストの中に入れてあげます。

そして、一着の番号が表示されるのは、1,4,7,10,13・・・なので

if i%3 ==1:
 実行文

とすればよいはずです。

また、beautifulsoupで抽出してきたものには余分なものが含まれてしまっているので、必要な数字の部分だけを抽出してから格納します。

number = re.sub(r"\D", "", content.text)

として、reモジュールの指定文字、または数字を抽出するメソッドを使って文字列を取り出します。

以上のことを踏まえコードを書くと以下のようになります。

#DataFrame作成
i=0
counter = 0
ranking_1 = []
ranking_2 = []
ranking_3 = []
for content in soup.find_all("span", class_='numberSet1_number'):
    i+=1
    if i%5==0 or i%5==4:
        continue

    counter += 1
    number = re.sub(r"\D", "", content.text)

    if counter%3 ==1:
        ranking_1.append(int(number))
    if counter%3 ==2:
        ranking_2.append(int(number))
    if counter%3 ==0:
        ranking_3.append(int(number))
kekka = {'一着':ranking_1,'二着':ranking_2,'三着':ranking_3}
df = pd.DataFrame(kekka)

ここではkekkaという辞書の中に、各順位を挿入しています。

    一着 二着 三着
0  1 4 5
1  2 1 4
2  4 2 6
3  4 3 5
4  1 2 6
5  1 3 2
6  4 5 6
7  1 5 3
8  1 2 3
9  1 3 2
10  1 4 2
11  1 2 3

すると以上のように表示され、スクレイピングで抽出した順位データが無事データフレームに格納されていることが分かります。

また、iとは別にcounterという変数を定義しています。

iは60までカウントされるのに対して、counterは36までしかカウントされません。

仕上げに以下を実行すればcsvファイルに出力できます。

df.to_csv("出力ファイル名.csv",encoding='utf_8_sig')

encodingは文字化けを防ぐために指定しています。

以上が、pythonによる簡単なボートレースのスクレイピングとデータフレーム格納の流れです。

もっと大量のデータを取得したり、選手情報も抽出したり、それらを使って結果を予測したり、やりたいことは山ほどあるのですが今日はここで区切りとさせていただきます。

すこしでも目にとめていただけたのなら幸いです。

本当にありがとうございました。
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す