Akshare 财经数据抓取实战:量化交易的第一步

本文介绍如何利用 Python 库 Akshare 抓取 A 股历史行情数据,并为后续的机器学习模型做准备。

为什么选择 Akshare?

对于我们的量化研究库来说,Akshare 提供了极其丰富的接口,涵盖了从股票、期货到宏观经济的全维度数据。 . 环境准备 确保您的 Python 环境已安装。由于 Akshare 依赖较多,建议在独立虚拟环境中操作。 安装命令:

pip install akshare --upgrade

核心代码实现

以下是在我的 Minisforum N5 Pro 服务器上测试通过的代码片段:

import akshare as ak

A. 股票行情数据 获取 A 股所有股票的最新实时行情。

# 获取日线数据
df = ak.stock_zh_a_hist(symbol="000001", period="daily", adjust="qfq")
print(df.head())

adjust=“qfq” 表示前复权,这在量化分析中非常重要。 B. 历史行情数据(日线/周线/月线) 获取特定股票的历史数据,适合用于回测。

stock_zh_a_hist_df = ak.stock_zh_a_hist(symbol="600519", period="daily", start_date="20230101", end_date="20231231", adjust="qfq")
print(stock_zh_a_hist_df)

B. 获取实时行情(全市场 snapshot) 用于实盘监控或盘后快速扫描:

# 获取当前时刻 A 股所有股票的实时行情
stock_zh_a_spot_em_df = ak.stock_zh_a_spot_em()
print(stock_zh_a_spot_em_df.head())

ETF数据源 使用fund_etf_category_sina 函数获取所有 ETF 基金的实时行情数据。

etf_data = ak.fund_etf_category_sina(symbol="ETF基金")
# 显示前10行
print(etf_data.head(10))

获取全部A股(沪、深、京市)股票代码和简称最基础

# 获取全市场 A 股代码和名称
stock_list_df = ak.stock_info_a_code_name()

# 查看前 5 行数据
print(stock_list_df.head())

# 查看当前 A 股市场总共有多少只股票
print(f"当前 A 股总计股票数量: {len(stock_list_df)}")
# 过滤掉名称中包含 "ST" 或 "退" 的股票
clean_stock_pool = stock_list_df[
    ~stock_list_df['name'].str.contains('ST|退')
]
print(f"清洗后的股票数量: {len(clean_stock_pool)}")

C. 宏观经济数据 如果你在做多因子模型,可能需要这些 中国 PMI 数据

macro_china_pmi_df = ak.macro_china_pmi_index()
print(macro_china_pmi_df)

获取 10 年期国债收益率数 有两个主要的接口可以选择,具体取决于你需要的数据维度: 方法一:使用 bond_zh_us_rate 接口(最简单直接,推荐) 这个接口专门用于获取中国和美国的宏观国债收益率(主打 10 年期和 2 年期),支持直接拉取长周期的历史数据,没有单次获取的时间跨度限制。

# 获取中美国债收益率历史数据
# start_date 指定起始日期,格式为 "YYYYMMDD"
bond_zh_us_rate_df = ak.bond_zh_us_rate(start_date="20200101")

# 提取所需的日期和中国 10 年期国债收益率
china_10yr_yield = bond_zh_us_rate_df[['日期', '中国国债收益率10年']]

# 打印最后 5 行数据
print(china_10yr_yield.tail())

返回的主要字段:日期、中国国债收益率10年、中国国债收益率2年、美国国债收益率10年、美国国债收益率2年 等。 方法二:使用 bond_china_yield 接口(获取完整收益率曲线) 这个接口调取的是中国债券信息网的“国债及其他债券收益率曲线”数据,包含了从 3 个月到 30 年的完整关键期限数据。 注意:受数据源接口限制,单次请求的 start_date 到 end_date 时间跨度不能超过一年。如果需要历史长序列数据,需要写一个循环分段拉取并拼接。

