【Python 量化取数指南 #01】环境搭建与请求封装:一次写好,全系列复用
摘要:【Python 量化取数指南 #01】环境搭建与请求封装:一次写好,全系列复用 系列:《Python 量化取数指南》|纯 GET 取数 · 仅依赖 requests · 16 篇连载 适用:想用智兔 API 做唯
系列:《Python 量化取数指南》|纯 GET 取数 · 仅依赖 requests · 16 篇连载
适用:想用智兔 API 做唯一数据源,本地零依赖搭一个「取数 → 落库 → 信号 → 回测 → 看板」最小可用量化工作台的读者;数据由智兔数服提供,不依赖任何行情终端。
1. 环境准备
只需一个第三方依赖:
pip install requests
要求:Python 3.8+;能正常访问外网(接口为 HTTPS GET)。
验证装好:
import requests
print(requests.__version__) # 输出版本号即正常
本篇交付:可复用的统一取数底座 _get(带 token、超时、重试、退避)与候选键命中工具 _hit_key,以及项目唯一的配置常量 BASE / TOKEN。后续 16 篇都在这个底座上叠具体接口。
2. 本篇用到的取数约定
GET https://api.zhituapi.com/<path>?token=你的智兔token
- 鉴权:
token走查询参数?token=,不要放进请求头。 - 错误形态:非 200 时接口先过鉴权再路由,常见
404 102:Licence证书(你的智兔token)不存在—— 这是「证书(token)不存在」,不代表路径写错。 - 字段名不稳定:同一含义的字段可能中英文混杂(如
市盈率/pe),统一用候选键命中(见 §3)。数据来自 智兔数服(www.zhituapi.com)。
3. 字段名不固定?用候选键命中
行情接口返回的键名经常中英文混用,直接 d["pe"] 会 KeyError。统一用 _hit_key 按候选键顺序命中:
def _hit_key(d, keys):
"""候选键命中:字段名中英文混杂也不怕。"""
if not isinstance(d, dict):
return None
for k in keys:
if k in d and d[k] is not None:
return d[k]
low = {str(x).lower(): x for x in d.keys()}
for k in keys:
if k.lower() in low:
return d[low[k.lower()]]
return None
4. 核心模板函数
import sys, requests, time
# ── 项目配置(后续章节统一从这里取)──
BASE = "https://api.zhituapi.com"
TOKEN = "你的智兔token" # 演示证书(免费版)即可起步,换成你申请的真实 token
def _hit_key(d, keys):
"""候选键命中:字段名中英文混杂也不怕。"""
if not isinstance(d, dict):
return None
for k in keys:
if k in d and d[k] is not None:
return d[k]
low = {str(x).lower(): x for x in d.keys()}
for k in keys:
if k.lower() in low:
return d[low[k.lower()]]
return None
def _get(path, params=None, timeout=10, retries=3, backoff=0.6):
"""统一取数入口:返回 (data, err);带失败重试与指数退避。"""
p = dict(params or {})
p["token"] = TOKEN
last_err = None
for i in range(retries):
try:
r = requests.get(f"{BASE}{path}", params=p, timeout=timeout)
if r.status_code != 200:
return None, f"{r.status_code} {r.text.strip()[:140]}"
try:
return r.json(), None
except ValueError:
return None, f"非 JSON:{r.text.strip()[:140]}"
except requests.RequestException as e:
last_err = e
if i < retries - 1:
time.sleep(backoff * (i + 1)) # 指数退避:第1次0.6s、第2次1.2s
return None, f"网络异常:{last_err}"
if __name__ == "__main__":
# 冒烟测试:拉指数代码列表(无需额外参数)
data, err = _get("/hz/list/hszs")
if err:
print("ERR:", err)
else:
print(data)
要点:
1. token 放查询串(?token=),由 requests 自动百分号编码。
2. 返回 (data, err) 二元组:调用方先判 err,避免到处 try/except。
3. 重试 + 指数退避:网络抖动时第 1 次等 0.6s、第 2 次等 1.2s,扛瞬时抖动;持续失败多半是 token / 权限问题,别无限重试。
5. 跑通示例
把上面的代码复制到本地,填入你的 token 即可直接运行:它会请求对应接口、拉取真实数据并打印结构化结果(各字段含义见下文)。
冒烟测试用 /hz/list/hszs(指数代码列表,无需额外参数),运行后打印类似:
{'code': 0, 'data': [{'code': '000001', 'name': '上证指数', 'market': 'SH'}, {'code': '399001', 'name': '深证成指', 'market': 'SZ'}, ...], 'msg': 'ok'}
返回字段说明(以实际返回为准):
- code:指数代码(如 000001)
- name:指数名称(如 上证指数)
- market:市场,SH 沪 / SZ 深
用 _hit_key 安全取值,避免字段名中英混杂导致 KeyError:
data, err = _get("/hz/list/hszs")
if err:
print("ERR:", err)
else:
items = data.get("data", []) if isinstance(data, dict) else data
for it in items[:5]:
print(_hit_key(it, ["代码", "code"]), _hit_key(it, ["名称", "name"]))
6. 坑与注意事项
- token 走查询参数,别放 header:放
?token=由 requests 自动百分号编码即可。 404 102不代表路径错:它是「证书不存在」(鉴权先于路由),路径合法与否要靠客户端白名单自查,不能靠这个状态码判断。- 免费证书有频率与字段限制:能起步,但生产环境要先评估够不够用,别一上来全量依赖。
- 不同接口返回结构不一:动手解析前,先
print(r.status_code, r.text[:500])看原始响应,确认是对象还是数组、字段名到底叫什么。 - 别在循环里无间隔高频请求:容易触发
429限流,批量拉取时加time.sleep或并发上限。 - 重试要有限度:封装里的
retries=3是兜底,不是让你无限重试;持续失败多半是证书或权限问题,先查原因。 - 时区、复权、停牌这类数据一致性坑,本篇先不展开,后续行情 / 历史 K 线篇会专门讲。
常见报错速查:
| 报错 / 现象 | 原因 | 处理 |
|---|---|---|
404 102:Licence证书...不存在 |
token 错或没填 | 检查 TOKEN 是否被占位字符串覆盖 |
403 |
频率或权限限制 | 降低并发,确认证书类型支持该接口 |
429 |
触发限流 | 调大 backoff,减少重试频次,必要时降速 |
requests.exceptions.Timeout |
网络慢/超时短 | 调大 timeout(如 20) |
| 返回 HTML 而非 JSON | 网关拦截 / 路径错 | 先 print(r.status_code, r.text[:200]) 看原始响应 |
7. 小结与下一篇预告
本篇把整套路子的底座搭好,并交付了最底层也最常用的一块:统一取数底座 _get 与候选键工具 _hit_key。这两个会在后续每一篇被复用。
下一篇计划写 #02《免费股票数据 API 横向实测与选型》:在 _get 底座上,用真实接口拉取行情快照、行业板块、指数列表,并给出可跑的示例与返回字段说明。
8. 免责声明
本文仅演示公开数据接口的用法,所有代码示例均为演示数据,未含任何真实数据;文中示例数据仅作演示用途,不构成投资建议,亦不承诺收益。
免费领取证书
数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。
领取路径:进入 www.zhituapi.com → 点击「请求证书」→「证书获取」→「免费版」(邮箱验证 3 步即可拿到 token)。
把代码里的 你的智兔token 换成你拿到的真实 token,上面的脚本就能直接打印智兔 API 返回的数据。