pfrederiksen/arccos-api
GitHub: pfrederiksen/arccos-api
Arccos Golf 平台的非官方 Python 客户端与 CLI,通过逆向让用户以编程方式访问个人高尔夫数据。
Stars: 1 | Forks: 0
# arccos-api
[Arccos Golf](https://arccosgolf.com) 平台的非官方 Python 客户端和 CLI。
Arccos 未提供公开 API。本库是通过逆向工程 Arccos Dashboard Web 应用程序得出的。它让你能够以编程方式完全访问自己的高尔夫数据——包括回合、差点、球杆距离、打球节奏等。
## 安装
```
pip install arccos-api
```
或从源码安装:
```
git clone https://github.com/pfrederiksen/arccos-api.git
cd arccos-api
pip install -e .
```
需要 Python >= 3.11。依赖项:`requests`, `click`, `rich`。
## CLI
### 快速开始
```
arccos login # authenticate and save credentials
arccos rounds # your recent rounds
arccos handicap # handicap breakdown
arccos clubs # smart club distances
```
### 命令
| 命令 | 描述 |
|---------|-------------|
| `arccos login` | 认证并将凭据缓存到 `~/.arccos_creds.json` |
| `arccos rounds` | 列出最近的回合,包含日期、成绩、+/-、球场名称 |
| `arccos round
` | 逐洞详情(成绩、推杆数、FIR、GIR)及总计 |
| `arccos handicap` | 按类别细分的差点(总体、开球、进攻果岭等) |
| `arccos clubs` | 智能球杆距离,包含品牌/型号、范围和击球数 |
| `arccos bests` | 有史以来的个人最佳记录(最低成绩、最远开球距离等) |
| `arccos overview` | 表现摘要——平均成绩 + 差点细分 |
| `arccos scoring` | 带有可视化条形图的成绩趋势 |
| `arccos courses` | 列出你打过的所有球场 |
| `arccos pace` | 按球场分析打球节奏(颜色编码) |
| `arccos stats ` | 单轮回合的 Strokes Gained 分析 |
| `arccos export` | 将回合导出为 JSON、CSV 或 NDJSON(`--detail` 用于获取逐洞数据) |
| `arccos logout` | 清除缓存的凭据 |
每个命令都支持 `--json` 输出原始 JSON,以及 `--help` 查看使用信息。
### 使用示例
```
# 回合
arccos rounds # last 20 rounds (with +/- and course names)
arccos rounds -n 50 # last 50
arccos rounds --after 2025-01-01 # filter by date
arccos rounds --course "pebble" # filter by course name (substring)
arccos rounds --json # raw JSON
# 回合详情
arccos round 18294051 # hole-by-hole breakdown
# Handicap
arccos handicap # category breakdown
arccos handicap --history # revision history
# 球杆距离
arccos clubs # active clubs with make/model
arccos clubs --after 2025-01-01 # distances from this year only
# 表现
arccos bests # all-time personal bests
arccos overview # scoring avg + handicap breakdown
arccos scoring # scoring trend with bar chart
# 球场
arccos courses # all courses played
# 打球节奏
arccos pace # all rounds, slowest courses first
arccos pace -n 20 # last 20 rounds only
# 导出
arccos export -f csv -o rounds.csv # export to CSV file
arccos export --detail # include hole-by-hole data
arccos export -f json # dump JSON to stdout
arccos export -f ndjson # newline-delimited JSON
```
### 输出示例
```
$ arccos clubs
Smart Club Distances
╭──────┬──────────────────┬───────┬─────────┬──────────┬───────╮
│ Club │ Model │ Smart │ Longest │ Range │ Shots │
├──────┼──────────────────┼───────┼─────────┼──────────┼───────┤
│ Dr │ TaylorMade Qi10 │ 252y │ 291y │ 245–263y │ 312 │
│ 3w │ TaylorMade Qi10 │ 228y │ 248y │ 220–235y │ 87 │
│ 5w │ Callaway Paradym │ 208y │ 231y │ 200–215y │ 143 │
│ 4h │ Titleist T200 │ 195y │ 214y │ 188–202y │ 61 │
│ 6i │ Titleist T150 │ 172y │ 190y │ 165–179y │ 94 │
│ 7i │ Titleist T150 │ 160y │ 178y │ 153–167y │ 118 │
│ 8i │ Titleist T150 │ 148y │ 165y │ 141–155y │ 105 │
│ 9i │ Titleist T150 │ 136y │ 152y │ 130–142y │ 97 │
│ Pw │ Titleist T150 │ 124y │ 140y │ 118–130y │ 82 │
│ 50 │ Vokey SM10 │ 108y │ 125y │ 102–114y │ 76 │
│ 54 │ Vokey SM10 │ 88y │ 105y │ 82–94y │ 201 │
│ 58 │ Vokey SM10 │ 64y │ 88y │ 58–70y │ 168 │
╰──────┴──────────────────┴───────┴─────────┴──────────┴───────╯
$ arccos round 18294051
╭─── Round 18294051 ────╮
│ Date: 2025-09-14 │
│ Course: Torrey Pines │
│ Score: 79 (+7) │
│ Holes: 18 │
╰───────────────────────╯
Hole-by-Hole
╭──────┬───────┬───────┬─────┬─────╮
│ Hole │ Score │ Putts │ FIR │ GIR │
├──────┼───────┼───────┼─────┼─────┤
│ 1 │ 4 │ 2 │ T │ T │
│ 2 │ 5 │ 2 │ F │ F │
│ 3 │ 3 │ 1 │ │ T │
│ ... │ ... │ ... │ ... │ ... │
├──────┼───────┼───────┼─────┼─────┤
│ Tot │ 79 │ 31 │ │ │
╰──────┴───────┴───────┴─────┴─────╯
$ arccos handicap
Handicap Breakdown
╭────────────┬───────╮
│ Category │ HCP │
├────────────┼───────┤
│ Overall │ -12.4 │
│ Driving │ -15.1 │
│ Approach │ -18.7 │
│ Short Game │ -14.3 │
│ Putting │ -6.2 │
╰────────────┴───────╯
$ arccos pace -n 10
Pace of Play — 10 rounds across 6 courses Overall avg: 4h 22m
By Course (slowest first)
╭────┬──────────┬───────────────────────┬────────╮
│ │ Avg Time │ Course │ Rounds │
├────┼──────────┼───────────────────────┼────────┤
│ 🔴 │ 5h 10m │ Bethpage Black │ 2 │
│ 🟡 │ 4h 45m │ Torrey Pines │ 3 │
│ 🟢 │ 3h 50m │ Bandon Dunes │ 2 │
│ 🟢 │ 3h 35m │ Chambers Bay │ 1 │
╰────┴──────────┴───────────────────────┴────────╯
```
### 环境变量
通过设置以下变量跳过登录提示:
```
export ARCCOS_EMAIL="you@example.com"
export ARCCOS_PASSWORD="your_password"
arccos rounds
```
## Python 库
```
from arccos import ArccosClient
client = ArccosClient(email="you@example.com", password="your_password")
# 凭证已缓存在 ~/.arccos_creds.json。自动静默刷新。
# 回合
rounds = client.rounds.list(limit=10)
for r in rounds:
print(f"{r['startTime'][:10]} score={r['noOfShots']} {r.get('courseName', '')}")
# 回合详情(包含嵌入式逐洞数据)
rd = client.rounds.get(rounds[0]["roundId"])
for hole in rd["holes"]:
print(f" Hole {hole['holeId']}: {hole['noOfShots']} shots, {hole['putts']} putts")
# Handicap 细分
hcp = client.handicap.current()
print(f"Overall: {hcp['userHcp']:.1f}")
print(f"Driving: {hcp['driveHcp']:.1f}")
# 球杆距离(返回 clubId 作为球包位置 — 参见 bag API 进行名称映射)
for club in client.clubs.smart_distances():
dist = club["smartDistance"]["distance"]
print(f" Club {club['clubId']}: {dist:.0f}y")
# Bag 配置(映射 clubId → clubType + 品牌/型号)
profile = client._http.get(f"/users/{client.user_id}")
bag = client.clubs.bag(str(profile["bagId"]))
for club in bag["clubs"]:
if club.get("isDeleted") != "T":
print(f" {club['clubMakeOther']} {club['clubModelOther']}")
# 已打球场
for course in client.courses.played():
print(f" {course.get('name', course['courseId'])}")
# 打球节奏分析
pace = client.rounds.pace_of_play()
print(f"Overall avg: {pace['overall_avg_display']}")
for c in pace["course_averages"][:5]:
print(f" {c['avg_display']} {c['course']}")
# 个人最佳成绩
bests = client.stats.personal_bests()
```
## API 参考
完整的 OpenAPI 3.1 规范:[`docs/openapi.yaml`](docs/openapi.yaml)
### 认证
所有认证调用均发往 `https://authentication.arccosgolf.com`。
| 步骤 | 端点 | Body | 返回值 |
|------|----------|------|---------|
| 1. 获取 access key | `POST /accessKeys` | `{"email", "password", "signedInByFacebook": "F"}` | `{"userId", "accessKey", "secret"}` |
| 2. 获取 JWT | `POST /tokens` | `{"userId", "accessKey"}` | `{"userId", "token"}` |
JWT 约在 3 小时后过期。`accessKey` 有效期约为 180 天。再次调用 `POST /tokens` 即可刷新。
### 端点
所有数据调用均发往 `https://api.arccosgolf.com`,并带有 `Authorization: Bearer `。
| 资源 | 方法 | 路径 |
|----------|--------|------|
| 用户资料 | GET | `/users/{userId}` (包含 `bagId`, `bags[]`) |
| 球包 / 球杆 | GET | `/users/{userId}/bags/{bagId}` (球杆配置,含品牌/型号) |
| 回合列表 | GET | `/users/{userId}/rounds?offSet=0&limit=200&roundType=flagship` |
| 回合详情 | GET | `/users/{userId}/rounds/{roundId}` (包含 `holes[]` 和 `shots[]`) |
| 差点 | GET | `/users/{userId}/handicaps/latest` |
| 差点历史 | GET | `/users/{userId}/handicaps?rounds=20` |
| 智能距离 | GET | `/v4/clubs/user/{userId}/smart-distances` |
| 打过的球场 | GET | `/users/{userId}/coursesPlayed` |
| 球场元数据 | GET | `/courses/{courseId}?courseVersion=1` |
| 球场搜索 | GET | `/v2/courses?search={query}` |
| 个人最佳 | GET | `/users/{userId}/personalBests?tags=allTimeBest` |
### 关键数据结构
**Round** (来自 `GET /users/{id}/rounds/{roundId}`):
```
{
"roundId": 18294051,
"courseId": 12450,
"courseVersion": 4,
"startTime": "2025-09-14T15:30:00.000000Z",
"endTime": "2025-09-14T20:15:00.000000Z",
"noOfShots": 79,
"noOfHoles": 18,
"holes": [
{
"holeId": 1, "noOfShots": 4, "putts": 2,
"isGir": "T", "isFairWay": "T",
"shots": [{"clubId": 1, "clubType": 1, "distance": 255.0}]
}
]
}
```
**Smart distance** (来自 `GET /v4/clubs/user/{id}/smart-distances`):
```
{
"clubId": 1,
"smartDistance": {"distance": 252.3, "unit": "yd"},
"longest": {"distance": 291.0, "unit": "yd"},
"range": {"low": 245.0, "high": 263.0, "unit": "yd"},
"usage": {"count": 312}
}
```
**Bag club** (来自 `GET /users/{id}/bags/{bagId}`):
```
{
"clubId": 1, "clubType": 1,
"clubMakeOther": "TaylorMade", "clubModelOther": "Qi10",
"isDeleted": "F"
}
```
## 开发
```
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest # tests with coverage (88%+, 125 tests)
ruff check arccos/ # lint
mypy arccos/ # type check
```
覆盖率报告:`htmlcov/index.html`。最低阈值:80%(在 `pyproject.toml` 中配置)。
## 安全
- 凭据缓存在 `~/.arccos_creds.json` 中(模式为 `0600`——仅所有者可读写)。该文件包含你的 access key(约 180 天有效期)和 JWT token。请妥善保管。
- 所有 API 通信均使用带有 TLS 证书验证的 HTTPS。
- `arccos logout` 会删除本地凭据文件,但**不会**撤销服务器端的 token。如果你怀疑凭据已泄露,请更改你的 Arccos 密码。
- 导出命令将输出路径限制在你的主目录或当前工作目录。
## 已知缺失
- [ ] SGA 端点认证(`/v2/sga/shots/` 返回 40102——可能需要通过 `secret` 进行 HMAC)
- [ ] 社交/动态流端点(`/users/{id}/feed`、关注等)
- [ ] 练习场数据(`roundType=range`)
- [ ] 异步客户端(`httpx`)
欢迎提交 PR。
## 免责声明
不隶属于、不由 Arccos Golf LLC 认可或与其有关联。
仅使用你自己的账户凭据。本项目用于个人数据访问和研究。
MIT License。标签:API客户端, Arccos Golf, CLI, Click, CSV, JSON, Python, Rich, URL抓取, WiFi技术, 云资产清单, 代码示例, 体育统计, 差点分析, 数据分析, 数据导出, 数据抓取, 文档结构分析, 无后门, 杆身距离, 比赛记录, 运动科技, 逆向工具, 逆向工程, 非官方API, 高尔夫数据