关于 esportsodds.gg
esportsodds.gg 是其 CS2 数据 API 的官方 Python 客户端,面向开发比赛、队伍、选手或赛事数据功能的开发者。它将 API 响应以 Python 字典和列表返回,且仅使用标准库。
主要功能
- 01查询比赛与赛果
- 02获取地图和选手数据
- 03浏览队伍与赛事
- 04访问排名和衍生赔率
- 05分页获取 API 响应
适用场景
- 01构建 CS2 比赛数据工具
- 02分析选手和队伍表现
- 03展示赛事日程与赛果
- 04使用排名和衍生市场线
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
24收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| has | string | 否 | 仅返回包含以下所有子资源的比赛,例如 `["rounds", "depth"]`。多个值以逗号分隔。 |
| sort | string | 否 | `-scheduled_at`(默认,最新优先)、`scheduled_at`(最早优先;对于已安排的比赛,即最先进行的比赛优先)、`changed_at` 或 `-changed_at`。游标与其所用的排序方式绑定。 |
| team | string | 否 | 仅返回此队伍的比赛(id)。 |
| limit | integer | 否 | 页面大小(默认 100,最大 500)。 |
| cursor | string | 否 | 上一页返回的 `next_cursor`;第一页省略。 |
| status | string | 否 | `scheduled`、`live`、`completed` 或 `cancelled`。使用 `scheduled` 时,还要传入 `sort="scheduled_at"`,以获取接下来进行的比赛,而非日期最远的比赛。 |
| date_to | string | 否 | 安排在此日期或之前的比赛(UTC,包含整天)。 |
| date_from | string | 否 | 安排在此日期或之后的比赛(UTC,包含当日)。 |
| tournament | string | 否 | 仅返回此锦标赛的比赛(id)。 |
| changed_since | string | 否 | 仅返回 `changed_at` 不早于此时刻的比赛;这是变更动态流(建议使用 `iter_changes`,它也会处理时间重叠)。 |
详细介绍
esportsodds
esportsodds.gg CS2 数据 API 的官方 Python 客户端。
Counter-Strike 2 比赛和赛果、队伍和选手统计数据、锦标赛、排名,以及衍生市场赔率,均以普通 Python 字典的形式返回。仅使用标准库:无需安装其他内容。
无需抓取 HLTV,即可获取 CS2 比赛数据和统计信息。此软件包是付费 API 的客户端;它不是官方 HLTV/Valve API。
安装
pip install esportsodds
Python 3.10 或更高版本。无依赖项。
无需账户即可先试用:将 ESPORTSODDS_API_KEY 设置为公共示例密钥 eo_sample_public,即可读取固定范围的过往比赛。该密钥由所有人共用,并按网络地址限流。
仅供评估使用;请遵守我们的条款。
还没有订阅?免费的 sandbox 密钥可读取固定范围的过往比赛,让你先基于真实响应进行开发。下面的快速入门会请求即将举行的比赛,这些比赛不在样本范围内,所以使用任一密钥时,都应先运行sandbox_tour.py,并使用指南中的锦标赛 ID。任何超出样本范围的请求都会引发 PermissionDeniedError(sandbox_scope),错误消息会列出可用的赛事。
快速入门
from esportsodds import Client
client = Client() # reads ESPORTSODDS_API_KEY from the environment
for match in client.matches.list(status="scheduled", sort="scheduled_at", limit=5).data:
print(match["scheduled_at"], match["team_a_name"], "vs", match["team_b_name"])
2026-10-08T14:00:00Z Team A vs Team B
2026-10-08T17:30:00Z Team C vs Team D
每次调用都会以普通字典和列表的形式返回 API 发来的内容。列表调用会返回一个 Page(page.data、page.next_cursor、page.has_more、page.meta);查询单个对象的调用会返回一个字典。
除非另有说明,比赛按时间从新到旧排列,这适用于查询赛果。对于已安排的比赛,该顺序会从时间最远的赛程开始,所以快速入门中传入 sort="scheduled_at",以获取接下来要进行的比赛。
API 密钥和套餐
有两种套餐,按月或按年计费,均需预先付款:Standard 每月 $99,包含 50,000 次请求;Pro 每月 $299,包含 150,000 次请求。年付相当于付 10 个月费用:Standard 每年 $990,Pro 每年 $2,990,相当于免费获得两个月。请求按账户、按日历月(UTC)计数,涵盖该账户拥有的所有密钥。没有试用期。免费的 sandbox 密钥可读取固定范围的过往比赛,总计最多可发起 2,000 次请求,无需提供银行卡;它不是套餐,获取当前数据则需要订阅套餐。超出套餐请求额度后,调用会收到错误码为 quota_exceeded 的 429 响应,直到下个月重置;此客户端会引发 QuotaExceededError,且不会重试(重试无济于事)。sandbox 密钥用尽额度后会返回 sandbox_quota_exceeded,并以相同方式引发错误(额度永不重置);超出样本范围的请求会引发 PermissionDeniedError(sandbox_scope,不计入额度)。
批量导出(matches.bulk() 及基于它构建的遍历器)还有一项限制。对于首次订阅日期为 2026 年 10 月 30 日或之后的 Standard 账户,每月最多可发起 250 次批量导出请求;超出后,API 会返回 bulk_quota_exceeded 错误码的 429,进而引发 QuotaExceededError,且不会重试,但其他调用仍可正常使用。Pro 没有批量导出限制;首次订阅日期早于该日期的 Standard 账户也没有此限制。
订阅后,在账户中创建密钥,并妥善保管,勿将其写入代码:
export ESPORTSODDS_API_KEY="eo_live_..."
- 客户端只会在
Authorization: Bearer标头中发送密钥,绝不会将其放入 URL。repr()只显示密钥的最后四个字符,错误消息或日志中也绝不会出现密钥。 - 客户端只通过 HTTPS 通信。仅对
localhost和其他环回地址(127.0.0.1、::1)接受普通http://,并且绝不会跟随重定向,因此密钥不会被发送到其他主机。 - 将密钥保存在你的服务器上。浏览器或移动应用应调用你的后端,而非直接调用 API。
- 订阅前,你可以在公开演示中查看真实响应。
配置
| 环境变量 | 含义 |
|---|---|
ESPORTSODDS_API_KEY | 你的 API 密钥,在未传入 api_key 时使用。 |
ESPORTSODDS_BASE_URL | API 地址,在未传入 base_url 时使用。 |
Client(...) 参数 | 默认值 | 含义 |
|---|---|---|
api_key | None | 你的密钥。省略时会读取 ESPORTSODDS_API_KEY;两者都没有时会引发 ValueError。 |
base_url | https://api.esportsodds.gg | API 地址。仅支持 HTTPS,但 localhost 和其他环回地址除外。 |
game | "cs2" | 要查询的游戏。目前只有 CS2 有数据。 |
timeout | 30.0 | 等待回复的秒数。批量导出始终至少等待 120 秒。 |
max_retries | 3 | 对 错误 中列出的故障进行重试的次数。0 表示关闭重试。 |
transport | None | 你自己的 HTTP 栈:任何具有 send(TransportRequest) -> TransportResponse 方法的对象。 |
Client 可以安全地供多个线程共用。可将其用作上下文管理器(with Client() as client:),
或在使用完毕后调用 client.close():该方法会关闭具有 close() 方法的自定义 transport
(默认 transport 不会保持任何连接,因此无需释放资源)。
方法
每个端点对应一个方法。{game} 是客户端的 game,{id} 接受 UUID;对于战队、选手和锦标赛,
也接受 slug。
| 调用 | 端点 | 返回值 | 提供的内容 |
|---|---|---|---|
client.matches.list() | GET /v1/{game}/matches | Page | 比赛赛程和结果,按时间倒序排列;可按 status、tournament、team、日期和 has 筛选,并用 sort 排序。 |
client.matches.bulk() | GET /v1/{game}/matches/bulk | Page | 比赛数据,内嵌地图、统计数据等(include=),每次请求 25 场。 |
client.matches.get(match) | GET /v1/{game}/matches/{id} | dict | 单场比赛;include= 可内嵌队伍、赛事、赔率或子资源。 |
client.matches.maps(match) | GET /v1/{game}/matches/{id}/maps | Page | 各地图的比赛结果。 |
client.matches.stats(match) | GET /v1/{game}/matches/{id}/stats | Page | 每位选手的统计数据,包括整场比赛和各地图的数据。 |
client.matches.vetoes(match) | GET /v1/{game}/matches/{id}/vetoes | Page | 地图的选取和禁用顺序。 |
client.matches.rounds(match) | GET /v1/{game}/matches/{id}/rounds | Page | 按回合统计的队伍数据:经济、首杀对决、残局和炸弹事件。 |
client.matches.history(match) | GET /v1/{game}/matches/{id}/history | Page | 比赛信息的历史记录:每次变更及变更前后的值。 |
client.matches.depth(match) | GET /v1/{game}/matches/{id}/depth | dict | 每位选手的武器、手雷、命中部位、对决和闪光弹数据。 |
client.matches.lineups(match) | GET /v1/{game}/matches/{id}/lineups | Page | 比赛前列出的各队阵容。 |
client.matches.streams(match) | GET /v1/{game}/matches/{id}/streams | Page | 转播比赛的频道。 |
client.odds.list() | GET /v1/{game}/odds | Page | 衍生市场赔率,可查看历史记录或当前赔率盘。 |
client.teams.list() | GET /v1/{game}/teams | Page | 所有队伍,按字母顺序排列;可用 q 按名称查找。 |
client.teams.get(team) | GET /v1/{game}/teams/{id} | dict | 单支队伍。 |
client.teams.h2h(team, opponent=...) | GET /v1/{game}/teams/{id}/h2h | dict | 两支队伍之间的交锋记录。 |
client.teams.form(team) | GET /v1/{game}/teams/{id}/form | Page | 最近已结束的比赛结果,按时间倒序排列。 |
client.teams.ratings(team) | GET /v1/{game}/teams/{id}/ratings | Page | 队伍的评分历史,每场比赛对应一个数据点。 |
client.teams.maps(team) | GET /v1/{game}/teams/{id}/maps | Page | 队伍在各张地图上的战绩。 |
client.teams.round_stats(team) | GET /v1/{game}/teams/{id}/round-stats | dict | 按回合统计的打法风格数据:各方胜率、手枪局和首杀对决。 |
client.teams.vetoes(team) | GET /v1/{game}/teams/{id}/vetoes | dict | 队伍在各张地图上的自选、禁用和决胜图记录,并标记永久禁用图。 |
client.teams.results(team) | GET /v1/{game}/teams/{id}/results | Page | 最近比赛结果,包含每张地图的比分以及赛前双方队伍的评分。 |
client.teams.rivals(team) | GET /v1/{game}/teams/{id}/rivals | Page | 队伍最常遇到的对手,以及双方交锋记录和评分差距。 |
client.teams.roster_history(team) | GET /v1/{game}/teams/{id}/roster-history | Page | 各场近期比赛中上场的五位选手及阵容变动。 |
client.teams.players(team) | GET /v1/{game}/teams/{id}/players | dict | 队伍最近一场比赛中的选手及其统计数据,还有过去 12 个月的数据。 |
client.tournaments.list() | GET /v1/{game}/tournaments | Page | 所有赛事,按时间倒序排列;可用 q 按名称搜索。 |
client.tournaments.get(tournament) | GET /v1/{game}/tournaments/{id} | dict | 单项赛事。 |
client.tournaments.teams(tournament) | GET /v1/{game}/tournaments/{id}/teams | Page | 参赛队伍,按种子排序。 |
client.players.list() | GET /v1/{game}/players | Page | 所有选手,按昵称字母顺序排列;可用 q 按昵称搜索。 |
client.players.get(player) | GET /v1/{game}/players/{id} | dict | 单名选手。 |
client.players.career(player) | GET /v1/{game}/players/{id}/stats | dict | 选手生涯总数据和平均数据。 |
client.players.performance(player) | GET /v1/{game}/players/{id}/performance | dict | 过去 12 个月内已记录地图的数据,每项数据都附有其在拥有个人页面的选手中的百分位排名。 |
client.players.maps(player) | GET /v1/{game}/players/{id}/maps | dict | 选手在各张已记录地图上的数据。 |
client.players.matches(player) | GET /v1/{game}/players/{id}/matches | Page | 最近已结束的比赛,按时间倒序排列,并附有该选手本人的数据。 |
client.players.teams(player) | GET /v1/{game}/players/{id}/teams | dict | 选手的队伍经历,按效力时段列出。 |
client.players.weapons(player) | GET /v1/{game}/players/{id}/weapons | dict | 过去 12 个月的武器和命中部位汇总数据。 |
client.rankings.list() | GET /v1/{game}/rankings | Page | 滚动三个月时间窗口内的队伍或选手排行榜。 |
client.rankings.history() | GET /v1/{game}/rankings/history | Page | 最近各个每周时点的队伍排行榜。 |
client.rankings.round_stats() | GET /v1/{game}/rankings/round-stats | Page | 排行榜上顶尖队伍的回合级数据,按榜单顺序排列。 |
client.maps.list() | GET /v1/{game}/maps | Page | 各张竞技地图的联赛整体数据。 |
client.maps.teams(map) | GET /v1/{game}/maps/{id}/teams | Page | 各队伍在一张地图上的表现及围绕该地图的选择情况。 |
client.coverage.list() | GET /v1/{game}/coverage | Page | 已有的数据及其刷新频率。 |
client.model.metrics() | GET /v1/{game}/model/metrics | Page | 按市场划分的模型赔率透明度指标。模型赔率即将推出;列表可能为空。 |
client.ws_token() | POST /v1/{game}/ws-token | dict | 用于 WebSocket 的 60 秒有效凭证。不消耗请求额度。 |
client.health() | GET /health | dict | 服务状态。无需密钥,也不会重试。 |
| 筛选条件采用关键字参数,名称与 API 参考文档 一致。 | |||
对于逗号分隔的筛选条件(has=["rounds", "depth"]、include=["maps", "stats"]), | |||
会自动为你拼接;datetime 或 date 会自动为你格式化(无时区信息的 datetime 表示 UTC);未知参数会引发 TypeError,而不会被发送。ID 在加入 URL 前会经过检查和转义。 |
赔率是我们自行推导的盘口(source="eo_market"),并非任何博彩公司提供的价格。模型盘口(source="eo_model")即将推出,目前尚未返回。
分页、批量导出和变更订阅
列表调用会返回一页数据和一个游标。你可以自行遍历:
page = client.matches.list(status="completed", limit=100)
while True:
for match in page.data:
print(match["id"])
if not page.has_more:
break
page = client.matches.list(status="completed", limit=100, cursor=page.next_cursor)
也可以让客户端代为处理。iter() 会逐行生成结果,pages() 会逐页生成结果;两者都会按需加载,每页发送一个请求,因此提前停止不会产生额外开销。max_pages 是安全限制;生成的最后一页仍带有 next_cursor,因此任务停止(或崩溃)后,可以通过 cursor= 恢复。
for match in client.matches.iter(status="completed", date_from="2026-09-01"):
print(match["id"])
matches、odds、teams、tournaments 和 players 均提供 iter 和 pages。
批量导出是低成本获取历史数据的方式:每个请求获取 25 场比赛,并嵌入你指定的子资源;每页请求只计入一次额度。
from datetime import date, timedelta
week_ago = date.today() - timedelta(days=7)
rows = client.matches.iter_bulk(
status="completed", date_from=week_ago, include=["maps", "stats"], max_pages=4
)
for match in rows:
print(match["id"], len(match["maps"]))
max_pages 会在达到指定请求数后停止遍历。不设置该参数时,iter_bulk 会持续运行,直到筛选结果耗尽;对于范围较广的筛选条件,这意味着会遍历全部历史数据,每页发送一个请求。Standard 订阅每月限额为 250 个请求,长时间遍历会在当月请求用尽时以 bulk_quota_exceeded 错误停止。使用 pages_bulk() 遍历并保存每页的 next_cursor,待下个月额度重置后,通过 cursor= 恢复遍历。
繁忙时段会返回 503 和较短的 Retry-After;客户端会为你等待并重试。
变更订阅可让本地副本保持最新。向 iter_changes 传入上次存储的最新一行的 changed_at,它会按变更时间从早到晚生成此后所有发生变更的比赛:
from datetime import datetime, timedelta, timezone
since = datetime.now(timezone.utc) - timedelta(hours=1)
newest = since.isoformat()
for match in client.matches.iter_changes(since):
newest = match["changed_at"] # rows arrive in changed_at order
print(match["id"], match["status"])
# Store `newest`; it is the `since` for the next run.
它会从 since 前十分钟开始(overlap=),因为一行数据可能在其携带的 changed_at 之后才可见,并会丢弃因此产生的重复项。静默一小时只需一个请求。matches.history(match) 和 matches.iter_history(match) 可查看每次变更的内容。
错误
所有错误都是 EsportsOddsError。收到错误状态的回复时,会引发 ApiError 子类;请根据类或 error.code 分支处理,切勿根据 error.message 判断。
| 异常 | API code | 状态码 | 是否自动重试 |
|---|---|---|---|
AuthenticationError | missing_api_key、invalid_api_key、unauthorized | 401 | 否 |
PermissionDeniedError | forbidden、sandbox_scope | 403 | 否 |
NotFoundError | not_found、unknown_game | 404 | 否 |
NotFoundError | match_merged | 308 | 否:比赛 ID 因合并而失效;请保存 err.headers.get("x-merged-into") 返回的存续 ID |
InvalidRequestError | invalid_parameter | 400 | 否 |
InvalidCursorError | invalid_cursor | 400 | 否:从第一页重新开始遍历 |
ConflictError | conflict | 409 | 否 |
RateLimitError | rate_limited | 429 | 是,等待 API 返回的 Retry-After 指定的时间后重试 |
QuotaExceededError | quota_exceeded | 429 | 永不:月度额度重置前不会有任何变化 |
QuotaExceededError | sandbox_quota_exceeded | 429 | 永不:Sandbox 密钥的额度不会重置 |
QuotaExceededError | sample_quota_exceeded | 429 | 永不:公共示例密钥的每日额度会在 00:00 UTC 重置 |
QuotaExceededError | bulk_quota_exceeded | 429 | 永不:套餐的月度批量导出额度会在每月重置;其他调用仍可正常使用 |
ServiceUnavailableError | unavailable | 503 | 是,等待 API 返回的 Retry-After 指定的时间后重试 |
ServerError | internal_error | 500 | 是,但最多重试两次 |
ApiError | 其他任意值 | 其他 | 仅针对 502 和 504 |
TransportError | 无:请求未收到响应 | 无 | 是,采用退避策略 |
InvalidResponseError | 无:回复格式与 API 文档不符 | 2xx | 否 |
未知路径 ID 会返回 404(NotFoundError),而不是 400;对于 matches.maps(...) 这类子资源中的未知 ID,会返回空页,而不是错误。
ApiError 包含 status、code、message、request_id、retry_after、headers 和 body。报告问题时请提供 request_id;它也可通过 client.last_response.request_id 获取。
from esportsodds import QuotaExceededError, RateLimitError
try:
client.matches.get("00000000-0000-7000-8000-000000000001")
except QuotaExceededError as error:
print("out of requests until", error.reset_at)
except RateLimitError as error:
print("slow down; retry in", error.retry_after, "seconds")
速率限制与重试
有两种限制:每个密钥的令牌桶限制(持续每秒 20 个请求,突发上限为 100 个)以及套餐的月度额度。Standard 套餐为每个账户 50,000 个请求,Pro 套餐为每个账户 150,000 个请求;账户的所有密钥共用该额度。每次调用后,client.last_response.rate_limit 中都会包含 API 报告的额度信息:
info = client.last_response # None until the first call has been made
if info is not None:
budget = info.rate_limit
print(budget.quota_remaining, "of", budget.quota_limit, "left; resets", budget.quota_reset)
客户端只会重试适合安全重试的请求,最多重试 max_retries 次(默认为 3 次),并会在 esportsodds 日志记录器上以 INFO 级别记录每次重试:
- 遇到
429 rate_limited或503时,会等待 API 返回的Retry-After指定的时间,并额外加入最多半秒的随机抖动。如果等待时间超过一分钟,则直接引发错误,不会继续等待。 - 遇到
502、504或网络故障时,会从半秒开始退避,每次加倍,最多等待八秒,并加入随机抖动。 - 无论
max_retries设置得多高,500最多只会重试两次:API 会将其计入你的额度,因此每次重试都会消耗一个你付费购买的请求。 - 遇到
429 quota_exceeded时绝不重试,其他情况也不会重试。
轮询通常不是最省成本的设计:变更馈送和 WebSocket 所需的请求要少得多。请求预算指南中列出了具体数据。
WebSocket(比赛更新)
WebSocket 会推送你订阅的比赛的比分和赔率变化,且不消耗请求额度:票据、连接和消息都不会计入你的额度。我们的数据采集一旦发现变化就会推送更新,因此 WebSocket 可以消除轮询延迟,但无法让数据比采集到的更新;下方链接的指南列出了典型数据时效。
此软件包不会自行打开套接字(这需要依赖项)。它会生成票据并构建地址;任何 WebSocket 库都可以连接,例如
websockets(pip install websockets):
import asyncio
import json
import websockets
from esportsodds import Client
client = Client()
async def watch(match_ids: list[str]) -> None:
ticket = await asyncio.to_thread(client.ws_token)
async with websockets.connect(client.ws_url(ticket)) as socket:
await socket.send(json.dumps({"type": "subscribe", "data": {"match_ids": match_ids}}))
async for raw in socket:
frame = json.loads(raw)
if frame["type"] in ("snapshot", "update"):
print(frame["match_id"], frame["seq"], frame["type"])
asyncio.run(watch(["00000000-0000-7000-8000-000000000001"]))
- 票据有效期为 60 秒,且并非一次性使用,因此可在有效期内重试并复用;过期后请重新生成。你的密钥不会出现在套接字地址中。
snapshot是比赛的完整当前状态,update则表示一项变化。seq按比赛递增;如果跳过了某个序号,请重新订阅该比赛以获取最新的snapshot。- 使用指数退避和随机抖动重连,并重新发送
subscribe。服务器不会重放消息。 - 一个密钥最多可同时保持五个连接,因此可以在一个连接上订阅多场比赛。
- 服务器每隔 54 秒发送一次 ping;
websockets会自动回复。
WebSocket 指南列出了所有帧类型。
AI 助手(MCP)
此软件包包含一个 MCP(Model Context Protocol)服务,因此 Claude 或 Cursor 等 AI 助手可以根据 API 回答问题,例如某支队伍近期的状态、某场比赛的 veto 结果,或某名选手的生涯数据。它在你的机器上运行,读取 ESPORTSODDS_API_KEY,且只读取数据。每次工具调用都会消耗一条请求额度;列表工具默认请求 20 行,除非助手设置了 limit。
将其添加到 MCP 客户端的配置中(Claude Desktop:claude_desktop_config.json;Cursor:
~/.cursor/mcp.json)。安装 uv 后,uvx 会自动获取软件包,因此无需进行其他设置:
{
"mcpServers": {
"esportsodds": {
"command": "uvx",
"args": ["esportsodds", "mcp"],
"env": {"ESPORTSODDS_API_KEY": "eo_live_..."}
}
}
}
或者运行 pip install esportsodds,并将 esportsodds-mcp 用作 command,不设置 args(如果客户端找不到它,请通过 which esportsodds-mcp 获取完整路径)。在 Claude Code 中:
claude mcp add --transport stdio --env ESPORTSODDS_API_KEY="$ESPORTSODDS_API_KEY" esportsodds -- uvx esportsodds mcp
这些工具包括 matches_list、matches_get、matches_maps、matches_stats、matches_vetoes、
matches_rounds、matches_lineups、odds_list、teams_list、teams_get、teams_h2h、
teams_form、teams_maps、teams_results、teams_players、tournaments_list、
tournaments_get、tournaments_teams、players_list、players_get、players_career、
players_matches、rankings_list 和 maps_list。每个工具对应上方方法表中的一行,并接受该方法的参数;此服务可响应 2024-11-05 至 2026-07-28 期间各版本 MCP 的客户端。
示例
examples/ 文件夹中包含可运行的脚本。每个脚本都会读取 ESPORTSODDS_API_KEY。
| 脚本 | 功能 |
|---|---|
quickstart.py | 上文的快速入门示例。 |
sandbox_tour.py | 获取一场赛事的最新结果,然后查看一场比赛的选图、地图和顶尖选手。可使用沙盒密钥运行。 |
upcoming_with_odds.py | 获取即将开始的比赛及其当前盘口。 |
team_report.py | 获取一支队伍的近期表现、交手记录和评级。 |
backfill_matches.py | 将已结束的比赛批量拉取到 JSON Lines 文件中,并支持断点续传。 |
follow_changes.py | 根据变更源更新本地文件。 |
handle_errors.py | 读取用量额度并处理各种错误。 |
watch_matches.py | 通过 WebSocket 接收比赛更新。 |
常见问题
这是官方 API 吗? 不是。它不是 HLTV/Valve 的官方 API,esportsodds.gg 也未与 Valve 或任何数据统计网站建立关联,也未获得其认可。
为什么不抓取网页? 网页一旦更改,抓取就会失效,而且许多网站禁止抓取。使用此 API,你无需抓取 HLTV 或其他网站即可构建应用:只需调用稳定且有文档说明的端点。
有免费套餐吗? 当前数据不提供免费套餐,也没有试用期;Standard 套餐每月 99 美元,包含 50,000 次请求;Pro 套餐每月 299 美元,包含 150,000 次请求,均需预先付款。免费的沙盒密钥可读取固定的历史比赛样本,公开演示无需账户即可展示真实响应。
一次调用的费用是多少? 每次请求都会占用月度额度,无论返回什么内容。批量页面最多包含 25 场比赛及其详情,也只计为一次请求(对于 2026 年 10 月 30 日或之后首次订阅的 Standard 账户,每月还会占用 250 次批量导出请求中的一次)。遍历器(iter、pages、iter_bulk、iter_changes)每获取一页就计为一次请求。WebSocket 不计费。
支持 asyncio 吗? 客户端是同步的,可安全地在线程间共享。在异步代码中,可在线程中运行调用:
matches = await asyncio.to_thread(client.matches.list, status="completed", limit=10)
可以使用其他 HTTP 库吗? 可以。传入 transport=,其值可以是任何具有 send(TransportRequest) -> TransportResponse 方法的对象。使用默认传输方式通过代理连接时,请传入 UrllibTransport(proxies={"https": "http://proxy.example:3128"})。
支持哪些游戏? CS2(game="cs2")。game 参数是为后续推出的游戏预留的。
提供类型标注吗? 是的:软件包包含 py.typed,并通过 mypy --strict 检查。响应是普通字典,因此类型为 dict[str, Any]。
在哪里报告此客户端的错误? 请在此代码库的 issues 中报告。账户、账单或数据相关问题,请通过 esportsodds.gg 联系。
许可
此存储库中的代码根据 MIT 许可发布。该许可 适用于此客户端,不适用于其获取的数据:根据服务条款第 4 和第 5 节,数据授权您用于自己的用途,但不得再分发。
Counter-Strike 和 CS2 是 Valve Corporation 的商标。esportsodds.gg 是独立网站,与 Valve 无关联,也未获得 Valve 的认可或赞助。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。