プロ野球選手の年棒をスクレイピングしてみる!
プロ野球選手の年棒が気になりますよね?
契約更改の時期になるとあの選手は活躍してこんなに上がったのかなど思ったりすると思います。
データ分析する身としては、どこかにまとまった情報があるとデータ収集が助かります。
探してみるとあるもんですね!
今回は、プロ野球選手の年棒をスクレイピングしてデータ収集してみようと思います。
サマリ
プロ野球選手の年俸をスクレイピングするサイト
スクレイピングする上での注意
スクレイピングでプロ野球選手のデータをスクレイピング
チームごとの年棒データをスクレイピング
データを取得したら次にやることは?
プロ野球選手の年俸をスクレイピングするサイト
プロ野球選手の年俸のデータはなかなかないものです。
金が関わることはやはりオープンになりにくいものですが、
ありました!!
今回はここに掲載されているデータをスクレイピングしていきましょう。
スクレイピングするときの注意
スクレイピングをするときは、そのサイトの規約など必ず見てください。
スクレイピングするときにあらかじめサイト作成者がサイト内でクローリングしてよいページやしてはいけないページや指定するアクセス間隔を記載したrobots.txtがあります。
今回はないようです。
この場合は、サイトに迷惑をかけない程度にしましょう。
アクセス間隔は最低でも1秒以上にしてください。
しかし、今回は一度読み取ればほしいデータが手に入るのでそこまで気にしなくていいです。
robots.txtを見るときの参考のコードは以下になります。
詳しいことは以下のサイトが参考になります。
実際にスクレイピングしてみる
実際に順を追ってスクレイピングしてみようと思います。
まずは、サイトのデータを取ってきます。
data = pd.read_html('https://baseball-dataroom.com/post-10511/')
取ってきたデータを見ればわかると思いますが、各チームの投手と野手に分かれて綺麗にテーブルになっています。
次に一つのテーブルを代入します。
巨人のデータになるので変数名はgiantsにしています。
giants = data[0]
データがどうなっているか確認してみましょう。
giants.head()
実行結果:
0 1 2 3
0 選手名 年俸 前年比 備考
1 菅野 智之 6.5億 ±0 NaN
2 A.サンチェス 3.4億 – 韓国リーグから移籍、2年契約
3 澤村 拓一 1.54億 ↑3250万 NaN
4 野上 亮磨 1.5億 ±0 NaN
カラム名が0,1,2,3と設定されていませんね。
カラム名を設定してあげましょう。
giants.columns=giants.loc[0]
giants.head()
実行結果:
選手名 年俸 前年比 備考
0 選手名 年俸 前年比 備考
1 菅野 智之 6.5億 ±0 NaN
2 A.サンチェス 3.4億 – 韓国リーグから移籍、2年契約
3 澤村 拓一 1.54億 ↑3250万 NaN
4 野上 亮磨 1.5億 ±0 NaN
1行目入らないので削ります。
giants=giants.drop(0)
giants.head()
実行結果:
選手名 年俸 前年比 備考
1 菅野 智之 6.5億 ±0 NaN
2 A.サンチェス 3.4億 – 韓国リーグから移籍、2年契約
3 澤村 拓一 1.54億 ↑3250万 NaN
4 野上 亮磨 1.5億 ±0 NaN
5 R.デラロサ 1.3億 – NaN
左のインデックスの数がそのままですね。
そのままでもいいのですが、リセットしておきましょう。
giants=giants.reset_index(drop=True)
giants.head()
実行結果:
選手名 年俸 前年比 備考
0 菅野 智之 6.5億 ±0 NaN
1 A.サンチェス 3.4億 – 韓国リーグから移籍、2年契約
2 澤村 拓一 1.54億 ↑3250万 NaN
3 野上 亮磨 1.5億 ±0 NaN
4 R.デラロサ 1.3億 – NaN
インデックスが元に戻りましたね。
次は年俸列と前年比列の文字列を数値にして使いやすい形にします。
文字列には「+」、「-」、「±」、「億」、「万」とあります。
「+」、「±」を見つけたら消去、
「↑」を見つけたら消去、
「↓」を見つけたらマイナスの符号をつけます。
「-」だけしかないトリッキーな列もあります。
これは、前年比で変化がなかったことがあるので「0」に置き換えます。
giants['前年比']=giants['前年比'].str.replace('↑','')
giants['前年比']=giants['前年比'].str.replace('↓','-')
giants['前年比']=giants['前年比'].str.replace('±','')
giants['前年比']=giants['前年比'].str.replace('–','0')
そして、「億」を見つけたら100000000倍、
「万」を見つけたら10000倍、
とします。
具体的な処理の仕方は以下の関数にしておきます。
処理手順を追っていきましょう。
まず、前年比または年俸列を取得します。
salary = row['前年比']
データの型は文字列のため「万」、「億」を見つけたら見つけた位置が何番目か変数に代入します。
ちなみに、このデータには誤字で「億」が「憶」になっています。
これに対処するために、「憶」を見つけた場合にも位置を代入できるようにしておきます。
man = salary.find('万')
oku = salary.find('億')
miss_oku = salary.find('憶')#誤字の対応
そして、「億」または「万」を見つけた場合、変数が0より大きくなるので、「億」を見つけた場合に格納した変数が0より上なら、「億」を見つけたことになります。
「億」を見つけたら、「億」の1個前の位置まで値を取得して、変数をfloatに変換してから100000000倍してあげます。
最後に仕上げで整数型にして完成です。
ほら面倒でしょw
if oku>0 or miss_oku>0:
salary = int(float(salary[:oku]) * 100000000)
elif man>0:
salary = int(float(salary[:man]) * 10000) # 「万」の手前までの数値を抽出し1万倍する
else:
salary = int(salary)
関数にすると以下になります。
def ToYen(row):#
salary = row['前年比']
man = salary.find('万')
oku = salary.find('億')
miss_oku = salary.find('憶')#誤字の対応
if oku>0 or miss_oku>0:
salary = int(float(salary[:oku]) * 100000000)
elif man>0:
salary = int(float(salary[:man]) * 10000) # 「万」の手前までの数値を抽出し1万倍する
else:
salary = int(salary)
row['前年比'] = salary
return row
def fromOkuManToYen(row):
salary = row['年俸']
man = salary.find('万')
oku = salary.find('億')
miss_oku = salary.find('憶')#誤字の対応
if oku>0 or miss_oku>0:
salary = int(float(salary[:oku]) * 100000000)
elif man>0:
salary = int(float(salary[:man]) * 10000) # 「万」の手前までの数値を抽出し1万倍する
else:
salary = int(salary)
row['年俸'] = salary
return row
以上の関数を使い、データを変換していきます。
giants.apply(ToYen,axis=1)
giants.apply(giants.apply(fromOkuManToYen,axis=1)
実行結果:
最後にデータをcsvにしましょう。
giants.to_csv('giants_salary.csv',index=False)
以上で完成になります。
文字列処理がなかなか大変だったのではないでしょうか。
スクレイピングにはつきものですので文字列処理の練習になったりしますw
チームごとデータを取得するスクレイピング
1つの表のスクレイピングをしてcsvファイルにしました。
サイトを見てみるとわかりますが、同じように表がチームごと投手、野手に分かれています。
スクレイピングの作業を繰り返しやるのも苦行です。
処理を関数にしてまとめてしまいましょう。
すぐにできるだろうと思ったら大間違いです。
データには誤字脱字などがあり、決まった加工をすればいいだろうと思うと様々なエラーに出くわします。
下記のコードを見てもらえればわかると思います。
文字列処理が色々と入っていますよね。
このような誤字など予想外の文字列をスクレイピングをするときにはよく出会います。
これらの文字列を対処した先にデータが得られます。
一種の宝さがしみたいな感じがしますね。
def ToYen(row):
salary = row['前年比']
man = salary.find('万')
oku = salary.find('億')
miss_oku = salary.find('憶')#誤字の対応
if oku>0 or miss_oku>0:
salary = int(float(salary[:oku]) * 100000000)
elif man>0:
salary = int(float(salary[:man]) * 10000) # 「万」の手前までの数値を抽出し1万倍する
else:
salary = int(salary)
row['前年比'] = salary
return row
def fromOkuManToYen(row):
salary = row['年俸']
man = salary.find('万')
oku = salary.find('億')
miss_oku = salary.find('憶')#誤字の対応
if oku>0 or miss_oku>0:
salary = int(float(salary[:oku]) * 100000000)
elif man>0:
salary = int(float(salary[:man]) * 10000) # 「万」の手前までの数値を抽出し1万倍する
else:
salary = int(salary)
row['年俸'] = salary
return row
def mung_data(data,team_list):
try:
for i in range(0,len(data)):
salary_data = data[i]
salary_data.columns=salary_data.loc[0]
salary_data=salary_data.drop(0)
salary_data=salary_data.reset_index(drop=True)
salary_data['年俸']=salary_data['年俸'].str.replace(',','')
salary_data['年俸']=salary_data['年俸'].str.replace('–','0')
salary_data.apply(fromOkuManToYen,axis=1)
salary_data['前年比']=salary_data['前年比'].str.replace('‐','0')
salary_data['前年比']=salary_data['前年比'].str.replace('↑万','0') #↑万という誤字がある
salary_data['前年比']=salary_data['前年比'].str.replace('↑','')
salary_data['前年比']=salary_data['前年比'].str.replace('±','')
salary_data['前年比']=salary_data['前年比'].str.replace('↓','-')
salary_data['前年比']=salary_data['前年比'].str.replace(',','')
salary_data['前年比']=salary_data['前年比'].str.replace('–','0') #「-」で埋められているセルを変動がないので0にする
salary_data.apply(ToYen,axis=1)
salary_data.to_csv('saraly_'+team_list[i]+'.csv',index=False)
print(i)
except:
print('error')
if __name__ == "__main__":
#セリーグのデータが詰まっているサイト
data_c = pd.read_html('https://baseball-dataroom.com/post-10511/')
#パリーグ
data_p = pd.read_html('https://baseball-dataroom.com/post-10516/')
#ファイル名に各チームの名前を付けるためにリストで管理します
team_list_c=['giants_p','giants_b','DeNA_p','DeNA_b','Tigers_p','Tigers_b','Carp_p','Carp_b','Dragons_p','Dragons_b','Swallows_p','Swallows_b','tsuba']
team_list_p=['Lions_p','Lions_b','SoftBank_p','SoftBank_b','Rakuten_p','Rakuten_b','Lotte_p','Lotte_b','Fighters_p','Fighters_b','OrixB_p','Orix_b']
mung_data(data_p,team_list_p)
mung_data(data_c,team_list_c)
スクレイピングしたそのあとは?
年俸のデータが集まったので、成績のデータと組み合わせて扱ってみると面白いでしょう。
その記事も次の機会に書いていこうと思います。
よろしければサポートをよろしくお願いします。サポートいただいた資金は活動費に使わせていただきます。