# 获取特定一年的完整国债收益率曲线数据
bond_china_yield_df = ak.bond_china_yield(start_date="20230101", end_date="20231231")

# 接口返回的包含多种债券类型,需过滤出“中债国债收益率曲线”
mask = bond_china_yield_df['曲线名称'] == '中债国债收益率曲线'
yield_curve_df = bond_china_yield_df[mask]

# 提取日期和具体的 10 年期收益率(列名为 '10年')
china_10yr_yield_curve = yield_curve_df[['日期', '10年']]

print(china_10yr_yield_curve.tail())

返回的主要字段:曲线名称、日期、3月、6月、1年、3年、5年、7年、10年、30年 等。 总结建议

  • 如果你只关心 10 年期国债 的绝对走势,或者需要同时对比中美利差,直接调用 bond_zh_us_rate。
  • 如果你做期限利差分析(例如 10Y-2Y 甚至 30Y-10Y),需要各期限的完整结构,使用 bond_china_yield 最为合适。 C. 股息红利数据 既然您的目标是长期股息红利,以下接口非常关键:
# 获取个股的分红送股数据
stock_history_dividend_df = ak.stock_history_dividend_detail(symbol="600036", indicator="分红")
print(stock_history_dividend_df)

. 获取三大基本报表 Akshare 提供了从东方财富(EM)或新浪财经(Sina)抓取的接口。 A. 资产负债表 (Balance Sheet) 展示公司在特定时点的资产、负债及所有者权益情况。

# 获取贵州茅台的资产负债表 (按报告期)
stock_balance_sheet_df = ak.stock_balance_sheet_by_report_em(symbol="600519")
print(stock_balance_sheet_df.head())

B. 利润表 (Income Statement) 展示公司在一定时期内的经营成果(营业收入、净利润等)。

# 获取利润表
stock_profit_sheet_df = ak.stock_profit_sheet_by_report_em(symbol="600519")
print(stock_profit_sheet_df.head())

C. 现金流量表 (Cash Flow Statement) 对分红投资者最重要的一张表,体现公司是否有真金白银。

# 获取现金流量表
stock_cash_flow_sheet_df = ak.stock_cash_flow_sheet_by_report_em(symbol="600519")
print(stock_cash_flow_sheet_df.head())
  1. 获取关键财务指标 (推荐) 如果您想直接看“股息率”、“ROE”、“每股收益”等计算好的数据,可以使用以下接口。 主要财务指标 这个接口包含了盈利能力、偿债能力、运营能力等综合指标。
# 获取主要财务指标
stock_financial_analysis_indicator_df = ak.stock_financial_analysis_indicator(symbol="600519")
print(stock_financial_analysis_indicator_df)

关键字段说明(与分红相关): 每股未分配利润:这是未来分红的潜力储备。 每股经营现金流:确保分红不是靠借钱发的。 净资产收益率 (ROE):评估公司赚钱的效率。

# 获取特定股票的公告列表(以平安银行为例)
stock_announcement_df = ak.stock_zcx_announcement(symbol="000001")
print(stock_announcement_df)

获取财报公告列表(巨潮资讯) 这是最常用的方式,可以获取指定个股的所有公告(包括年报、半年报)的标题、发布日期以及 PDF 下载链接。 接口: stock_zcx_announcement 提示: 返回的 DataFrame 中通常包含 公告标题 和 公告链接。你可以根据标题筛选“年度报告”或“摘要”,然后通过链接下载 PDF 进一步解析。 2. 获取财务报表 3. 获取业绩快报与预告 如果你需要的是财报正式发布前的文字版业绩描述或摘要数据: 业绩快报: stock_zhyjkb_em 业绩预告: stock_zyjsyg_em

# 获取最新季度的业绩预告
yjyg_df = ak.stock_zyjsyg_em(date="20231231")
print(yjyg_df)

