免费获取足球xG数据的完整指南:用Understat异步Python包快速搭建数据管线
免费获取足球xG数据的完整指南:用Understat异步Python包快速搭建数据管线
【免费下载链接】understatAn asynchronous Python package for https://understat.com/.项目地址: https://gitcode.com/gh_mirrors/un/understat
深夜十一点,足球数据分析师阿凯还在为周末的战术报告发愁:为了凑齐两支球队的xG(预期进球)和PPDA(每次防守动作的传球数)数据,他在十几个网页之间来回切换,手动复制、清洗、对齐,三个小时就这么无声无息地溜走了。这不是他一个人的困境——足球数据免费拿不到,商业API年费动辄数万美元,自己写爬虫又得跟JavaScript渲染页面死磕。直到他遇见了Understat,一个基于aiohttp的免费开源异步Python包,用十几行代码就能把 understat.com 上的高级指标一次性拉回来,还附送排行榜和球员明细。
它凭什么行?——免费开源,还自带异步引擎
说白了,它相当于给数据采集这件事发了一张"免考卷":你不需要懂JS逆向,不用手动拼请求头,更不用逐页解析HTML。
- 零成本:MIT开源协议,随便拿去用、随便改,对比一下动辄五位数的商业API,差距一目了然。
- 纯异步架构:整个库构建在 aiohttp 之上,一个会话复用连接池,批量取数时并发效率比同步脚本高一个量级。
- 解析已封装:请求头和JSON解析都在包内部完成(核心逻辑见
understat/utils.py的get_data),你只需要关心"要什么数据",而不是"怎么要到数据"。
一句话:别人还在研究怎么绕过反爬,你已经拿到结构化数据了。
它到底能做什么?——从联赛积分榜到单次射门,全覆盖
它的接口设计得很"贴地气":所有方法都挂在唯一的Understat类上,按数据维度划分,看一眼方法名就知道能拿什么。
| 数据维度 | 代表方法 | 你能拿到什么 |
|---|---|---|
| 联赛 | get_league_players/get_league_results/get_league_table | 全联赛球员统计、赛果、含xG/xGA/PPDA/OPPDA/xPTS的积分榜 |
| 球队 | get_team_players/get_team_results | 单支球队的球员数据和逐场结果 |
| 球员 | get_player_shots/get_player_matches | 每次射门的细节、逐场表现 |
| 比赛 | get_match_players/get_match_shots | 单场首发名单与全部射门记录 |
支持的联赛覆盖英超(epl)、西甲(la_liga)、德甲(bundesliga)、意甲(serie_a)、法甲(ligue_1)、俄超(rfpl)六大主流赛事。更贴心的是,几乎所有方法都支持options参数,比如想看某支球队的球员,直接传{"team_title": "Manchester United"}就能过滤,省去一堆手工筛选。
上手到底多简单?——三行初始化,一行取数
不夸张地说,装完包之后,跑通第一个查询用不了两分钟。✅ 安装只需要一条命令:
pip install understat然后是最小可运行的示例:
import asyncio import aiohttp from understat import Understat async def main(): async with aiohttp.ClientSession() as session: # 建一个连接会话 us = Understat(session) # 把会话交给它 players = await us.get_league_players("epl", 2023) # 拉英超整季球员 print(f"共 {len(players)} 名球员") asyncio.run(main())注意一个细节:Understat不自己管理连接,而是要求你传入aiohttp.ClientSession。这不是麻烦,而是设计上的聪明之处——会话在多个请求间复用,连接开销被压到最低。
跟着走一遍:找出英超"被低估"的射手
现在来点实战。假设你是球探,想找出那些"创造的机会远多于实际进球"的前锋——这类球员一旦射门手感回归,往往就是转会市场上的价值洼地。从初始化、取数、加工到输出,一气呵成:
import asyncio import aiohttp from understat import Understat async def undervalued_scorers(season=2023, top_n=5): """找出英超赛季中 xG 明显高于实际进球的前锋。""" async with aiohttp.ClientSession() as session: us = Understat(session) players = await us.get_league_players("epl", season) # 只保留出场超过900分钟、位置带前锋(F)标记的球员 forwards = [p for p in players if int(p["time"]) > 900 and "F" in p["position"]] # 按 (xG - 进球) 降序,差值越大说明越"背运" forwards.sort(key=lambda p: float(p["xG"]) - float(p["goals"]), reverse=True) print(f"{'球员':<20}{'进球':<6}{'xG':<8}{'差距'}") for p in forwards[:top_n]: gap = float(p["xG"]) - float(p["goals"]) print(f"{p['player_name']:<18}{p['goals']:<6}" f"{float(p['xG']):.2f}{'':<2}{gap:+.2f}") asyncio.run(undervalued_scorers())跑出来的结果会是类似这样的榜单:
| 球员 | 进球 | xG | 差距 |
|---|---|---|---|
| 某前锋A | 8 | 12.43 | +4.43 |
| 某前锋B | 9 | 12.10 | +3.10 |
| 某前锋C | 11 | 13.87 | +2.87 |
差距为正,意味着"机会明显多于产出"。比如榜单第一位的球员 xG 高达12.4却只进8球,在样本量足够的情况下,他的进球数大概率会向xG回归——这正是球探报告里最值得标注的一类信号。整套流程:初始化会话 → 整季取数 → 内存过滤排序 → 榜单输出,全程异步,十几秒跑完。换作手动整理,两小时起步。
避坑指南:三个新手最容易踩的坑
第一次用这类异步库,难免在环境上栽跟头。下面是高频误区速查表:
| ⚠️ 高频误区 | 典型症状 | 正确姿势 |
|---|---|---|
| 在同步脚本里直接调用 | 报协程未等待(asyncio)相关错误 | 用asyncio.run(main())包一层 |
| 把返回字段当数字直接用 | 排序、计算时报TypeError | 库返回的goals、xG等多为字符串,先float()转换 |
| 频繁新建session狂拉数据 | 请求被限流、超时 | 全局复用同一个ClientSession,控制并发和请求间隔 |
你的第一步行动:pip install understat,然后把上面的第一段代码原样跑一遍,看到球员数量打印出来就算入门了。想摸清每个方法的细节,翻一翻docs/classes/understat.rst的完整API参考;想确认环境没问题,pytest tests/跑一遍测试即可。
🚀 当别人还在复制粘贴表格、对着网页截图手动录入的时候,你已经把整个赛季的xG数据管线攥在手里了——这就是数据驱动决策的真正分水岭。
【免费下载链接】understatAn asynchronous Python package for https://understat.com/.项目地址: https://gitcode.com/gh_mirrors/un/understat
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
