用 Python 调用足球赛程 API:按日期查询与时区处理
做球迷小程序、赛程日历或体育资讯专题,第一步往往是“获取今天的比赛”。但接口里的日期不一定等于用户所在时区的日期。本文用足球赛程 API 获取比赛列表,再用 Python 转换北京时间,避免漏掉凌晨比赛或把未开赛的 0–0 写成平局。
接口怎么选
以下均为 GET,完整参数见足球 API 文档。
| 操作 | 必填参数 | 用途 |
|---|---|---|
get-search-all | search | 按名称搜索球队与比赛,获取带类型的 ID |
get-matches-events-by-date | date | 用 YYYYMMDD 查询赛程和赛果 |
get-match-event-detail-by-event-id | eventid | 补充比赛身份、赛事和轮次 |
get-standing-all-by-league-id | leagueid | 读取总积分榜 |
get-team-detail-by-team-id | teamid | 获取球队与球场资料 |
比赛、球队、联赛和球员 ID 不能互换。先搜索或查赛程,再带着正确类型的编号查询详情,不要靠名字拼接数据。
curl:从搜索到日期查询
在控制台取得自己有权使用的 API Key,并确认项目权限及可用额度。此流程无需球队账号、会话或 Cookie。以下使用公开搜索词和已验证的日期参数;占位符换成自己的 Key 后才可运行,不保证该日期始终有数据。
curl --get 'https://api.opendata-api.com/api/project/football/get-search-all?key=YOUR_API_KEY' \
--data-urlencode 'search=Real Madrid'
curl --get 'https://api.opendata-api.com/api/project/football/get-matches-events-by-date?key=YOUR_API_KEY' \
--data-urlencode 'date=20261008'
每次实际执行都可能消耗额度;阅读、复制示例或展开文档不会发送数据请求。不要把 Key 放进前端页面、仓库或截图,含 Key 的命令历史和访问日志也应妥善保护。
Python:检查状态,再转换北京时间
需要 Python 3.9+、requests 和系统时区数据库;若找不到时区,可安装 tzdata。把自己的 Key 注入服务端环境变量 OPENDATA_API_KEY。示例只请求一个日期,然后筛选返回记录中的北京时间目标日;它不是完整日程保证,也不附虚构成功响应。
import json
import os
from datetime import date, datetime
from zoneinfo import ZoneInfo
import requests
key = os.environ["OPENDATA_API_KEY"].strip()
if not key or key == "YOUR_API_KEY":
raise RuntimeError("Set your authorized API key")
url = "https://api.opendata-api.com/api/project/football/get-matches-events-by-date"
try:
result = requests.get(
url,
params={"key": key, "date": "20261008"},
timeout=30,
)
except requests.RequestException:
raise RuntimeError("Network request failed") from None
if not 200 <= result.status_code < 300:
raise RuntimeError(f"HTTP {result.status_code}")
try:
envelope = result.json()
if not isinstance(envelope, dict) or str(envelope.get("code")) != "200":
raise RuntimeError("Platform request failed")
payload = envelope.get("data")
if isinstance(payload, str):
payload = json.loads(payload)
except ValueError:
raise RuntimeError("Invalid JSON response") from None
if not isinstance(payload, dict) or payload.get("status") != "success":
raise RuntimeError("Football query failed")
response = payload.get("response")
rows = response.get("matches") if isinstance(response, dict) else None
if not isinstance(rows, list):
raise RuntimeError("Unexpected fixture schema")
zone = ZoneInfo("Asia/Shanghai")
target = date(2026, 10, 8)
skipped = 0
for row in rows:
try:
kickoff = datetime.fromisoformat(
row["status"]["utcTime"].replace("Z", "+00:00")
)
if kickoff.tzinfo is None:
raise ValueError("Missing timezone")
except (KeyError, TypeError, ValueError, AttributeError):
skipped += 1
continue
local = kickoff.astimezone(zone)
if local.date() == target:
print(row.get("id"), local.isoformat())
print("Skipped invalid timestamps:", skipped)
HTTP 200 只代表收到响应。还要检查平台外层 code,以及 data 内的足球业务 status,最后确认数组结构。失败时查看脱敏后的消息,不要记录完整 URL 或直接输出可能带 Key 的网络异常。
返回字段怎么用
成功的日期查询在内层 response.matches 中提供比赛记录:
id、leagueId:用于比赛去重,以及衔接详情和积分榜。home、away:包含球队 ID、名称和比分;缺失值不能自行补零。status.utcTime:用于时区转换;timeTS为毫秒时间戳,使用前核对实际位置与单位。started、finished、cancelled:结合实际嵌套读取状态标志,不能仅凭比分判断完赛。status.scoreStr、status.reason:部分完赛记录有比分文本和结束原因,不应假设每场都有。
比赛详情可补赛事、轮次与开赛信息,但已验证的详情响应不含最终比分。制作赛果卡片时仍需保留赛程里的比分和状态。
跨日边界与落地场景
同一个日期请求已观察到返回两个 UTC 日期的比赛,但接口日历采用的时区尚未明确。不要把 date 当成 UTC 日筛选器,也不要添加未声明的 timezone 参数。
北京时间日历可按需补查相邻日期,合并后按比赛 id 去重,再转换并筛选本地日期。这会增加调用量,而且仍需检查覆盖范围。面向海外用户时用其 IANA 时区,不要一律加八小时;夏令时地区尤其需要时区数据库。
体育编辑可据此生成带采集时间的赛果摘要;球迷站可从球队 ID 链接俱乐部页;数据研究可保存请求日期、原始 UTC 时间和本地时间,方便复核历史样本。用于足球实时比分页面时,应标明最后刷新时间,不承诺秒级延迟。
常见问题
如何用 Python 按日期查询赛程和赛果?
调用 get-matches-events-by-date,传入八位日期。上面的代码展示了请求、业务校验和本地日筛选;没有返回比赛不代表当天全球无赛事。
为什么同一天的结果包含两个 UTC 日期?
接口日历边界未明确,已有跨 UTC 日样本。保留开赛时间,以用户时区重新归日,不按时间字符串前十位直接分组。
UTC 如何转成北京时间?
用带时区的 datetime 调用 astimezone(ZoneInfo("Asia/Shanghai"))。时间缺失或不带时区时先标记待核查,不能悄悄当成本地时间。
如何按球队名称获取球队资料?
先用 get-search-all 搜索,核对 response.suggestions 的类型和球队上下文,再把球队 ID 传给 get-team-detail-by-team-id。
如何获取比赛详情和技术统计?
从赛程或比赛搜索选定比赛 ID,核对双方和日期,再传入详情或统计接口的 eventid。统计字段、单位和覆盖率需独立验证。
如何区分未开始、进行中与已结束?
结合开始、结束、取消标志判断,缺失或冲突时显示“状态待确认”。未开始的 0–0 不是已结束平局。
如何生成英超积分榜?
总榜接口已验证 leagueid=47。读取 played、胜平负、scoresStr、goalConDiff、pts 和 idx,保留返回排名,不自行猜测同分规则或扣分。
总榜、主场榜和客场榜有什么区别?
总榜展示整体表现,主客场榜用于场地拆分。后两者尚无已验证响应,不能直接套用总榜结构,也不能把分榜名次当总排名。
如何确认阵容、赔率和详细统计的覆盖?
用目标联赛、比赛分别验证。列有接口不等于每场有数据;赔率还需合法适用的国家代码,媒体链接也不自动授予转载权。
搜索返回空数组是失败吗?
综合搜索已验证 status="success" 且 suggestions=[] 的无匹配情况。应显示“无结果”,其他搜索接口不能照搬这个结论。
如何缓存,避免耗尽额度?
按操作、日期或实体 ID 建缓存,合并重复请求,对关注比赛按需刷新。完赛记录降低刷新频率但保留更正机制;限流和暂时性故障采用有限退避,不循环重试无匹配结果。
免费和付费足球 API 应比较什么?
比较目标联赛覆盖、历史范围、更新延迟、配额、并发及再分发许可,而不只看端点数量。具体费用与限制以定价页面和账户说明为准。