SofaScore 综合评分统计脚本
SofaScore 没有公开 API,但网页端有内部接口,下面给出一套实用脚本(Python),支持球员评分、球队评分、赛事统计。

核心思路
SofaScore 数据接口域名:https://api.sofascore.com/api/v1/
常用端点:
| 用途 | 端点 |
|------|------|
| 赛事列表 | /unique-tournament/{id}/season/{seasonId}/events/round/{round} |
| 比赛详情 | /event/{eventId} |
| 球员评分 | /event/{eventId}/lineups |
| 比赛统计 | /event/{eventId}/statistics |
⚠️ 必须有 User-Agent,否则返回 403。
Python 脚本
import requests
import time
import json
from statistics import mean
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/122.0.0.0 Safari/537.36",
"Accept": "application/json",
}
BASE = "https://api.sofascore.com/api/v1"
def get_json(url, retry=3):
for i in range(retry):
try:
r = requests.get(url, headers=HEADERS, timeout=15)
if r.status_code == 200:
return r.json()
time.sleep(1.5)
except Exception as e:
print(f"[warn] {e}")
time.sleep(2)
return None
def get_event_lineups(event_id):
"""获取一场比赛的球员评分"""
url = f"{BASE}/event/{event_id}/lineups"
data = get_json(url)
if not data:
return None, None
players = []
for side in ("home", "away"):
for p in data.get(side, {}).get("players", []):
info = p.get("player", {})
stats = p.get("statistics", {}) or {}
rating = stats.get("rating")
if rating is None:
continue
players.append({
"name": info.get("name"),
"team": side,
"position": p.get("position"),
"substitute": p.get("substitute", False),
"rating": float(rating),
})
return players, data
def team_rating(players):
"""按球队聚合平均评分(仅首发)"""
starters = [p for p in players if not p["substitute"]]
if not starters:
return {}
result = {}
for side in ("home", "away"):
arr = [p["rating"] for p in starters if p["team"] == side]
if arr:
result[side] = round(mean(arr), 2)
return result
def stat_overview(event_id):
"""获取整场关键统计数据"""
url = f"{BASE}/event/{event_id}/statistics"
data = get_json(url)
if not data:
return {}
summary = {}
for period in data.get("statistics", []):
period_name = period.get("period")
for group in period.get("groups", []):
for item in group.get("statisticsItems", []):
key = item.get("name")
summary.setdefault(period_name, {})[key] = {
"home": item.get("home"),
"away": item.get("away"),
}
return summary
def analyze_event(event_id, verbose=True):
players, _ = get_event_lineups(event_id)
if not players:
print(f"[event {event_id}] 无评分数据")
return None
ratings = [p["rating"] for p in players]
summary = {
"event_id": event_id,
"player_count": len(players),
"avg_rating": round(mean(ratings), 2),
"max_rating": max(ratings),
"min_rating": min(ratings),
"team_avg": team_rating(players),
"top5": sorted(players, key=lambda x: -x["rating"])[:5],
}
if verbose:
print(f"\n=== Event {event_id} ===")
print(f"平均评分: {summary['avg_rating']} 最高: {summary['max_rating']}")
print(f"球队均分: {summary['team_avg']}")
print("Top 5:")
for p in summary["top5"]:
print(f" {p['rating']:.1f} {p['name']} ({p['team']})")
return summary
if __name__ == "__main__":
# 用赛事 URL 里的数字替换 event_id
# 例:https://www.sofascore.com/event/12345678
EVENTS = [12345678, 12345679]
all_summary = []
for eid in EVENTS:
res = analyze_event(eid)
if res:
all_summary.append(res)
time.sleep(2) # 防止限流
with open("sofascore_summary.json", "w", encoding="utf-8") as f:
json.dump(all_summary, f, ensure_ascii=False, indent=2)
print("\n已保存 sofascore_summary.json")
如何拿 event_id / tournament_id
- 打开 SofaScore 网页任意比赛
- URL 形如
https://www.sofascore.com/event/12345678/...,中间数字即 event_id - 要批量抓整轮赛事:
- 比赛 URL
.../unique-tournament/17/season/61627→ tournament=17,season=61627 - 调
/unique-tournament/17/season/61627/events/round/10拿到该轮所有 event_id
- 比赛 URL
批量采集示例:
def events_of_round(tid, sid, rnd):
url = f"{BASE}/unique-tournament/{tid}/season/{sid}/events/round/{rnd}"
data = get_json(url)
return [e["id"] for e in data.get("events", [])]
注意事项
| 项 | 说明 |
|---|---|
| 频率 | 建议 ≥1.5s/次,否则易被封 IP |
| UA | 必须带浏览器 UA |
| Cloudflare | 大量请求会触发 403,可考虑 cloudscraper 或代理池 |
| 商用 | SofaScore 数据版权归其所有,仅供个人学习 |
| 订阅者评分 | 该接口只返回官方评分,不含 SofaScore 用户投票分;用户投票需要抓 /event/{id}/polls |
可选增强
-
持久化:写入 SQLite / CSV
import csv with open("ratings.csv", "w", newline="", encoding="utf-8") as f: w = csv.writer(f) w.writerow(["event_id", "name", "team", "position", "rating"]) for s in all_summary: for p in s["top5"]: w.writerow([s["event_id"], p["name"], p["team"], p["position"], p["rating"]]) -
可视化:用
matplotlib画球队均分柱状图 -
增量更新:按日期查询
/sport/football/scheduled-events/2024-05-01
你的目标是单个联赛整赛季统计,还是具体某几场比赛?告诉我我可以把脚本改成对应的批量采集版本。