. 进阶:如何处理“非结构化”文本? 由于 AKShare 本身主要提供数据抓取,并不直接提供年报内部的“董事会经营评述”等纯文本提取。如果你需要做文本分析(如词频分析、情感分析),建议: 利用 stock_zcx_announcement 获取 PDF URL。 使用 Python 库 pdfplumber 或 PyMuPDF 下载并解析该 PDF。 定位“管理层讨论与分析”章节提取文本。 常用技巧总结

需求类型 推荐接口 下载年报原文 (PDF) stock_zcx_announcement 三大报表数据 stock_balance_sheet_by_report_em 业绩快报摘要 stock_zhyjkb_em 个股基本概况 stock_individual_info_em

下载年报原文 (PDF) 接口: stock_zcx_announcement 用途: 获取巨潮资讯上的公告,返回 PDF 的下载链接。 代码示例:

# symbol: 股票代码(不带后缀)
df = ak.stock_zcx_announcement(symbol="000001")
# 筛选包含“年度报告”字样的公告
annual_reports = df[df['公告标题'].str.contains("年度报告")]
print(annual_reports[['公告标题', '公告链接']])

解析中国上市公司年报(PDF)最精准的工具。 相比于传统的 PyPDF2,pdfplumber 的核心优势在于它对表格数据的提取能力以及对字符坐标的精确控制,这对于解析财报中复杂的资产负债表至关重要。 以下是针对你量化研究场景的实战进阶指南:

  1. 为什么它是解析年报的首选? 中国上市公司的 PDF 年报通常包含大量的嵌套表格和复杂的排版。
  • 高精度表格识别:能自动识别表格边框,甚至可以处理没有外边框的“无线表格”。
  • 可视化调试:它允许你将 PDF 页面导出为图像,并叠加识别出的表格框线,方便调整参数。
  • 文本流还原:能较好地处理双栏排版,不会像某些库那样把左右两栏的文字混在一起。
  1. 核心代码:提取年报中的关键表格 假设你通过 Akshare 拿到了 PDF 链接并下载到了本地,以下是提取“主要财务数据”表格的典型逻辑:

import pdfplumber
import pandas as pd

def extract_financial_table(pdf_path, page_num):
    with pdfplumber.open(pdf_path) as pdf:
        page = pdf.pages[page_num]
        
        # 自动搜索页面中的表格
        table = page.extract_table(table_settings={
            "vertical_strategy": "lines", 
            "horizontal_strategy": "lines",
            "snap_tolerance": 3, # 容差,解决线段不连续问题
        })
        
        if table:
            df = pd.DataFrame(table[1:], columns=table[0])
            # 清洗:去除换行符,防止数据错位
            df = df.replace('\n', '', regex=True)
            return df
    return None
  1. 针对“管理层讨论与分析”的文本提取 对于你的 TFT 模型 或 NLP 情感分析,你需要提取特定章节的文字。通常这一章包含公司对未来分红潜力的主观描述。
def extract_text_by_keyword(pdf_path, keyword="管理层讨论与分析"):
    full_text = ""
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            text = page.extract_text()
            if keyword in text:
                # 找到关键字所在的页面开始提取,直到下一个大标题
                full_text += text
    return full_text
  1. 你的 Home Lab 实战建议 (Minisforum N5 Pro) 由于解析 PDF 是 CPU 密集型任务,你在 N5 Pro 上运行抓取脚本时,可以利用 multiprocessing 进行并行解析:
  • 分步走:先用 Akshare 的 stock_zcx_announcement 批量获取 PDF URL。
  • 异步下载:使用 httpx 或 aiohttp 快速下载 PDF 到你的 NVMe 硬盘。
  • 多进程解析:
    • PDF 解析比较费内存,建议 96GB 内存的你,可以同时开启 8-12 个进程并行处理几百家公司的年报。
    • 解析后的结构化数据(如提取出的股息政策文字)直接存入你的 TimescaleDB 的 JSONB 字段中,方便后续做词频向量化。 💡 小提醒 pdfplumber 解析纯文本很快,但 extract_table 比较慢。如果你的目标只是提取三大报表,Akshare 现成的财务接口(如 stock_balance_sheet_by_report_em)速度会快几个数量级。 只有当你需要提取 “利润分配预案详情” 这种接口没涵盖的细节文本时,才祭出 pdfplumber 这个大杀器。 你目前是打算用它来做简单的文本特征提取,还是准备结合 LLM 做更深度的语义分析?
  1. 个股基本概况 接口: stock_individual_info_em 用途: 获取个股的基本信息,如总股本、流通股本、所属行业、上市日期等
