利用Python获取京沪深历史数据并导入数据库

1、模块说明

akshare:基于 ‌Python 的开源财经数据接口库,旨在为金融研究、量化交易等领域提供 ‌股票、期货、期权、基金、外汇、债券、指数、加密货币 等金融产品的 ‌实时数据、历史行情数据及衍生数据,支持从数据采集、清洗到存储的全流程处理‌

sqlalchemy:Python 中最流行的 ORM(对象关系映射)库SQL 工具包,它允许开发者通过 Python 类和方法操作数据库,而无需直接编写原始 SQL 语句。其核心目标是提供高效、灵活且安全的数据库访问方式。

2、数据库表

CREATE TABLE `stocks_qfq` (
  `id` int primary key auto_increment,
  `trade_date` date DEFAULT NULL COMMENT '交易日',
  `symbol` varchar(10) NOT NULL COMMENT '股票代码',
  `name` varchar(10) NOT NULL COMMENT '公司名称', 
  `px_close_last` decimal(10,2) DEFAULT NULL COMMENT '昨日收盘价',
  `px_open` decimal(10,2) DEFAULT NULL COMMENT '开盘价',
  `px_close` decimal(10,2) DEFAULT NULL COMMENT '收盘价',
  `high` decimal(10,2) DEFAULT NULL COMMENT '当日最高价',
  `low` decimal(10,2) DEFAULT NULL COMMENT '当日最低价',
  `vol` bigint DEFAULT NULL COMMENT '成交量(股)',
  `amt` bigint DEFAULT NULL COMMENT '成交额(元)',
  `amplitude` decimal(5,4) DEFAULT NULL COMMENT '振幅(百分比)',
  `pct_chg` decimal(5,4) DEFAULT NULL COMMENT '涨跌幅(百分比)',
  `chg_amt` decimal(10,2) DEFAULT NULL COMMENT '涨跌额(绝对值)',
  `turnover` decimal(5,4) DEFAULT NULL COMMENT '换手率(百分比)'
);

3、Python代码

import time
from sqlalchemy import create_engine, Table, Column, MetaData, Numeric, Date, String, Integer
from sqlalchemy.dialects.mysql import NUMERIC
import akshare as ak
import pandas as pd
from urllib.parse import quote
from datetime import datetime

# ================== 数据库配置 ==================
DB_USER = "user"
DB_PASSWORD = "123456@mysql"
encoded_password = quote(DB_PASSWORD)  # 自动转义特殊字符(如@转为%40)
DB_HOST = "192.168.10.27"  # 或你的数据库IP
DB_NAME = "stocks"
TABLE_NAME = "stocks_hfq"

# 创建数据库引擎
engine = create_engine(f"mysql+pymysql://{DB_USER}:{encoded_password}@{DB_HOST}/{DB_NAME}")

# ================== 定义表结构(需与数据库实际表一致) ==================
metadata = MetaData()

Stock_daily = Table(
    "stocks_hfq",
    metadata,
    Column("id", Integer),  # 建议改为自增主键:Column("id", Integer, primary_key=True, autoincrement=True)
    Column("trade_date", Date),
    Column("symbol", String(10)),
    Column("name", String(10)),
    Column("px_open", Numeric(10, 2)),
    Column("px_close", Numeric(10, 2)),
    Column("high", Numeric(10, 2)),
    Column("low", Numeric(10, 2)),
    Column("vol", Numeric),
    Column("amt", Numeric(15, 2)),
    Column("amplitude", Numeric(5, 2)),
    Column("pct_chg", Numeric(5, 2)),
    Column("chg_amt", Numeric(10, 2)),
    Column("turnover", Numeric(5, 2))
)

# ================== 获取股票列表 ==================
def get_stock_list():
    """获取沪深京A股代码列表"""
    stock_list = ak.stock_zh_a_spot_em()
    return stock_list[["代码", "名称"]]

# ================== 主逻辑:遍历股票并插入数据 ==================
def insert_stock_daily_data():
    stock_list = get_stock_list()

    i=0
    for idx, row in stock_list.iterrows():
        stock_code = row["代码"]
        stock_name = row["名称"]


        try:
            # 从akshare获取历史数据(假设使用后复权)
            df = ak.stock_zh_a_hist(
                symbol=stock_code, 
                period="daily", 
                adjust="hfq"  # 可选:"qfq"(前复权)或 None(不复权)
            )
            #print(df.head())
            # 添加股票代码和名称列
            #df["symbol"] = stock_code
            df["name"] = stock_name
            df["振幅"]=df["振幅"]/100    #换算为百分比
            df["涨跌幅"]=df["涨跌幅"]/100    #换算为百分比
            df["换手率"]=df["换手率"]/100    #换算为百分比          
            df["昨收"]=df["收盘"] / (1 + df["涨跌幅"])    #换算昨日收盘价

            # 重命名列(映射到表结构)
            df = df.rename(columns={
                "日期": "trade_date",
                "股票代码": "symbol",
                "名称": "name",
                "昨收": "px_close_last",
                "开盘": "px_open",
                "收盘": "px_close",
                "最高": "high",
                "最低": "low",
                "成交量": "vol",
                "成交额": "amt",
                "振幅": "amplitude",
                "涨跌幅": "pct_chg",
                "涨跌额": "chg_amt",
                "换手率": "turnover"
            })

            # 转换日期格式(确保为 datetime.date 类型)
            df["trade_date"] = pd.to_datetime(df["trade_date"]).dt.date

            # 插入数据库(自动匹配列名)
            df.to_sql(
                name=TABLE_NAME,
                con=engine,
                if_exists="append",
                index=False,
                dtype={
                    "trade_date": Date,
                    "symbol": String(10),
                    "name": String(10),
                    "px_open": NUMERIC(10, 2),
                    "px_close": NUMERIC(10, 2),
                    "high": NUMERIC(10, 2),
                    "low": NUMERIC(10, 2),
                    "vol": NUMERIC,
                    "amt": NUMERIC(15, 2),
                    "amplitude": NUMERIC(5, 2),
                    "pct_chg": NUMERIC(5, 2),
                    "chg_amt": NUMERIC(10, 2),
                    "turnover": NUMERIC(5, 2)
                }
            )

            print(f"插入成功: {stock_code} {stock_name}")
            time.sleep(10)
        except Exception as e:
            print(f"错误: {stock_code} {stock_name}", str(e))
            time.sleep(10)   #限制请求频率,避免触发反爬虫机制
if __name__ == "__main__":
    insert_stock_daily_data()

4、补充说明

sqlalchemy中数据类型定义与mysql或其他RDMS不一样,以下是sqlalchemy常用基础数据类型:

from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime, Date, Float, Numeric

class User(Base):
    __tablename__ = "users"

    # 整数类型
    id = Column(Integer, primary_key=True)  

    # 字符串类型(带长度限制)
    name = Column(String(50), nullable=False)  

    # 长文本(无长度限制)
    description = Column(Text)  

    # 布尔类型(映射为数据库的 TINYINT/BOOLEAN)
    is_active = Column(Boolean, default=True)  

    # 日期时间类型
    created_at = Column(DateTime, default=datetime.now)  

    # 日期类型
    birth_date = Column(Date)  

    # 浮点数(近似值)
    price = Column(Float)  

    # 高精度小数(适合金额)
    balance = Column(Numeric(10, 2))  # 总位数 10,小数位 2
posted @ 2025-03-19 16:27  HoraceXie  阅读(379)  评论(0)    收藏  举报