python案例统计SofaScore综合评分?

wen python案例 2

Python 案例:统计 SofaScore 综合评分

下面给你一个完整的 Python 案例,演示如何从 SofaScore 获取并统计球队/球员的综合评分。

python案例统计SofaScore综合评分?

方案说明

SofaScore 官方 API(https://api.sofascore.com/api/v1/)是公开接口,但有反爬限制(Cloudflare 防护),所以下面给出两种方案:

  • 方案 A:直接调用 API(需要正确的请求头)
  • 方案 B:浏览器抓包 + 手动保存 JSON 后离线统计(更稳定)

方案 A:直接调用 API

import requests
import pandas as pd
import time
HEADERS = {
    "User-Agent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                   "AppleWebKit/537.36 (KHTML, like Gecko) "
                   "Chrome/122.0 Safari/537.36"),
    "Referer": "https://www.sofascore.com/",
    "Accept": "application/json, text/plain, */*",
}
def get_team_last_matches(team_id: int, page: int = 0):
    """获取球队最近比赛列表"""
    url = f"https://api.sofascore.com/api/v1/team/{team_id}/events/last/{page}"
    r = requests.get(url, headers=HEADERS, timeout=10)
    r.raise_for_status()
    return r.json().get("events", [])
def get_match_player_stats(match_id: int):
    """获取一场比赛的球员评分"""
    url = f"https://api.sofascore.com/api/v1/event/{match_id}/lineups"
    r = requests.get(url, headers=HEADERS, timeout=10)
    r.raise_for_status()
    data = r.json()
    rows = []
    for side in ("home", "away"):
        team_name = data[side]["team"]["name"]
        for player in data[side]["players"]:
            p = player["player"]
            stats = player.get("statistics", {}) or {}
            rows.append({
                "team": team_name,
                "player": p["name"],
                "position": p.get("position"),
                "rating": stats.get("rating"),
            })
    return rows
# ===== 示例:统计某球队近几场球员平均评分 =====
TEAM_ID = 44  # Manchester City 的 ID(可在 SofaScore URL 中找到)
all_rows = []
for page in range(3):          # 取最近3页
    events = get_team_last_matches(TEAM_ID, page)
    for ev in events:
        try:
            rows = get_match_player_stats(ev["id"])
            for r in rows:
                r["match_id"] = ev["id"]
                r["date"] = ev["startTimestamp"]
            all_rows.extend(rows)
            time.sleep(1)      # 避免触发限流
        except Exception as e:
            print("跳过比赛", ev["id"], e)
df = pd.DataFrame(all_rows)
df["rating"] = pd.to_numeric(df["rating"], errors="coerce")
df = df.dropna(subset=["rating"])
# 按球员统计平均分
summary = (df.groupby(["team", "player"])["rating"]
             .agg(["count", "mean", "max", "min"])
             .round(2)
             .sort_values("mean", ascending=False))
print(summary.head(20))
summary.to_csv("sofascore_ratings.csv", encoding="utf-8-sig")

方案 B:离线 JSON 统计(推荐)

API 被拦截,可以直接在浏览器 F12 → Network 里复制对应的 JSON 保存到本地,然后统计:

import json
import pandas as pd
# 假设你保存了 lineups 接口返回的 JSON
with open("lineups.json", "r", encoding="utf-8") as f:
    data = json.load(f)
rows = []
for side in ("home", "away"):
    team = data[side]["team"]["name"]
    for player in data[side]["players"]:
        stats = player.get("statistics", {}) or {}
        rows.append({
            "team": team,
            "player": player["player"]["name"],
            "position": player["player"].get("position"),
            "rating": stats.get("rating"),
            "goals": stats.get("goals", 0),
            "assists": stats.get("goalAssist", 0),
            "passes": stats.get("totalPass", 0),
        })
df = pd.DataFrame(rows)
df["rating"] = pd.to_numeric(df["rating"], errors="coerce")
df = df.dropna(subset=["rating"])
# 全场平均
print("全场平均评分:", round(df["rating"].mean(), 2))
# 各队平均
print("\n各队平均评分:")
print(df.groupby("team")["rating"].mean().round(2))
# MVP
print("\n全场最佳:")
print(df.sort_values("rating", ascending=False).head(3))
# 分位置平均
print("\n按位置评分:")
print(df.groupby("position")["rating"].mean().round(2))

综合评分公式(自定义加权)

SofaScore 原生 rating 是 0–10 分,如果你想做多维度综合评分,可以按权重合成:

import numpy as np
def combined_score(row):
    """
    示例权重:
    SofaRating 60% + 进球*0.5 + 助攻*0.3 + 传球成功率 10%
    """
    rating = row["rating"] or 0
    goal   = (row.get("goals")   or 0) * 0.5
    assist = (row.get("assists") or 0) * 0.3
    # 传球成功率归一化到 0-1
    acc = (row.get("accuratePass") or 0) / max(row.get("totalPass") or 1, 1)
    return 0.6 * rating + goal + assist + 0.1 * (acc * 10)
df["combined"] = df.apply(combined_score, axis=1)
# 结果排序
top = df.sort_values("combined", ascending=False)[
    ["player", "team", "rating", "goals", "assists", "combined"]
].head(10)
print(top.round(2))

常见问题

问题 说明
403 / Cloudflare SofaScore 有反爬,需完整浏览器头或使用 Playwright
Team ID 怎么找 打开 SofaScore 球队页面,URL 中 team/44 数字即 ID
球员评分在哪个字段 /event/{id}/lineups → players[].statistics.rating
限流 每请求间隔 ≥ 1s,建议加缓存
球员姓名重复 用 player.id 分组更可靠

若使用 Playwright 绕过防护(简版)

from playwright.sync_api import sync_playwright
import json
with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    # 先访问主页拿 cookie
    page.goto("https://www.sofascore.com/")
    # 直接用页面上下文请求 API
    resp = page.request.get(
        "https://api.sofascore.com/api/v1/team/44/events/last/0"
    )
    print(resp.json())
    browser.close()

如果你告诉我具体需求(统计某球员赛季评分、某联赛所有球队平均分、或按位置分组统计),我可以把代码进一步细化成可直接运行的脚本。

抱歉,评论功能暂时关闭!