# symbol: 股票代码(不带后缀)
df = ak.stock_individual_info_em(symbol="600519")
print(df)

获取最新个股研报一览 该接口可以返回全市场的最新研报列表,包括研报标题、评级、机构名称等。

# 获取个股研报数据
stock_report_df = ak.stock_zyjs_report_em()
print(stock_report_df.head())

获取特定股票的盈利预测 这对于你做长期的“股息红利”目标非常有参考价值,可以预估未来的分红能力

# 以中国神华 (601088) 为例
symbol = "601088"
profit_forecast_df = ak.stock_profit_forecast_em(symbol=symbol)
print(profit_forecast_df)

C. 研报评级调高/个股排行 筛选出近期机构一致看好的标的:

# 获取机构关注度排行
stock_rank_df = ak.stock_report_stock_rank_em()
print(stock_rank_df)

常见应用场景示例

场景:筛选高股息率股票 结合多个接口,您可以编写脚本自动计算当前的股息率情况

步骤接口示例
1. 获取成分股ak.index_stock_cons(symbol=“000016”) (上证50)
2. 获取财务报表ak.stock_financial_analysis_indicator()
3. 获取最新市值ak.stock_zh_a_spot_em

针对“股息红利”的专项数据

既然您的目标是红利策略,以下两个接口能提供更直观的支持:

接口名称功能适用场景
ak.stock_history_dividend()历史分红详情查看公司历年送股、转增、派现数据。
ak.stock_zh_a_gdhs_detail_em()股东户数详情观察筹码集中度,判断大股东动向。

数据清洗与标准化

原始数据往往需要清洗才能用于量化研究。以下是几个关键处理步骤: 必须进行的清洗操作:处理缺失值(特别是停牌日) 统一命名规范(列名英文小写) 确保时间序列连续性 处理异常值(如涨跌幅超过限制)

import pandas as pd

def clean_data(raw_df):
    """数据清洗标准化"""
    
    # 1. 列名标准化 (额外补充了 AkShare 常返回的其他核心字段)
    df = raw_df.rename(columns={
        '日期': 'date',
        '开盘': 'open',
        '收盘': 'close',
        '最高': 'high',
        '最低': 'low',
        '成交量': 'volume',
        '成交额': 'amount',
        '振幅': 'amplitude',
        '涨跌幅': 'pct_chg',
        '涨跌额': 'change',
        '换手率': 'turnover'
    })
    
    # 2. 时间类型转换 (补全了你截断的代码)
    df['date'] = pd.to_datetime(df['date'])
    
    # 3. 数值类型转换
    # AkShare 返回的 dataframe 往往全都是 object (字符串) 类型,
    # 直接计算移动平均线或送入模型会报错,这里强制转为 float
    numeric_cols = ['open', 'close', 'high', 'low', 'volume', 'amount', 
                    'amplitude', 'pct_chg', 'change', 'turnover']
    
    # 使用 intersection 保证只转换 dataframe 中实际存在的列,避免 KeyError
    exist_cols = df.columns.intersection(numeric_cols)
    df[exist_cols] = df[exist_cols].apply(pd.to_numeric, errors='coerce')
    
    # 4. 时间序列排序与去重
    # 防止接口返回的数据顺序错乱(导致回测出现未来函数)以及由于数据源问题导致的重复日期
    df = df.sort_values(by='date').drop_duplicates(subset=['date'])
    
    # 5. 设置时间索引 (可选,但推荐)
    # 对于时序分析、特征工程(如 shift(), rolling())以及大部分量化回测框架,使用 DatetimeIndex 是最优解
    df.set_index('date', inplace=True)
    
    # 6. 处理异常缺失值 (可选,这里示范剔除没有收盘价的异常交易日)
    df = df.dropna(subset=['close'])
    
    return df

