普通网友 2025-11-21 04:30 采纳率: 98.6%
浏览 58
已采纳

ak.stock_zh_a_spot_em()为何仅返回100条数据?

为何 `ak.stock_zh_a_spot_em()` 仅返回100条数据?该函数基于东方财富网实时行情接口,通常默认限制单次请求返回前100只股票。这是由于接口分页机制或服务器端设定所致,并非函数本身缺陷。用户需通过分页参数或循环调用不同板块接口(如沪市、深市)获取完整数据。
  • 写回答

1条回答 默认 最新

  • Qianwei Cheng 2025-11-21 09:16
    关注

    一、现象解析:为何 ak.stock_zh_a_spot_em() 仅返回100条数据?

    在使用 AKShare 库调用 ak.stock_zh_a_spot_em() 函数时,许多开发者发现其默认返回结果仅为100条股票数据。这并非函数实现错误或本地环境问题,而是由底层数据源——东方财富网(East Money)的实时行情接口所决定。

    该接口设计上存在默认分页限制,即单次HTTP请求最多返回前100只A股股票的实时行情信息。这一机制常见于高并发金融数据平台,用于控制服务器负载与响应延迟。

    1.1 接口行为分析

    • 请求URL示例https://push2.eastmoney.com/api/qt/clist/get?pn=1&pz=100
    • 参数说明
      参数含义典型值
      pn页码(Page Number)1
      pz每页数量(Page Size)100
      fid排序字段IDf3(涨跌幅)
      fs市场代码过滤m:0+t:6,m:1+t:13(沪市+深市)
    • 从上述URL可见,pz=100 明确限定了最大返回条目数。

    1.2 分页机制的存在性验证

    通过修改 pn 参数可获取后续页面数据。例如:

    
    import akshare as ak
    
    # 获取第一页(默认)
    data_1 = ak.stock_zh_a_spot_em()
    
    # 模拟第二页请求(需自定义参数)
    # 实际中可通过构造URL或使用高级接口实现
        

    但由于 ak.stock_zh_a_spot_em() 封装层级较高,默认未暴露分页参数,导致用户难以直接翻页。

    二、深层技术动因剖析

    为何服务端要设定此限制?我们可以从多个维度进行推导:

    2.1 服务端性能与稳定性考量

    东方财富网每日需处理亿级行情查询请求。若允许单次返回全部4000+只A股数据,将显著增加:

    • 后端数据库查询压力
    • 网络传输带宽消耗
    • 前端渲染延迟(网页版用户体验)

    2.2 API 设计范式一致性

    主流金融数据API(如Tushare、Baostock、Sina Finance)均采用分页 + 板块划分策略。例如:

    数据源默认返回条数是否支持分页备注
    AKShare - EM接口100隐式支持需手动构造请求
    Tushare5000(可调)显式支持需Token权限
    Baostock不限(但慢)支持速度较慢

    三、解决方案与工程实践建议

    面对该限制,资深开发者应采取系统化方法突破数据边界。

    3.1 方案一:按市场板块分别请求

    利用不同板块标识符分别调用:

    
    # 示例:模拟分板块请求(实际需结合requests库)
    def fetch_all_stocks_by_sector():
        sectors = {
            "sh": "m:0+t:6",   # 沪市A股
            "sz": "m:1+t:13"   # 深市A股
        }
        all_data = []
        for name, fs_code in sectors.items():
            # 构造自定义请求(略)
            print(f"Fetching sector: {name} with filter: {fs_code}")
            # 调用底层接口并合并结果
        return all_data
        

    3.2 方案二:模拟分页抓取完整列表

    基于 pnpz 参数循环请求:

    
    import requests
    import pandas as pd
    
    def get_all_stocks_paged():
        url = "https://push2.eastmoney.com/api/qt/clist/get"
        params = {
            "pn": 1,
            "pz": 100,
            "fid": "f3",
            "fs": "m:0+t:6,m:1+t:13",
            "fields": "f1,f2,f3,f12,f14"
        }
        all_results = []
        while True:
            resp = requests.get(url, params=params)
            json_data = resp.json()
            data_list = json_data['data']['diff']
            if not data_list:
                break
            all_results.extend(data_list)
            params["pn"] += 1  # 下一页
        return pd.DataFrame(all_results)
        

    3.3 方案对比与选型建议

    以下为不同方案适用场景分析:

    方案实现难度稳定性推荐指数
    板块拆分★☆☆☆☆★★★★☆★★★★☆
    全量分页★★★☆☆★★★☆☆★★★☆☆
    混合策略★★★★☆★★★★★★★★★★

    四、架构级优化思路(面向高级开发者)

    对于构建企业级金融数据管道的团队,建议引入如下设计模式:

    4.1 使用 Mermaid 流程图描述数据采集流程

    graph TD
        A[启动采集任务] --> B{是否首次运行?}
        B -- 是 --> C[初始化板块队列]
        B -- 否 --> D[加载断点续传状态]
        C --> E[遍历每个市场板块]
        D --> E
        E --> F[设置 pn=1]
        F --> G[发送HTTP请求]
        G --> H{响应非空?}
        H -- 是 --> I[存储数据]
        I --> J[pn++]
        J --> G
        H -- 否 --> K[标记该板块完成]
        K --> L{所有板块完成?}
        L -- 否 --> E
        L -- 是 --> M[结束任务]
        

    4.2 异步并发提升效率

    结合 asyncioaiohttp 实现异步批量请求:

    
    import asyncio
    import aiohttp
    
    async def fetch_page(session, pn, pz=100):
        url = "https://push2.eastmoney.com/api/qt/clist/get"
        params = {"pn": pn, "pz": pz, "fs": "m:0+t:6,m:1+t:13", "fid": "f3"}
        async with session.get(url, params=params) as resp:
            return await resp.json()
    
    async def fetch_all_pages():
        async with aiohttp.ClientSession() as session:
            tasks = [fetch_page(session, pn) for pn in range(1, 50)]
            results = await asyncio.gather(*tasks)
            return [item for res in results for item in res.get('data', {}).get('diff', [])]
        
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 已采纳回答 11月22日
  • 创建了问题 11月21日