審判ファンの文系SEがFlaskでプロ野球審判出場記録アプリを作る④【Python】【Selenium】
今回のヘッダーは2006年の東さんにしてみました。いい表情してますね!ちらっと16年前の私の推しがいるのもポイント高いです。YouTubeで審判の動画を見てると「あなたこんなのにも興味あるでしょ?」と昔の動画をオススメされるわけですが、昨日は2006年の「フルスタレンガ事件」の一部始終が出てきました。
自分がプロ野球を見始めたのは、セ・パ審判部が統合された2011年からなのでこの「事件」は知りませんでした。自分セ・パ分かれてた頃の野球を知らないんですよね。
プレイボールかける前から吹雪いてるし試合始まったらレンガ事件、そしてまた雪、暴投、エラーと散々な試合展開でこれが私の知らない時代のパ・リーグの野球か……!と思い知らされました。こういう事件もSeleniumで取得してこの日の試合はこんなことがありました、っていうのも分かったら面白いんじゃないかなと技術的な部分はさておき夢が膨らみました。
さて、今回は昨年書いた記事の酷くて冗長なコードがどう改善されたかをまとめます。まだまだ改良の余地はありますが、大幅に行数を減らすことに成功しました。
四人制と六人制の試合の条件分岐
去年のコードでは、審判のポジション毎、試合の種類別にリストを作っていて、Seleniumで取得してきた審判の記述を正規表現でいらない文字を削除し「、」で区切ってリスト化したものを要素番号で条件分岐させていました(球審ではあれば要素番号が0か4で割り切れる数)。
試合の種類別にも条件分岐させていたので、「オールスター」「CS」「日本シリーズ」と書かれていれば六人制用のリストに入れていました(球審であれば要素番号が0か6で割り切れる数)。そのため長めな行数になっていました。さらに、不必要な文字を削除するのに全てリストに入れてから文字列にして、正規表現で削除してから再度リストにするという長ったらしいことをしていました。
やっと使い方が分かった関数と辞書型
初心者向けの解説を読んでもいまいち理解できなかった関数の使い方を理解することが出来ました。仮引数は本当に仮なんですね。リストや辞書型に入れる前にSeleniumで取得した文字列を関数に引き渡して上げることで削除したい文字列や型変換できるので、後から文字列にして再度リストにして……という手間を無くすことが出来ました。
#審判団の不要な文字を削除する関数
def moji_clear(ump):
ump = re.sub('[球塁線審()一二三右左:、]','',ump)
ump = ump.split(" ")
#4人制の場合
if len(ump) == 4:
UK_umpire = ump[0]
first_umpire= ump[1]
second_umpire = ump[2]
third_umpire = ump[3]
left_umpire = ""
right_umpire = ""
else:
UK_umpire = ump[0]
first_umpire= ump[1]
second_umpire = ump[2]
third_umpire = ump[3]
left_umpire = ump[4]
right_umpire = ump[5]
return UK_umpire,first_umpire,second_umpire,third_umpire,left_umpire,right_umpire
いらない文字列を削除し、リストにした時の要素数が4だったら四人制、6だったら六人制で分岐させています。四人制であったら線審のリストには''を入れることでズレないようにします。 試合詳細画面から情報を取得するメインの処理も関数にします。
#辞書に記載していく関数
dic_game_info = []
def dic_write():
umpire = moji_clear(driver.find_element_by_class_name("referee_info").text)
dic_game_info.append({"日時":game_day_clear(driver.find_element_by_css_selector("#game_stats > div.game_tit > time").text),
"コード":game_code_clear(driver.find_element_by_css_selector("#game_stats > div.game_tit > h3").text),
"先攻チーム":top_team_clear(driver.find_element_by_xpath("/html/body/div/div/div[3]/section/table[2]/tbody/tr[1]/th").text),
"先攻スコア":(score_clear(driver.find_element_by_css_selector("#tablefix_ls > tbody > tr.top > td.total-1").text)),
"後攻スコア": score_clear(driver.find_element_by_css_selector("#tablefix_ls > tbody > tr.bottom > td.total-1").text),
"後攻チーム":top_team_clear(driver.find_element_by_xpath("/html/body/div/div/div[3]/section/table[2]/tbody/tr[2]/th").text),
"球場名":driver.find_element_by_class_name("place").text,
"試合時間":game_info_clear(driver.find_element_by_class_name("game_info").text),
"球審":umpire[0],
"一塁":umpire[1],
"二塁":umpire[2],
"三塁":umpire[3],
"線審(左)":umpire[4],
"線審(右)":umpire[5]
})
実際にページをループさせる処理では取得した当日に試合があるかないかでループさせる回数が変わってきてしまうので条件分岐させていますが、関数にしておくと2回同じことを書かなくて楽です。関数の中の関数の呼び出しも問題なく出来ています。
そして辞書型。「辞書型を使うとコードを短縮できるよ」とアドバイスを貰ったもののどう記述すればいいのか分かりませんでしたが慣れると本当に便利です。ただここで苦労したのはKEYが同じになってしまうと値が上書きされてしまうというところです。
リストの中に辞書型を追加していくことでうまくいきました。ちょっと沼ったのは先の四人制、六人制で分岐させている関数の戻り値をどう辞書型に追加するかという部分。umpireというリストに戻り値を格納して、要素番号毎に値を入れるやり方で出来ました。というかこれを書いてて思ったんですが、普通に戻り値に入れてる変数を指定しても行けそうな気がして来ました。家に帰ったら試してみます。
あとはPandasでデータフレームに変換してCSVにしたりデータベースに入れればOKです。関数と辞書型のおかげで昨年ダラダラ書いていたコード(よく書いたなとは思う)を200行近く減らすことが出来ました。可読性が上がるとちょっとプログラミングできるようになった感じがあって嬉しいです。
今はまだ取得したデータをCSVファイルに出力するところまでしか出来ていないのでこれを更新分のみデータベースに入れる処理を定期的に実行するようにしていきたいです。
この記事が気に入ったらサポートをしてみませんか?