はじめに
日本フットボールリーグオフィシャルWebサイトの日程・結果から試合結果をスクレイピング
スクレイピング
import requests
from bs4 import BeautifulSoup
url = "http://www.jfl.or.jp/jfl-pc/view/s.php?a=1542&f=2020A001_spc.html"
r = requests.get(url)
r.raise_for_status()
soup = BeautifulSoup(r.content, "html.parser")
data = []
for table in soup.find_all("table", class_="table-data"):
trs = table.find_all("tr")
th = int(trs[0].th.get_text(strip=True).strip("第節"))
for i, tr in enumerate(trs[1:], 1):
tds = [td.get_text(strip=True) for td in tr.find_all("td")]
data.append([th, i] + tds)
データラングリング
import pandas as pd
df = pd.DataFrame(
data, columns=["節", "番号", "日にち", "時間", "ホーム", "スコア", "アウェイ", "スタジアム", "備考"]
)
df.set_index(["節", "番号"], inplace=True)
df
df_score = (
df["スコア"].str.split("-", expand=True).rename(columns={0: "ホーム得点", 1: "アウェイ得点"})
)
df_score["ホーム得点"] = pd.to_numeric(df_score["ホーム得点"], errors="coerce").astype("Int64")
df_score["アウェイ得点"] = pd.to_numeric(df_score["アウェイ得点"], errors="coerce").astype("Int64")
df1 = pd.concat([df, df_score], axis=1).dropna(subset=["ホーム得点", "アウェイ得点"])
# ホームの結果のみ
df_home = df1.loc[:, ["ホーム", "ホーム得点", "アウェイ得点"]].copy()
df_home.rename(columns={"ホーム": "チーム名", "ホーム得点": "得点", "アウェイ得点": "失点"}, inplace=True)
df_home["戦"] = "ホーム"
df_home.head()
# アウェイの結果のみ
df_away = df1.loc[:, ["アウェイ", "アウェイ得点", "ホーム得点"]].copy()
df_away.rename(columns={"アウェイ": "チーム名", "アウェイ得点": "得点", "ホーム得点": "失点"}, inplace=True)
df_away["戦"] = "アウェイ"
df_away.head()
# ホームとアウェイを結合
df_total = pd.concat([df_home, df_away])
# 得失点を計算
df_total["得失点"] = df_total["得点"] - df_total["失点"]
# 勝点追加
df_total["勝点"] = df_total["得失点"].apply(lambda x: 1 if x == 0 else 0 if x < 0 else 3)
df_total["勝敗"] = df_total["勝点"].replace({0: "敗戦", 1: "引分", 3: "勝利"})
df_total.head()
# 得点・失点・得失点・勝点 集計
pv_score = df_total.pivot_table(
index="チーム名", values=["得点", "失点", "得失点", "勝点"], aggfunc=sum
)
pv_score
# 勝敗集計
pv_wl = pd.crosstab(df_total["チーム名"], [df_total["戦"], df_total["勝敗"]])
pv_wl
# 列名変更
# pv_wl.columns = ["勝利A", "引分A", "敗戦A", "勝利H", "引分H", "敗戦H"]
pv_wl.rename(columns={"アウェイ": "A", "ホーム": "H"}, inplace=True)
pv_wl.columns = pv_wl.columns.swaplevel(0, 1)
pv_wl.columns = ["".join(col).strip() for col in pv_wl.columns.values]
# 合計追加
pv_wl["勝利"] = pv_wl["勝利H"] + pv_wl["勝利A"]
pv_wl["引分"] = pv_wl["引分H"] + pv_wl["引分A"]
pv_wl["敗戦"] = pv_wl["敗戦H"] + pv_wl["敗戦A"]
# 試合数追加
pv_wl["試合数"] = pv_wl["勝利"] + pv_wl["引分"] + pv_wl["敗戦"]
# 確認
pv_wl
df2 = df_total.copy()
# 評価値を作成
df2["評価値"] = ((df2["勝点"]) * 10000) + (df2["得失点"] * 100) + df2["得点"]
df2
# 評価値集計
df3 = df2.pivot_table(
values="評価値", index="チーム名", columns="節", aggfunc=sum, fill_value=0
)
df3
# 評価値の累計和
df_eval = df3.apply(lambda d: d.cumsum(), axis=1)
df_eval
# 評価値から順位作成
df_chart = df_eval.rank(ascending=False, method="min").astype(int)
df_chart.sort_values(by=df_chart.columns[-1], inplace=True)
df_chart
# 最終順位取得
s1 = df_chart.iloc[:, -1]
s1.name = "順位"
df_diff = df_chart.diff(axis=1).fillna(0).astype(int)
df_diff
# 前節差分
s2 = df_diff.iloc[:, -1].apply(lambda x: "-" if x == 0 else "▼" if x < 0 else "▲")
s2.name = "前節"
s2
# 全部を結合
df4 = pd.concat([pv_score, pv_wl], axis=1).join([s1, s2])
# 順位で昇順
df4.sort_values(["順位"], inplace=True)
df_rank = df4.reset_index().loc[
:,
[
"前節",
"順位",
"チーム名",
"勝点",
"試合数",
"勝利",
"勝利H",
"勝利A",
"引分",
"引分H",
"引分A",
"敗戦",
"敗戦H",
"敗戦A",
"得失点",
"得点",
"失点",
],
]
df_rank
print(df_rank.to_markdown(index=False))
順位表
2020/10/07現在
前節 | 順位 | チーム名 | 勝点 | 試合数 | 勝利 | 勝利H | 勝利A | 引分 | 引分H | 引分A | 敗戦 | 敗戦H | 敗戦A | 得失点 | 得点 | 失点 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | 1 | Honda FC | 18 | 8 | 5 | 2 | 3 | 3 | 2 | 1 | 0 | 0 | 0 | 11 | 15 | 4 |
- | 2 | ヴェルスパ大分 | 15 | 7 | 5 | 2 | 3 | 0 | 0 | 0 | 2 | 2 | 0 | 5 | 14 | 9 |
- | 3 | テゲバジャーロ宮崎 | 14 | 7 | 4 | 1 | 3 | 2 | 1 | 1 | 1 | 1 | 0 | 6 | 11 | 5 |
- | 4 | MIOびわこ滋賀 | 13 | 8 | 4 | 2 | 2 | 1 | 1 | 0 | 3 | 1 | 2 | 4 | 17 | 13 |
- | 5 | いわきFC | 13 | 8 | 4 | 3 | 1 | 1 | 0 | 1 | 3 | 1 | 2 | 0 | 14 | 14 |
- | 6 | ソニー仙台FC | 13 | 8 | 4 | 1 | 3 | 1 | 1 | 0 | 3 | 1 | 2 | 0 | 13 | 13 |
- | 7 | 松江シティFC | 12 | 9 | 4 | 3 | 1 | 0 | 0 | 0 | 5 | 1 | 4 | -5 | 10 | 15 |
▼ | 8 | FC大阪 | 11 | 8 | 3 | 2 | 1 | 2 | 2 | 0 | 3 | 1 | 2 | 3 | 12 | 9 |
▲ | 9 | 奈良クラブ | 11 | 8 | 3 | 1 | 2 | 2 | 1 | 1 | 3 | 2 | 1 | 2 | 10 | 8 |
▲ | 10 | 鈴鹿ポイントゲッターズ | 11 | 8 | 3 | 2 | 1 | 2 | 0 | 2 | 3 | 3 | 0 | 0 | 9 | 9 |
▲ | 11 | ホンダロックSC | 10 | 8 | 3 | 0 | 3 | 1 | 0 | 1 | 4 | 4 | 0 | -7 | 8 | 15 |
- | 12 | 東京武蔵野シティFC | 8 | 6 | 2 | 2 | 0 | 2 | 0 | 2 | 2 | 1 | 1 | 1 | 7 | 6 |
- | 13 | ヴィアティン三重 | 8 | 8 | 2 | 1 | 1 | 2 | 1 | 1 | 4 | 2 | 2 | -3 | 8 | 11 |
- | 14 | ラインメール青森 | 8 | 7 | 2 | 1 | 1 | 2 | 1 | 1 | 3 | 1 | 2 | -5 | 7 | 12 |
- | 15 | FCマルヤス岡崎 | 5 | 8 | 1 | 0 | 1 | 2 | 1 | 1 | 5 | 3 | 2 | -5 | 7 | 12 |
- | 16 | 高知ユナイテッドSC | 3 | 8 | 0 | 0 | 0 | 3 | 2 | 1 | 5 | 2 | 3 | -7 | 9 | 16 |