从 AkShare 迁移到 ashareapi:接口对照与改写
AkShare 强在覆盖广,我们强在不用自己维护。如果你已经在用 AkShare、又被"上游改版→接口报错"折腾过,迁移主要是三处改动:代码格式、调用方式、字段名。下面给对照表与可运行示例,也写清哪些迁移不过来。
先想清楚:为什么从 AkShare 迁出来
AkShare 是 MIT 开源的免费 Python 库,数据面比我们宽得多(几乎什么都抓)。迁移动机通常不是"数据更多",而是这三个:
- 不想维护:AkShare 抓的是公开网页,上游改版 → 接口失效,得升级版本或改代码自己修
- 要稳定与缓存:我们的每个端点有多源备份(某个源出问题自动换)+ 缓存 + 健康巡检
- 要给 AI 用 / 非 Python 环境:我们用 HTTP + MCP,任意语言都能调,不用装 1,300+ 依赖
如果你预算为零、已在用 Python、且玩的是研究探索(不是生产跑任务),AkShare 是很好的选择——这页是给"想少维护一点"的人看的,不是要说服所有人。两者也可以同时用。
第一步:把代码格式从纯数字改成带前缀
这是迁移里最容易踩的坑。AkShare 的 `symbol` 是纯 6 位数字(`"600667"`);我们的是前缀式(`sh600667`)。所有端点都吃这个格式。
# AkShare # ashareapi
# "600667" (沪 A) → sh600667
# "000001" (深 A) → sz000001
# "830799" (北交所) → bj830799
# "00700" (港股) → hk00700
# "AAPL" (美股) → usAAPL
# 按代码首位判断市场(A 股规则)——够用但不完备,北交所/新老代码需按实际核对
def to_code(symbol: str) -> str:
"""把 AkShare 的纯数字代码转成 ashareapi 前缀式代码"""
if not symbol.isdigit():
return "us" + symbol.upper() # 非数字 → 美股
if symbol.startswith(("60", "68")): # 沪市主板 / 科创板
return "sh" + symbol
if symbol.startswith(("00", "30")): # 深市主板 / 创业板
return "sz" + symbol
if symbol.startswith(("83", "87", "43")): # 北交所
return "bj" + symbol
return "sh" + symbol # 兜底(务必按实际核对)- 最稳的做法:先用 `/v1/search?q=证券名称或代码` 拿到代码,它返回的就是正确的前缀式(自动消歧)
- 前缀式同时消掉了"同一个 000001 是平安银行还是上证指数"这类歧义
第二步:换调用方式(函数 → HTTP 请求)
AkShare 是 `import akshare as ak` 后调函数、拿 DataFrame;我们是发一个 GET 请求、拿统一的 JSON 信封。两端都不复杂,但形态不同。
# ── 改写前(AkShare)─────────────────────────
# import akshare as ak
# df = ak.stock_zh_a_hist(symbol="600667", period="daily",
# start_date="20260101", end_date="20260925",
# adjust="")
# print(df[["日期", "收盘", "成交量"]])
# ── 改写后(ashareapi)──────────────────────
import requests
BASE = "https://api.ashareapi.com/v1"
H = {} # 免费端点无需 Key;付费端点加 {"Authorization": "Bearer ct-你的Key"}
def get(path, **params):
r = requests.get(f"{BASE}/{path}", params=params, headers=H, timeout=30)
if r.status_code == 429: # 超频:见第五节
raise RuntimeError("rate limited")
r.raise_for_status()
body = r.json()
if not body.get("ok"):
raise RuntimeError(f"upstream failed (not counted): {body}")
return body["data"]
# 历史 K 线(免费)——等价 stock_zh_a_hist(无区间参数,取最近 N 根,回来自己按日期过滤)
bars = get("kline", code="sh600667", period="day", count=30)
for r in bars:
print(r["date"], r["last"], r["volume"]) # 原「收盘」→ last
# 实时行情(免费)——等价 stock_zh_a_spot_em 的单只版本
q = get("quote", code="sh600667")
print(q[0]["last"], q[0]["turnover"]) # 最新价 / 换手率- 没有 `adjust`(复权)参数 —— 口径固定为前复权(除权除息日不跳空);⚠️ 不要再自己复权(会二次复权);也不提供不复权 / 后复权数据
- 没有 `start_date` / `end_date` —— 用 `count` 取最近 N 根,再本地过滤(也避免"区间内无数据"被当成接口错误)
- 返回是 `list[dict]`(字段为字符串数字),不是 DataFrame;要 DataFrame 可以 `import pandas as pd; pd.DataFrame(bars)`
第三步:改字段名
只有几个常用字段名不同,其余同名同义。注意我们返回的数值是字符串(`"19.41"` 而非 `19.41`),比较/计算前记得转换。
| 含义 | AkShare 字段 | ashareapi 字段 | 说明 |
|---|---|---|---|
| 日期 | 日期 | date | 我们带横线(2026-09-24) |
| 收盘 / 最新 | 收盘 | last | 字段名不同,含义一致 |
| 今开 | 开盘 | open | 同名同义 |
| 最高 / 最低 | 最高 / 最低 | high / low | 同名同义 |
| 成交量(手) | 成交量 | volume | 同为手 |
| 成交额(元) | 成交额 | amount | 元 |
| 换手率(%) | 换手率 | turnover | 2026-09-26 由 `exchange` 改名(旧名易误读为「交易所」)· 与 `snapshot` 同名同值 |
| 股票代码 | 代码 / symbol | code | 前缀式 sh600667 |
接口对照表(AkShare 函数 → 我们的端点)
左列是 AkShare 官方文档里的常用函数名;右列是等价(或最接近)的端点。没有等价端点的不硬凑,见备注。
| AkShare | ashareapi | 备注 |
|---|---|---|
| stock_zh_a_spot_em(全市场实时) | GET /v1/quote(单只)· /v1/hot(热度) | 我们不做全市场快照批量导出,只有按代码取单只 |
| stock_zh_a_hist(历史行情) | GET /v1/kline | period=day|week|month,count 取最近 N 根(无区间参数) |
| stock_zh_a_hist_min_em(分钟) | ❌ | 不做分钟级数据(这是我们明确的边界) |
| stock_individual_info_em(个股信息) | GET /v1/profile · /v1/snapshot | profile = 上市日期/主营/行业;snapshot = 估值/市值/股本/涨停价 |
| stock_bid_ask_em(五档盘口) | GET /v1/orderbook | 买一~买五/卖一~卖五的价格与挂单量 |
| stock_financial_abstract(财务摘要) | GET /v1/finance | 三大报表多期(num 控期数),ROE/毛利率等在返回里 |
| stock_profit_sheet_by_report_em(利润表) | GET /v1/finance | 三表一次返回,不必三次调用 |
| stock_individual_fund_flow(个股资金流) | GET /v1/fund | 一个端点拿全:主力资金 + 龙虎榜 + 大宗 + 两融 |
| stock_market_fund_flow(大盘资金流) | ❌ | 没有全市场资金流分时;可看 /v1/changedist(市场广度,免费) |
| stock_lhb_detail_em(龙虎榜明细) | GET /v1/lhb | type=institution 机构 / hotmoney 游资 / activeseat 活跃席位 |
| stock_margin_detail_sse / _szse(两融) | GET /v1/margin-trade | 融资余额/买入/偿还/融券;code 支持批量 |
| stock_dzjy_mrmx(大宗交易明细) | GET /v1/block-trade | 成交价/折溢价/成交量/买卖方营业部 |
| stock_dividend_cninfo(分红送转) | GET /v1/dividend | years 控年份(默认 3 年) |
| stock_gdfx_free_top_10_em(十大流通股东) | GET /v1/shareholder | 十大股东 + 股东户数 + 机构持仓 |
| stock_zh_a_gdhs(股东户数) | GET /v1/shareholder | 股东户数(筹码集中度) |
| bond_zh_cov(可转债比价表) | GET /v1/bond | 条款为主:转股价/强赎触发/双低/溢价率;不提供转债日线 |
| fund_etf_spot_em(ETF 实时) | GET /v1/etf | 行情/规模/溢折率/资金流(code 形如 sh510300) |
| stock_new_gh_detail_em(新股) | GET /v1/ipo | 发行/申购/中签/上市日历(days 控天数) |
| stock_board_industry_name_em(行业板块) | GET /v1/sector · /v1/sector-valuation | 板块行情榜 + 板块估值(含历史分位) |
| stock_board_concept_name_em(概念板块) | GET /v1/sector · /v1/industry-chain | sector 含概念板块;industry-chain 给产业链上下游与关联度 |
| stock_zh_index_daily(指数日线) | ❌ | 有 /v1/market-overview(大盘画像/风格轮动/估值分位),不是指数 K 线 |
| stock_news_em / 公告 / 研报全文 | ❌ | 不做新闻与公告全文;研报只有脱水摘要(/v1/dehydrated) |
| 股票列表 / 全市场导出 | GET /v1/search(按关键词) | 不提供全量列表批量导出 |
第四步:限流与错误处理
AkShare 没有限流(本地调用);换成 HTTP API 后要处理 429 与上游失败。这也正是"稳定性"的代价与收益所在。
import time, requests
BASE = "https://api.ashareapi.com/v1"
H = {}
def get_with_retry(path, tries=3, **params):
for i in range(tries):
r = requests.get(f"{BASE}/{path}", params=params, headers=H, timeout=30)
if r.status_code == 429: # 超频
time.sleep(2 ** i) # 退避重试(别死循环打)
continue
r.raise_for_status()
body = r.json()
if not body.get("ok"): # 上游失败 → 不扣次数,可重试
time.sleep(1)
continue
return body["data"]
raise RuntimeError(f"{path}: failed after {tries} tries")- 免费端点:匿名正常配额 5 次/分,解一次 PoW 挑战(`GET /v1/challenge`)可到 60 次/分
- 注意:短时间内连续请求会被临时收紧(实测连续 6 次后提示"匿名限流 2 次/分")——退避即可恢复,不是封禁
- 付费 Key 按档位限流(体验 30 · 标准 120 · 专业 300 · 不限量 600 次/分)
- 上游取数失败不会扣次数(`ok:false`),可以安全重试;429 才需要退避
能迁 / 不能迁(写在前面,免得白迁)
- 能迁:实时行情 · 日/周/月 K 线 · 三大报表 · 资金流 · 龙虎榜 · 融资融券 · 大宗 · 分红 · 股东 · 可转债条款 · ETF · 新股 · 板块 · 产业链
- 不能迁:分钟级行情 · 新闻/公告/研报全文 · 指数日线 · 全市场列表批量导出 · 不复权 / 后复权序列(我们的 K 线口径固定为前复权)
- 态度:这几项请继续用 AkShare —— 它在这几块比我们强,两边同时用是最务实的组合
常见错误
- 代码写成 `"600667"` → 400/空结果;必须 `sh600667`(或用 `/v1/search` 确认)
- 拿字符串当数字算 → `"19.41" * 2` 不是 38.82;先 `float(...)` 再算
- 找不到 `adjust` / `start_date` / `end_date` → 复权口径固定为前复权(无参数可调)、不做区间查询;用 `count` + 本地过滤
- 换手率找不到 → 字段叫 `turnover`(`quote` / `kline` / `snapshot` 同名同值;2026-09-26 之前叫 `exchange`)
- 说"数据错了"其实是上游未披露 → 财务/股东/两融按披露节奏更新,未到披露日就是没有(不是接口故障)
常见问题
不是数据更多(AkShare 覆盖比我们宽),而是"少维护":AkShare 抓公开网页,上游改版时要自己修;我们做多源备份、缓存与巡检。如果预算为零、能接受维护,AkShare 是很好的选择——不必为了迁移而迁移。
能,而且常见。典型组合:冷门/极广的数据(新闻、公告、分钟、指数)用 AkShare 抓,核心数据(实时行情、资金、龙虎榜、板块估值)走我们,稳定性与维护成本由我们承担。
不行。所有端点都要求前缀式(`sh600667`)。最省事的转换方式是先用 `/v1/search?q=平安银行`,它返回的 code 就是正确格式,还顺带解决了"同名/同号"的消歧。
HTTP 端点返回的是 `list[dict]`(字段值多为字符串)。一行就能转:`import pandas as pd; df = pd.DataFrame(bars)`。官方 Python SDK(`pip install ashareapi`)装 `[pandas]` 后可直接返回 DataFrame。
先看端点清单(32 个端点按分类),或用 `/v1/search` 搜关键词。确实没有的(分钟、新闻公告全文、指数日线、不复权 / 后复权序列、全量列表)请继续用 AkShare——这是我们的边界,写在这里免得你白迁移。
最后更新: 2026-09-25
AkShare 侧函数名取自其官方文档(akshare.akfamily.xyz);我们侧端点数与分层取自官方端点清单 endpoints.json(32 个 = 7 免费 + 25 付费,2026-09-24 生成),字段与返回结构取自线上真实返回(quote / kline 于 2026-09-25 实测)。两侧接口与字段都可能变更,以各自官方页面为准。