Files
MoFin/venv/lib/python3.12/site-packages/akshare/fund/fund_etf_sina.py
T
知微 fa45d8aa5f fix: 小果地址统一node122(兼容LAN+EasyTier)
- health_checklist.json: 192.168.1.122→node122
- ocr_client.py: docstring IP→node122
- docs/market-data-requirements.md: IP→node122
- 所有API调用通过ProxyHandler({})绕过系统代理
  Privoxy对node122:18003返回500,直连正常
2026-06-30 02:56:35 +08:00

206 lines
6.9 KiB
Python

#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2025/11/10 15:30
Desc: 新浪财经-基金行情
https://vip.stock.finance.sina.com.cn/fund_center/index.html#jjhqetf
"""
import pandas as pd
import py_mini_racer
import requests
from akshare.stock.cons import hk_js_decode
from akshare.utils import demjson
def fund_etf_category_sina(symbol: str = "LOF基金") -> pd.DataFrame:
"""
新浪财经-基金列表
https://vip.stock.finance.sina.com.cn/fund_center/index.html#jjhqetf
:param symbol: choice of {"封闭式基金", "ETF基金", "LOF基金"}
:type symbol: str
:return: 指定 symbol 的基金列表
:rtype: pandas.DataFrame
"""
fund_map = {
"封闭式基金": "close_fund",
"ETF基金": "etf_hq_fund",
"LOF基金": "lof_hq_fund",
}
url = (
"https://vip.stock.finance.sina.com.cn/quotes_service/api/jsonp.php/"
"IO.XSRV2.CallbackList['da_yPT46_Ll7K6WD']/Market_Center.getHQNodeDataSimple"
)
params = {
"page": "1",
"num": "5000",
"sort": "symbol",
"asc": "0",
"node": fund_map[symbol],
"[object HTMLDivElement]": "qvvne",
}
r = requests.get(url, params=params)
data_text = r.text
data_json = demjson.decode(data_text[data_text.find("([") + 1 : -2])
temp_df = pd.DataFrame(data_json)
if symbol == "封闭式基金":
temp_df.columns = [
"代码",
"名称",
"最新价",
"涨跌额",
"涨跌幅",
"买入",
"卖出",
"昨收",
"今开",
"最高",
"最低",
"成交量",
"成交额",
"_",
"_",
]
else:
temp_df.columns = [
"代码",
"名称",
"最新价",
"涨跌额",
"涨跌幅",
"买入",
"卖出",
"昨收",
"今开",
"最高",
"最低",
"成交量",
"成交额",
"_",
"_",
"_",
"_",
]
temp_df = temp_df[
[
"代码",
"名称",
"最新价",
"涨跌额",
"涨跌幅",
"买入",
"卖出",
"昨收",
"今开",
"最高",
"最低",
"成交量",
"成交额",
]
]
temp_df["最新价"] = pd.to_numeric(temp_df["最新价"], errors="coerce")
temp_df["涨跌额"] = pd.to_numeric(temp_df["涨跌额"], errors="coerce")
temp_df["涨跌幅"] = pd.to_numeric(temp_df["涨跌幅"], errors="coerce")
temp_df["买入"] = pd.to_numeric(temp_df["买入"], errors="coerce")
temp_df["卖出"] = pd.to_numeric(temp_df["卖出"], errors="coerce")
temp_df["昨收"] = pd.to_numeric(temp_df["昨收"], errors="coerce")
temp_df["今开"] = pd.to_numeric(temp_df["今开"], errors="coerce")
temp_df["最高"] = pd.to_numeric(temp_df["最高"], errors="coerce")
temp_df["最低"] = pd.to_numeric(temp_df["最低"], errors="coerce")
temp_df["成交量"] = pd.to_numeric(temp_df["成交量"], errors="coerce")
temp_df["成交额"] = pd.to_numeric(temp_df["成交额"], errors="coerce")
return temp_df
def fund_etf_hist_sina(symbol: str = "sh510050") -> pd.DataFrame:
"""
新浪财经-基金-ETF 基金-日行情数据
https://finance.sina.com.cn/fund/quotes/159996/bc.shtml
:param symbol: 基金名称, 可以通过 ak.fund_etf_category_sina() 函数获取
:type symbol: str
:return: 日行情数据
:rtype: pandas.DataFrame
"""
url = (
f"https://finance.sina.com.cn/realstock/company/{symbol}/hisdata_klc2/klc_kl.js"
)
r = requests.get(url)
js_code = py_mini_racer.MiniRacer()
js_code.eval(hk_js_decode)
dict_list = js_code.call(
"d", r.text.split("=")[1].split(";")[0].replace('"', "")
) # 执行js解密代码
temp_df = pd.DataFrame(dict_list)
if temp_df.empty: # 处理获取数据为空的问题
return pd.DataFrame()
temp_df["date"] = pd.to_datetime(temp_df["date"], errors="coerce").dt.tz_localize(
None
)
temp_df["open"] = pd.to_numeric(temp_df["open"], errors="coerce")
temp_df["high"] = pd.to_numeric(temp_df["high"], errors="coerce")
temp_df["low"] = pd.to_numeric(temp_df["low"], errors="coerce")
temp_df["close"] = pd.to_numeric(temp_df["close"], errors="coerce")
temp_df["volume"] = pd.to_numeric(temp_df["volume"], errors="coerce")
# 转换日期列为日期类型
temp_df["date"] = temp_df["date"].dt.date
temp_df = temp_df.sort_values(by="date", ascending=True)
return temp_df
def fund_etf_dividend_sina(symbol: str = "sh510050") -> pd.DataFrame:
"""
新浪财经-基金-ETF 基金-累计分红
https://finance.sina.com.cn/fund/quotes/510050/bc.shtml
:param symbol: 基金名称, 可以通过 ak.fund_etf_category_sina() 函数获取
:type symbol: str
:return: 累计分红
:rtype: pandas.DataFrame
"""
# 构建复权数据URL
factor_url = f"https://finance.sina.com.cn/realstock/company/{symbol}/hfq.js"
r = requests.get(factor_url)
text = r.text
if text.startswith("var"):
json_str = text.split("=")[1].strip().rsplit("}", maxsplit=1)[0].strip()
data = eval(json_str + "}") # 这里使用eval而不是json.loads因为数据格式特殊
if isinstance(data, dict) and "data" in data:
df = pd.DataFrame(data["data"])
# 重命名列
df.columns = ["date", "f", "s", "u"] if len(df.columns) == 4 else df.columns
# 移除1900-01-01的数据
df = df[df["date"] != "1900-01-01"]
# 转换日期
df["date"] = pd.to_datetime(df["date"])
# 转换数值类型
df[["f", "s", "u"]] = df[["f", "s", "u"]].astype(float)
# 按日期排序
df = df.sort_values(by="date", ascending=True, ignore_index=True)
temp_df = df[["date", "u"]].copy()
temp_df.columns = ["日期", "累计分红"]
temp_df["日期"] = pd.to_datetime(temp_df["日期"], errors="coerce").dt.date
return temp_df
else:
return pd.DataFrame()
else:
return pd.DataFrame()
if __name__ == "__main__":
fund_etf_category_sina_df = fund_etf_category_sina(symbol="封闭式基金")
print(fund_etf_category_sina_df)
fund_etf_category_sina_df = fund_etf_category_sina(symbol="ETF基金")
print(fund_etf_category_sina_df)
fund_etf_category_sina_df = fund_etf_category_sina(symbol="LOF基金")
print(fund_etf_category_sina_df)
fund_etf_hist_sina_df = fund_etf_hist_sina(symbol="sh510050")
print(fund_etf_hist_sina_df)
fund_etf_dividend_sina_df = fund_etf_dividend_sina(symbol="sh510050")
print(fund_etf_dividend_sina_df)