Pythonでスクレイピング ~Wリーグ版LINE Botを作った~
まえがき
Bリーグ版選手情報Botを作ったらWリーグ好きの後輩からリクエストをもらった。
Bリーグ版はTwitterで拡散して頂き現在友達989人!ありがとうございます。1000人いかないかな〜
Wリーグ版LINE Bot
後輩が丁寧に宣伝してくれました
Wリーグファンの皆様へ。
— m (@mbasket78) 2019年2月11日
先輩が便利なLINE BOTを作ってくれました!https://t.co/HNpcdc8RVF
チーム名と番号を送ると選手のプロフィールを返してくれます。チーム名だけだと選手一覧を返してくれます。
試合観戦のお供に是非! pic.twitter.com/aucRUejSYT
この宣伝の結果Wリーグ版の方が友達が多くなり、Bリーグ版を真面目に宣伝するに至りました笑。
結果Bリーグが数倍になってしまったので、よかったらこちらをご登録の上、Wリーグを観に行ってください!
今シーズンは終わってしまいましたが、チーム間の実力差が埋まってきて面白くなってきています。
身体能力は男子に劣るものの、テンポの速さだったりシュートの正確さは男子以上です。(世界ランク10位は伊達じゃない)
実装
Bリーグ版とやることは変わらないので、まるっと載せます。
import re import requests from bs4 import BeautifulSoup import gspread from oauth2client.service_account import ServiceAccountCredentials # wリーグ公式HP BASE_URL = "https://www.wjbl.org" def list_team_url(): url = BASE_URL + "/team/list_html/" res = requests.get(url) soup = BeautifulSoup(res.content, "html.parser") content = soup.find(id="main_contents_outer") teams_content = content.find_all(class_="team_block") team_list = [] for div in teams_content: name = re.sub(r"[\s]","",div.find("h3").text) uri_block = div.find(class_="btn09") uri = uri_block.get("href") team_list.append({"name": name, "uri": uri}) return team_list def get_playersdata(team): url = BASE_URL + team["uri"] res = requests.get(url) soup = BeautifulSoup(res.content, "html.parser") div = soup.find(class_="team-color-table") table = div.find('table') blocks = table.findAll('tr') players_data = [] for block in blocks: data = {} values = block.findAll('td') if len(values) == 0: continue data["team"] = team["name"] data["num"] = values[0].text data["name"] = re.sub(r"[\s]","",values[1].text) data["url"] = BASE_URL + values[1].a.get('href') data["position"] = values[2].text data["height"] = values[3].text data["weight"] = values[4].text data["birth"] = values[5].text data["home"] = values[6].text data["career"] = values[7].text detail = get_player_detail(data["url"]) data["blood"] = detail["blood"] data["nickname"] = detail["nickname"] data["ppg"] = detail["ppg"] data["rpg"] = detail["rpg"] data["apg"] = detail["apg"] players_data.append(data) return players_data def get_player_detail(url): res = requests.get(url) soup = BeautifulSoup(res.content, "html.parser") table = soup.findAll('table', class_="table04") data = {} data["blood"] = table[0].findAll('td')[5].text data["nickname"] = table[0].findAll('td')[6].text data["ppg"] = table[1].findAll('td')[0].text data["rpg"] = table[1].findAll('td')[1].text data["apg"] = table[1].findAll('td')[2].text return data def write_to_sheet(sheet, team_data): cell_list = sheet.range('A1:O20') i = 0 for player in team_data: data = list(player.values()) for n in range(15): cell_list[i].value = data[n] i += 1 while cell_list[i].value != "": cell_list[i].value = "" i += 1 sheet.update_cells(cell_list) if __name__ == "__main__": team_list = list_team_url() for team in team_list: team_name = team['name'] team_data = get_playersdata(team) sheets = G_CLIENT.open_by_key(SHEET_ID) try: team_sheet = sheets.worksheet(team_name) except: print('new '+team_name) team_sheet = sheets.add_worksheet(title=team_name, rows="30", cols="20") write_to_sheet(team_sheet, team_data)
相違点
- チーム名を自動取得にした
TwitterでBリーグ版広島が反応しないと言われ、よくみたら手動で書き起こしていたチーム一覧に広島が入っていなかった。人間がやるからミスするんだよ・・・ - 選手情報がチームのロスター一覧で取れるものと選手個人ページで取れるものが違ったために
get_playersdata
のなかでget_player_detail
を呼び、2段階で取得している
…くらいかな
なおこちらは絶対に週末しか試合をしない&できたのがプレーオフ直前でほとんどスタッツを更新する必要がなさそうだったのでローカルで実行しています。
来シーズン始まったらBリーグ版同様Herokuにのせようかな。
まとめ
- ほとんど流用なので、全部で2時間ほどでできた(スクレイピング1時間+LINE接続30分+文章その他整形30分)
- 100行くらいでスッキリ
- 自動化できるところは自動化しましょう
雑で内容ほとんど解説してないので、なにか聞きたいことあればお気軽にどうぞ。
W杯楽しみですね!!! 🇺🇸🇹🇷🇨🇿🇯🇵