Whoscored 评分对比 - Python 实现方案
数据获取
Whoscored 网站有反爬机制,需使用 requests + BeautifulSoup 并模拟浏览器请求。

import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random
def get_whoscored_data(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/120.0.0.0 Safari/537.36',
'Accept-Language': 'en-US,en;q=0.9',
}
resp = requests.get(url, headers=headers, timeout=15)
soup = BeautifulSoup(resp.text, 'html.parser')
return soup
⚠️ Whoscored 数据通常通过 JS 动态加载,更推荐使用 Selenium / Playwright 或第三方库
soccerdata:
# 推荐:soccerdata 直接抓取 Whoscored 数据 import soccerdata as sd ws = sd.WhoScored(leagues="ENG-Premier League", seasons="2023/2024") player_stats = ws.read_player_season_stats(stat_type="summary") print(player_stats.columns.tolist())
典型对比场景
场景 1:同队球员评分对比
import matplotlib.pyplot as plt
import seaborn as sns
# 假设已有 dataframe
df = player_stats.reset_index()
# 筛选某队球员
team_df = df[df['team'] == 'Arsenal'].sort_values('rating', ascending=False)
plt.figure(figsize=(10, 6))
sns.barplot(data=team_df, x='rating', y='player', palette='viridis')'Arsenal 球员 Whoscored 评分 (2023/24)')
plt.xlabel('Whoscored Rating')
plt.tight_layout()
plt.show()
场景 2:多球员关键指标雷达图对比
import numpy as np
import matplotlib.pyplot as plt
def radar_compare(df, players, metrics):
"""多球员雷达图对比"""
N = len(metrics)
angles = np.linspace(0, 2 * np.pi, N, endpoint=False).tolist()
angles += angles[:1] # 闭合
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))
# 使用百分位归一化(消除量纲差异)
for player in players:
row = df[df['player'] == player].iloc[0]
values = []
for m in metrics:
pct = (df[m] < row[m]).mean() * 100 # 百分位
values.append(pct)
values += values[:1]
ax.plot(angles, values, label=player, linewidth=2)
ax.fill(angles, values, alpha=0.15)
ax.set_xticks(angles[:-1])
ax.set_xticklabels(metrics)
ax.set_title('Whoscored 多球员指标对比 (百分位)')
ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.1))
plt.show()
radar_compare(
player_stats.reset_index(),
players=['Bukayo Saka', 'Mohamed Salah', 'Son Heung-Min'],
metrics=['goals', 'assists', 'shots_per_game', 'key_passes_per_game',
'dribbles_per_game', 'rating']
)
场景 3:赛季评分趋势对比
# 若抓取到每轮评分数据
def plot_rating_trend(round_data, players):
plt.figure(figsize=(12, 5))
for p in players:
sub = round_data[round_data['player'] == p].sort_values('round')
plt.plot(sub['round'], sub['rating'], marker='o', label=p)
plt.axhline(7.0, color='gray', linestyle='--', label='优秀线 7.0')
plt.xlabel('比赛轮次')
plt.ylabel('Whoscored 评分')
plt.title('赛季评分趋势对比')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
实用对比分析函数
def compare_players(df, players, metrics=None, return_df=True):
"""返回多球员核心指标对比表"""
if metrics is None:
metrics = ['rating', 'goals', 'assists', 'shots_per_game',
'key_passes_per_game', 'pass_success',
'dribbles_per_game', 'tackles_per_game']
compare = df[df['player'].isin(players)][['player'] + metrics].copy()
compare = compare.set_index('player')
if return_df:
return compare.round(2)
# 使用
result = compare_players(df, ['Erling Haaland', 'Harry Kane', 'Kylian Mbappe'])
print(result.T) # 转置更直观
注意事项与避坑
| 问题 | 解决方案 |
|---|---|
| 反爬封锁 403 | 加 User-Agent、Referer;使用 Playwright |
| 数据动态加载 | 用 soccerdata 库 / Selenium 渲染后解析 |
| 换行符污染字段 | df['col'].str.replace('\n','') |
| 百分位口径 | 建议按位置(FW/MF/DF)分组计算百分位 |
| 评分无法跨赛季直接比较 | Whoscored 评分是相对值,需注意样本口径 |
| Compliance | 仅用于学习研究,遵守网站 robots.txt 及 ToS |
推荐工作流
- 数据层:
soccerdata拉取 Whoscored 数据 → 本地 CSV 缓存 - 清洗层:位置分组、去除缺席球员(出场时间<450min)
- 对比层:表格 + 雷达图 + 百分位排名
- 可视化:
matplotlib/seaborn/plotly(交互式)
需要我针对特定场景(如同位置球员对比、跨联赛对比、组建评分模型)展开完整代码吗?