kta-basket's blog

バスケット好きによるなにか

Pythonでスクレイピング ~Wリーグ版LINE Botを作った~

まえがき

Bリーグ版選手情報Botを作ったらWリーグ好きの後輩からリクエストをもらった。

Bリーグ版はTwitterで拡散して頂き現在友達989人!ありがとうございます。1000人いかないかな〜

Wリーグ版LINE Bot

後輩が丁寧に宣伝してくれました


この宣伝の結果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)


相違点

  • チーム名を自動取得にした
    TwitterBリーグ版広島が反応しないと言われ、よくみたら手動で書き起こしていたチーム一覧に広島が入っていなかった。人間がやるからミスするんだよ・・・
  • 選手情報がチームのロスター一覧で取れるものと選手個人ページで取れるものが違ったためにget_playersdataのなかでget_player_detailを呼び、2段階で取得している

…くらいかな


なおこちらは絶対に週末しか試合をしない&できたのがプレーオフ直前でほとんどスタッツを更新する必要がなさそうだったのでローカルで実行しています。
来シーズン始まったらBリーグ版同様Herokuにのせようかな。

まとめ

  • ほとんど流用なので、全部で2時間ほどでできた(スクレイピング1時間+LINE接続30分+文章その他整形30分)
  • 100行くらいでスッキリ
  • 自動化できるところは自動化しましょう

雑で内容ほとんど解説してないので、なにか聞きたいことあればお気軽にどうぞ。


W杯楽しみですね!!! 🇺🇸🇹🇷🇨🇿🇯🇵