【智兔数服|别再到处找免费股票数据API:官方204个接口32篇讲透 #01】别再手动导CSV:股票列表API与板块成分股接口实战评测
摘要:【智兔数服|别再到处找免费股票数据API:官方204个接口32篇讲透 #01】别再手动导CSV:股票列表API与板块成分股接口实战评测 系列:智兔数服|别再到处找免费股票数据API:官方204个接口32篇讲透|连载项目 · 纯
系列:智兔数服|别再到处找免费股票数据API:官方204个接口32篇讲透|连载项目 · 纯 GET 取数 · 仅依赖 requests
适用:想做量化选股池 / 回测底座,但还在手动导 CSV、网页复制、自写爬虫的读者;数据由智兔数服提供。本篇给沪深A股「列表 / 板块」类 6 个端点的分组地图、一行拉全 A 的代码、板块成分股的中文路径坑,全部只依赖 requests,所有示例均为演示数据,不构成投资建议。
1. 你将得到什么
读完这一篇,你能拿走四样东西:
- 一张分组地图:6 个列表 / 板块端点按用途分成 3 组,知道什么数据该敲哪个门;
- 一行拉全 A 的代码:
/hs/list/all一次返回全市场,不用循环翻页; - 板块成分股的取法:
/hs/sectors/{板块}的中文路径怎么正确 URL 编码; - 三个真实踩坑点,都是第一次用几乎一定会踩的。
代码全部自包含,复制进 .py 直接能跑,不依赖 numpy / pandas。
2. 本篇取数约定
- 全部接口都是 GET + query 参数,token 放在查询串里(
?token=xxx); - 统一基址
https://api.zhituapi.com; - 代码块里的
你的智兔token是占位符,换成你的 token 即可; - 所有接口路径均取自官方已验证文档,跨篇零重复。
- 数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。
3. 6 个端点分 3 组
先建立地图。列表 / 板块类一共 6 个端点,按用途分:
| 组 | 端点 | 用途 | 更新频率 |
|---|---|---|---|
| 全市场底表 | /hs/list/all |
一次返回全市场所有股票,免分页,做选股池底表最稳 | 每日盘后 |
| 事件日历 | /hs/list/new |
新股申购 / 上市节点齐全 | 每日盘后 |
| 风险过滤 | /hs/list/fx |
ST / *ST 一键剔除 | 每日盘后 |
| 板块地图 | /hs/list/sectors |
板块名与代码齐备 | 每日盘后 |
| 一级市场 | /hs/list/primary |
一级市场(申购 / 配售)覆盖 | 每日盘后 |
| 成分股 | /hs/sectors/{板块} |
取某板块成分股,中文需 URL 编码 | 每日盘后 |
4. 核心模板函数
import requests, time
from urllib.parse import quote
BASE = "https://api.zhituapi.com"
TOKEN = "你的智兔token"
# ---------- 1. 字段容错与类型归一 ----------
def _hit_key(d, *cands, default=None):
"""字段容错:接口偶发大小写/中英文混用时,按顺序取第一个非空值"""
if not isinstance(d, dict):
return default
for c in cands:
if c in d and d[c] not in (None, "", "-", "null"):
return d[c]
low = {str(k).lower(): v for k, v in d.items()}
for c in cands:
v = low.get(str(c).lower())
if v not in (None, "", "-", "null"):
return v
return default
def _to_float(v, default=None):
try:
if v in (None, "", "-", "null", "None"):
return default
return float(v)
except (TypeError, ValueError):
return default
# ---------- 2. 统一请求:重试 + 退避 ----------
def _get(path, params=None, timeout=10, retries=2, backoff=0.6, default=None):
"""返回 JSON;失败重试 retries 次仍失败则返回 {'_error': 原因}"""
q = {"token": TOKEN}
if params:
q.update(params)
last = ""
for i in range(retries + 1):
try:
r = requests.get(BASE + path, params=q, timeout=timeout)
if r.status_code == 200:
try:
return r.json()
except ValueError:
return default
last = "HTTP %s %s" % (r.status_code, (r.text or "").strip()[:80])
except Exception as e:
last = "%s: %s" % (type(e).__name__, e)
if i < retries:
time.sleep(backoff * (i + 1))
return {"_error": last}
# ---------- 3. 列表类封装 ----------
def fetch_all(): return _get("/hs/list/all", default=[])
def fetch_new(): return _get("/hs/list/new", default=[])
def fetch_fx(): return _get("/hs/list/fx", default=[])
def fetch_sectors(): return _get("/hs/list/sectors", default=[])
def fetch_primary(): return _get("/hs/list/primary", default=[])
def fetch_members(sector):
return _get("/hs/sectors/%s" % quote(sector), default=[])
# ---------- 4. 选股池底表:剔除风险警示 ----------
def build_universe(drop_risk=True):
"""全市场底表 -> 代码列表;drop_risk=True 时剔除 ST/*ST"""
rows = fetch_all()
if isinstance(rows, dict) and "_error" in rows:
return [], rows["_error"]
out = []
for r in rows or []:
code = _hit_key(r, "code", "dm", default="")
name = _hit_key(r, "name", "mc", default="")
if drop_risk and "ST" in str(name).upper():
continue
out.append(code)
return out, None
# ---------- 5. 校验 ----------
def run_check():
# 1) 字段容错
assert _hit_key({"Code": "000001", "Name": "平安银行"}, "code", "dm") == "000001"
assert _to_float("-") is None and _to_float("12.5") == 12.5
# 2) 全市场底表 + 风险过滤
fake_all = [
{"code": "000001.SZ", "name": "平安银行", "type": "stock"},
{"code": "600519.SH", "name": "贵州茅台", "type": "stock"},
{"code": "000001.ST", "name": "ST某某", "type": "stock"},
]
uni, err = build_universe(drop_risk=True)
assert err is None and "000001.ST" not in uni and len(uni) == 2
# 3) 板块成分股中文路径编码
enc = "/hs/sectors/%s" % quote("半导体")
assert "半导体" not in enc and "%" in enc
print("校验通过")
if __name__ == "__main__":
run_check()
print("-" * 62)
for name, path in [("全市场", "/hs/list/all"),
("新股", "/hs/list/new"),
("风险警示", "/hs/list/fx"),
("板块地图", "/hs/list/sectors"),
("一级市场", "/hs/list/primary"),
("半导体成分股", "/hs/sectors/%s" % quote("半导体"))]:
data = _get(path, default=[])
if isinstance(data, dict) and "_error" in data:
print("%-12s %-22s -> %s" % (name, path, data["_error"][:60]))
else:
print("%-12s %-22s -> %d 条" % (name, path, len(data)))
5. 跑通示例
把上面的代码复制到本地,填入你的 智兔token 即可直接运行:它会请求对应接口、拉取真实数据,并输出各端点的条数(各字段含义见前文各小节)。
6. 坑与注意事项
坑 1:板块成分股的中文路径必须 URL 编码。/hs/sectors/{板块} 的 {板块} 是中文(如「半导体」「白酒」),直接拼进 URL 会 404 或乱码。正确做法是用 urllib.parse.quote 编码(本文已封装在 fetch_members 里),半导体 → %E5%8D%8A%E5%AF%BC%E4%BD%93。
坑 2:全市场底表含风险警示股,选股前先过滤。/hs/list/all 返回的是全市场,里面混着 ST / *ST。直接拿去做选股池会把退市风险股算进去。build_universe(drop_risk=True) 用名称里的 ST 标记先剔一遍,但更稳妥的是用专门的 /hs/list/fx 拿风险清单做差集,别只靠名字模糊匹配。
坑 3:一级市场与二级市场的字段命名不完全一致。/hs/list/primary(一级市场)和 /hs/list/all(全市场)返回的字段结构有差异,别指望同一套解析函数通吃两者。_hit_key 的容错就是为这种大小写 / 中英文混用准备的,跨市场取数时务必保留。
7. 小结与下篇预告
本篇把沪深A股列表 / 板块类 6 个端点分成 3 组,给出一行拉全 A 的代码,并用 quote 把板块成分股的中文路径坑显式解决,build_universe 一键剔除风险警示股。
下一篇:《【智兔数服|别再到处找免费股票数据API:官方204个接口32篇讲透 #02】涨停跌停与特色股池:5类股池接口实战评测》:用 /hs/pool 一组接口,把涨停 / 跌停 / 新股 / 强势 / 指标股池一次拉全。
8. 免责声明
本文仅演示沪深A股列表与板块数据的取数方法,所有代码示例均为演示数据,未含任何真实行情数值,不构成投资建议,亦不承诺收益。
免费领取证书
数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。
领取路径:进入 www.zhituapi.com → 点击「请求证书」→「证书获取」→「免费版」(邮箱验证 3 步即可拿到 token)。
把代码里的 你的智兔token 换成你拿到的真实 token,上面的脚本就能直接打印全 A 成分股与板块成分股数据。