AKtools-源码解析-源码分析


AKShare 转换为 HTTP API 的实现分析

核心实现原理

AKTools 项目通过以下方式将 AKShare 转换为 HTTP API:

1. 基于 FastAPI 框架构建

项目使用 FastAPI 作为 HTTP 框架,提供了高性能的异步 API 服务:

app = FastAPI(
    title="欢迎访问 AKTools 为 AKShare 打造的 HTTP API 在线文档",
    description="AKTools 是 AKShare 的 HTTP API 工具, 主要目的是使 AKShare 的数据接口部署到服务器,从而让用户通过 HTTP 访问相关接口来获取所需要的数据",
    version=akshare.__version__,
    redoc_url=None,
)

2. 动态调用 AKShare 接口

核心实现位于 api.py 文件中,通过动态执行 AKShare 接口来实现 HTTP API:

2.1 公开接口实现

@app_core.get(path="/public/{item_id}", description="公开接口", summary="该接口主要提供公开访问来获取数据")
def root(request: Request, item_id: str):
    interface_list = dir(ak)
    decode_params = urllib.parse.unquote(str(request.query_params))

    if item_id not in interface_list:
        return JSONResponse(
            status_code=status.HTTP_404_NOT_FOUND,
            content={
                "error": "未找到该接口,请升级 AKShare 到最新版本并在文档中确认该接口的使用方式:https://akshare.akfamily.xyz"
            },
        )

    # 处理参数
    if "cookie" in decode_params:
        eval_str = (
                decode_params.split(sep="=", maxsplit=1)[0]
                + "='"
                + decode_params.split(sep="=", maxsplit=1)[1]
                + "'"
        )
        eval_str = eval_str.replace("+", " ")
    else:
        eval_str = decode_params.replace("&", '", ').replace("=", '="') + '"'
        eval_str = eval_str.replace("+", " ")  # 处理传递的参数中带空格的情况

    # 执行 AKShare 接口
    try:
        if not bool(request.query_params):
            received_df = eval("ak." + item_id + "()")
        else:
            received_df = eval("ak." + item_id + f"({eval_str})")

        if received_df is None:
            return JSONResponse(
                status_code=status.HTTP_404_NOT_FOUND,
                content={"error": "该接口返回数据为空,请确认参数是否正确:https://akshare.akfamily.xyz"},
            )

        # 转换为 JSON 格式
        temp_df = received_df.to_json(orient="records", date_format="iso")
        return JSONResponse(status_code=status.HTTP_200_OK, content=json.loads(temp_df))
    except KeyError as e:
        return JSONResponse(
            status_code=status.HTTP_404_NOT_FOUND,
            content={
                "error": f"请输入正确的参数错误 {e},请升级 AKShare 到最新版本并在文档中确认该接口的使用方式:https://akshare.akfamily.xyz"
            },
        )

2.2 私有接口实现

私有接口与公开接口类似,但增加了用户认证功能:

@app_core.get("/private/{item_id}", description="私人接口", summary="该接口主要提供私密访问来获取数据")
def root(
        request: Request,
        item_id: str,
        current_user: User = Depends(get_current_active_user),
):
    # 实现逻辑与公开接口类似,但增加了用户认证
    # ...

3. 工作流程

  1. 请求接收:客户端发送 HTTP 请求到 /public/{接口名}/private/{接口名}
  2. 参数解析:解析 URL 查询参数
  3. 接口验证:检查请求的接口是否存在于 AKShare 库中
  4. 动态执行:使用 eval 动态执行 AKShare 接口
  5. 数据转换:将返回的 DataFrame 转换为 JSON 格式
  6. 响应返回:返回 JSON 格式的数据给客户端

4. 技术特点

  1. 动态接口映射:无需为每个 AKShare 接口编写单独的 API 端点
  2. 参数自动处理:自动处理 URL 查询参数,转换为函数调用参数
  3. 错误处理:提供详细的错误信息,帮助用户排查问题
  4. 用户认证:支持私有接口的访问控制
  5. CORS 支持:允许跨域请求,方便前端调用
  6. 日志记录:记录 API 调用情况,便于问题排查

使用方法

1. 启动服务

python -m aktools
# 或
python aktools/main.py

2. 访问 API

2.1 无参数接口

例如获取打新收益率:

GET http://localhost:8080/api/public/stock_dxsyl_em

2.2 带参数接口

例如获取股票历史数据:

GET http://localhost:8080/api/public/stock_zh_a_hist?symbol=000001&period=d&start_date=20230101&end_date=20230131&adjust=qfq

3. 访问文档

服务启动后,可以访问以下地址查看 API 文档: - Swagger UI: http://localhost:8080/docs - 项目主页: http://localhost:8080/

项目结构

aktools/
├── aktools/
   ├── core/
      └── api.py          # 核心 API 实现
   ├── main.py             # 主入口文件
   ├── config.py           # 配置文件
   ├── utils.py            # 工具函数
   └── ...
├── requirements.txt        # 依赖文件
└── setup.py                # 安装配置

核心技术栈

  • FastAPI: 高性能的 HTTP 框架
  • AKShare: 金融数据接口库
  • Uvicorn: ASGI 服务器
  • Pandas: 数据处理库(AKShare 依赖)
  • Jinja2: 模板引擎

代码优化建议

  1. 安全性改进
  2. 当前使用 eval 执行动态代码,存在安全风险
  3. 建议使用更安全的方式调用 AKShare 接口,如使用 getattr 和参数字典

  4. 性能优化

  5. 考虑使用异步执行 AKShare 接口,提高并发处理能力
  6. 实现缓存机制,减少重复请求

  7. 代码结构

  8. 提取公共代码逻辑,减少重复代码
  9. 增加单元测试,提高代码可靠性

  10. 错误处理

  11. 增加更详细的错误处理,区分不同类型的错误
  12. 提供更友好的错误提示

  13. 文档完善

  14. 增加 API 使用示例
  15. 提供更详细的参数说明

总结

AKTools 项目通过巧妙的设计,将 AKShare 的所有数据接口转换为 HTTP API,使得用户可以通过网络请求获取金融数据,而无需在本地安装 Python 和相关依赖。这种实现方式不仅方便了前端开发者使用 AKShare 的数据,也为数据分析和可视化提供了更多可能性。

通过动态调用和参数自动处理,项目实现了高度的灵活性和可扩展性,能够随着 AKShare 的更新自动支持新的接口,无需修改代码。这种设计思路值得学习和借鉴。