見出し画像

プロ野球の試合の観客数データを35行のコードで取得する2023年版

割引あり

はじめに

2023年もあとプロ野球は日本シリーズを残すのみになりました。
今年は関西対決で大いに盛り上がっていることでしょう。
今回は各球団のプロ野球の試合の観客数を14年分(2009年〜2022年)取得します。

データ取得元

データ取得元は、プロ野球Freakさんです。
いつもお世話になっています。!

スクレイピングコード全体

コードの全体は以下です。
scrape関数はその名の通りスクレイピングの処理をします。
urlにスクレイピングするサイトのURL、yearは年のデータを作成していくための変数です。
main部分はアクセスするためのURLを自動で作成してスクレイピング関数に処理させるためのコードになっています。
合計35行(空行含む)で14年分のデータが取得できます。

import pandas as pd
import time as t
import warnings
warnings.simplefilter("ignore")

def scrape(url,year):
    data = pd.read_html(url)
    df = data[2]
    df3 = df[['日付','観客数']]
    df3['観客数'] = df3['観客数'].str.replace('人','').str.replace(',','').str.replace('-','')
    df3['観客数'] = df3['観客数'].str.strip()
    df3.dropna(inplace=True)
    df3['日付'] = df3['日付'].str[:-3]
    df3['日付'] = pd.to_datetime(year + '年' + df3['日付'], format='%Y年%m月%d日')
    
    return df3

if __name__ == "__main__":
    start = t.time()
    teams = ['swallows','baystars','tigers','giants','carp','dragons','buffaloes','marines','eagles','hawks','fighters','lions']

    for team in teams:
        data = pd.DataFrame()
        for year in range(9,23):
            s = '{:02}'.format(year)
            print('https://baseball-freak.com/audience/'+ s + '/'+team+'.html')
            df = scrape('https://baseball-freak.com/audience/'+ s + '/'+team+'.html','20'+s)
            df['球団'] = team
            data = pd.concat([data,df])
            t.sleep(5)

        data.to_csv('audience_data/' + team + '_audience.csv',index=False)

    elapsed_time = t.time() - start
    print ("elapsed_time:{0:.3f}".format(elapsed_time) + "[sec]")


コード解説

ライブラリインポートです。
主に使うライブラリはpandasのみですが、処理時間計測用にtime、警告表示を非表示にするためにwarningsを用います。

import pandas as pd
import time as t
import warnings
warnings.simplefilter("ignore")

スクレイピング関数はurlにあるデータを抽出してデータフレームに加工していく処理です。
urlはデータを取得するサイトです。
yearは年の数値が入ります。
pd.read_html(url)でサイトの表形式の部分を抽出します。

def scrape(url,year):
    data = pd.read_html(url)

dataにサイトの表形式部分のデータを全て取ってきます。
data[2]の位置に観客数データが格納されているので、dfに代入します。

    df = data[2]

取得する列のデータを指定してdf3に代入します。
必要なデータを絞りたい場合はここで取得する列を変更すれば良いです。
下記は取得できる全ての列です。

    df3 = df[['日付','観客数','勝敗','スコア','対戦相手','先発投手','試合時間','球場']]

観客数のデータは文字列であり、「人」や「,」などが含まれています。
観客数は計算しやすい数値として扱いため、これらの文字列を削除します。
strip()では空白を削除し、欠損値のあるデータは削除します。

   df3['観客数'] = df3['観客数'].str.replace('人','').str.replace(',','').str.replace('-','')
   df3['観客数'] = df3['観客数'].str.strip()
   df3.dropna(inplace=True)

日付列は年月日に曜日まであるので、曜日部分の文字列を削除します。
後ろ3文字が曜日の記載になっているので、df3['日付'].str[:-3]で後ろ3文字は除外できます。
除外後、pd.to_datetime(year + '年' + df3['日付'], format='%Y年%m月%d日')で日付データの方に変換します。
最後にreturnでデータフレーム形式で返します。

    df3['日付'] = df3['日付'].str[:-3]
    df3['日付'] = pd.to_datetime(year + '年' + df3['日付'], format='%Y年%m月%d日')
    
    return df3

メイン処理部分です。
メインメソッドを宣言して始めます。
start変数にt.time()で時刻を取得します。
teamsにはURLのパーツとなる文字列を入れておきます。
サイトは各球団、年別にサイトが分かれています。
teamsのリストには各球団を識別するためのURLの一部を格納しておきます。
このサイトはチーム名で分けてくれているのでわかりやすいです。

if __name__ == "__main__":
    start = t.time()
    teams = ['swallows','baystars','tigers','giants','carp','dragons','buffaloes','marines','eagles','hawks','fighters','lions']

スクレイピング処理はfor文の2重ループで12球団の14年分の観客数を取得します。
最初のループでチームを指定するため、teamsリストから格納されている文字列を取得。
2つ目のループに入る前にデータフレーム形式の変数をdataとして初期化します。
2つ目のループは年を指定していきます。
スクレイピング先のサイトのURLはチームと年で分けられています。
年は一桁は09と表示としているため、0パディングした文字列をsに代入。
printでアクセスするURLを出力しています。(出力しなくても処理上問題はありません。)
scrape関数にurlと'20'+sを渡して、dfにデータセットが格納されます。
'20'+sで2009、2010・・・と年を西暦で渡します。
データ取得後、df['球団']=teamで球団列を追加します。
scrape関数は1年ごとデータを取得しますので、pd.concat()を用いて、データを追加していきます。
t.sleep(5)で5秒間処理を止めます。
処理を止めるのは、高速にURLアクセスを避けるためです。
5秒は長すぎかもしれません。
短くする場合は5より低い数値にすれば良いですが1秒より長めに設定しておくことをお勧めします。
内側のループを抜けたらdata.to_csv()でcsvファイル形式で保存します。
これで球団ごとの14年分のデータを取得することができます。

    for team in teams:
        data = pd.DataFrame()
        for year in range(9,23):
            s = '{:02}'.format(year)
            print('https://baseball-freak.com/audience/'+ s + '/'+team+'.html')
            df = scrape('https://baseball-freak.com/audience/'+ s + '/'+team+'.html','20'+s)
            df['球団'] = team
            data = pd.concat([data,df])
            t.sleep(5)
        data.to_csv('audience_data/' + team + '_audience.csv',index=False)

最後は時間計測のために、t.time()と処理の開始時に取得した時刻データstartの差を取ることで処理時間を計算します。
print ("elapsed_time:{0:.3f}".format(elapsed_time) + "[sec]")で処理にかかった時間を秒で出力して終了です。
5秒間の処理停止を設けてプログラムを実行すると約15分です。

    elapsed_time = t.time() - start
    print ("elapsed_time:{0:.3f}".format(elapsed_time) + "[sec]")

取得データ例

取得したデータは下のようになります。
観客数の他にも球場や対戦した球団、勝敗、スコア、先発投手、試合時間が取得できます。

取得データ

まとめ

35行でプロ野球の観客数データを取得しました。
取得したデータでいろんな分析をしてみてください。

プログラムコード(有料)

本記事のプログラムコードをpythonファイルとnotebook形式で販売します。

ここから先は

0字 / 2ファイル
この記事のみ ¥ 100〜

よろしければサポートをよろしくお願いします。サポートいただいた資金は活動費に使わせていただきます。