数据存储

鉴于你在搞 Home Lab 并且有 Minisforum N5 Pro 这样不错的硬件,建议不要每次回测都在线请求,而是建立本地数据库。 简单的本地化方案(保存为 CSV/Excel):

stock_df.to_csv("000001_daily.csv", index=False)

存入数据库: 由于你在用 Docker,可以跑一个 PostgreSQL 或 ClickHouse 容器,通过 sqlalchemy 配合 akshare 实现自动化数据同步

为了后续能训练你的TFT机器学习模型,我们需要一个自动化的同步脚本。这个脚本会做三件事: 1.从Akshare 抓取数据。 2.自动在quant_lab库中创建表。 3.关键:自动将表转换为TimescaleDB的Hypertable(超表),实现极致的查询性能。 在你的Ubuntu VM或本地开发机上运行

SQL脚本

 -- 1. 创建量化专用库
CREATE DATABASE quant_lab;

-- 2. 切换到新库
\c quant_lab

-- 3. 在新库也要开启插件
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
-- 开启压缩,这对于 NAS 存储非常友好,能节省约 90% 空间
ALTER TABLE stock_daily_hists SET (
  timescaledb.compress,
  timescaledb.compress_segmentby = 'symbol'
);

Python脚本:sync_all_stocks.py

import akshare as ak
import pandas as pd
from sqlalchemy import create_engine, text
# 1. 连接到你的新库 quant_lab
DB_URL = "postgresql://postgres:password@ip/quant_lab"
engine = create_engine(DB_URL)
def sync_daily_data(symbol="000001"):
    print(f"正在抓取 {symbol}...")
    # 获取历史日线 (前复权)
    df = ak.stock_zh_a_hist(symbol=symbol, period="daily", adjust="qfq")
    # 字段清洗:对接数据库命名规范
    df = df[['日期', '开盘', '收盘', '最高', '最低', '成交量', '成交额']]
    df.columns = ['trade_date', 'open', 'close', 'high', 'low', 'volume', 'turnover']
    df['symbol'] = symbol
    df['trade_date'] = pd.to_datetime(df['trade_date'])
    # 2. 写入数据库
    # 如果表不存在则创建,如果存在则追加数据
    df.to_sql('stock_daily_hists', engine, if_exists='append', index=False)

def init_hypertable():
    # 3. 将表转为 Hypertable (只需执行一次)
    with engine.connect() as conn:
        conn.execute(text("SELECT create_hypertable('stock_daily_hists', 'trade_date', if_not_exists => TRUE);"))
        conn.commit()
    print("✅ Hypertable 转换完成!")

if __name__ == "__main__":
    # 先运行一次初始化
    init_hypertable()
    # 尝试同步一只股票测试
    sync_daily_data("000001")

结语

从配置环境、调用 Akshare 获取全景数据,再到数据标准化与本地 TimescaleDB 的超表搭建,整个量化研究的数据基座已经初步成型。 数据抓取与入库只是“体力活”,真正的挑战在于如何从这片海量时序数据中提取阿尔法。下一阶段,我们将开始构建滞后特征、技术指标等特征工程,并开始向强大的机器学习模型(如 Temporal Fusion Transformer)输送弹药。 远思为径,码动价值。 量化交易的第一步已经稳稳迈出,期待模型在海量数据中挖掘出令人惊喜的规律!