AKShare 实现与跨语言接入调查
AKShare 实现与维护机制
分析函数组织、导出、解析、JS 资产、错误及维护责任。
调查基线为原材料记载的 2026-10-04、AKShare v1.19.1、浅克隆短提交号 fac1e50。本轮读取了归档报告;未取得原运行环境或重跑接口、全库计数及 npm 检索。下文统计和“实测”均属于原调查记录,不能自动代表当前版本或服务可用性。短提交链接本轮未成功取得,数字保留为历史证据并披露复算边界。
一、项目概览与实现原理
结论先行:akshare 主要实现为一个"对东方财富、新浪财经、金十、巨潮资讯、同花顺、各交易所官网等数十家金融网站的公开(含逆向出的私有)HTTP 接口做同步抓取与聚合"的 Python 爬虫集合。
单个接口的实现范式
每个接口函数是一个自包含单元,典型五段式:
- URL(含 token)硬编码在函数体内;
- 按需伪造浏览器请求头;
requests同步请求;- 手工解析(JSON / jsonp 剥壳 /
read_html/read_excel/ JS 解密); - 中文列名重命名 +
to_datetime/to_numeric类型收敛,返回pandas.DataFrame。
以 A 股日线 stock_zh_a_hist 为例:URL https://push2his.eastmoney.com/api/qt/stock/kline/get 与 ut token 均硬编码(akshare/stock_feature/stock_hist_em.py:981-991),r.json() 后将 klines 每行按逗号 split 建 DataFrame(:993-996),再逐列清洗(:998-1039)。新浪期货日线则需手工剥 jsonp 壳:r.text.split("=(")[1].split(");")[0](akshare/futures/futures_zh_sina.py:651-688)。
包结构与接口导出
- 打包:
setup.py是 6 行空壳,真正配置在pyproject.toml——setuptools>=61 后端(pyproject.toml:1-3)、动态版本取akshare._version.__version__(:97-98)、requires-python >=3.11(:10)、随包分发*.json/*.js/*.pk/*.zip数据文件(:100-104,即逆向用的ths.js/cninfo.js等)。 - 组织维度:数据品类子包(stock、stock_feature、stock_fundamental、futures、option、fund、bond、index、economic、fx、crypto、news 等,实测 36 个代码子包)× 每个数据源一个文件,如
stock_feature/stock_hist_em.py="东方财富历史行情"、stock_lhb_sina.py="新浪龙虎榜"。 - 导出:
__init__.py共 7103 行,自:3311起 344 条from akshare.子包.模块 import 函数,纯 import 聚合、无工厂无懒加载;__all__实有 1102 项 = 1096 个接口函数 + 6 个异常类(akshare/exceptions.py:6-40)。 - 接口注册表:构建期
scripts/build_registry.py解析 docs 与__init__.py生成akshare/data/interfaces.json(实测 1090 条),运行时支撑ak.search()/interface_info()/list_categories()检索(akshare/registry.py:31-41)。
逆向是确凿的核心手段
- py_mini_racer(V8 JS 引擎)在 40 个源文件中使用,执行从网站前端抠出的 JS:
- 同花顺:读取打包的
akshare/data/ths.js(含v_cookie函数,ths.js:2)→js_code.call('v')生成 v_code → 以Cookie: v={v_code}与hexin-v头请求(akshare/stock_feature/stock_board_industry_ths.py:43-52, :237); - 巨潮资讯:
akshare/data/cninfo.js(CryptoJS 实现)→call('getResCode1')生成 mcode → 塞进Accept-Enckey请求头 POSTwebapi.cninfo.com.cn(akshare/stock/stock_new_cninfo.py:38-45;债券侧akshare/bond/bond_issue_cninfo.py:44-47); - 新浪:内嵌
hk_js_decodeJS 常量(akshare/stock/cons.py:239)解密加密 K 线文本(akshare/stock/stock_zh_a_sina.py:183-187)。
- 同花顺:读取打包的
- TLS 指纹伪装:curl_cffi
impersonate="chrome"模拟 Chrome JA3 指纹(akshare/economic/macro_china_nbs.py:63)。 - 东财 push2 接口的
uttoken 直接硬编码(stock_hist_em.py:28, :985)。 - 唯一 token 制例外
pro_api:对接奇货可查api.qhkch.com的鉴权 API(tushare 风格),token 持久化到用户目录(akshare/pro/data_pro.py、akshare/utils/token_process.py)。
架构现状与维护机制
- 无统一抽象层/基类/持久化缓存/全局限速:406 个源文件中 314 个直接调用
requests.get/post("直接"=文件内出现requests.get/post字面调用、不经request_with_retry/make_request_with_retry_*等共享封装。注意这是文件级口径,与 请求头口径 的"849 处调用点不带 headers"是调用点级口径,两个维度正交——直接调用可以带伪装头,封装调用也可能不带);带指数退避+随机抖动的request_with_retry仅 6 个文件使用(定义于akshare/utils/request.py:15-64);限速仅局部——翻页间time.sleep(random.uniform(0.5,1.5))(akshare/utils/func.py:49)。复核纠正:并非"完全没有缓存"——functools.lru_cache在约 30 个文件 50+ 处做局部记忆化(多为品种映射表),但确无统一/持久化缓存层。 - 异常体系定义了 6 个异常类,但接口层很少抛出(全库仅 13 个文件 30 处 raise)。失败时调用者实际拿到什么:绝大多数直调请求未设超时(全库仅 85 处出现
timeout=,对应 1291 个调用点,原调研修订 grep 复核),失败时 requests 原生异常(ConnectionError/Timeout/JSONDecodeError 等)原样向上冒泡、不会转译为自定义异常——经 AKTools 透传给 TS 端的就是 HTTP 错误码 + 异常文本,无结构化错误契约。 - 接口增删维护:
__init__.py:9-3310是手写逐版本更新记录 docstring(约 3300 行);docs/changelog.md有接口更名一览表;发布前scripts/check_release.py校验 git tag /_version.py/ docstring / changelog 四处一致。 tests/仅 8 个文件且全部测工具(registry/构建/发布脚本/乐咕 csrf,monkeypatch 不联网),无任何数据接口回归测试(因依赖外网无法稳定 CI)。- 本仓库为 depth=1 浅克隆,无法做 git 历史维度的接口增删频率分析(改以版本记录为证据)。
最后更新于