如果你写过股票相关的小程序、量化脚本或者行情看板,大概率你接触过这个地址:hq.sinajs.cn。这就是被无数教程反复提及的新浪财经股票数据接口。它免费、无需注册、一个 URL 就能拿到实时报价,是很多人第一次接触行情数据的起点。

但很多读者不清楚的是:新浪官方从来没有对外发布过这个API接口

它其实和我们早前提到过的Yahoo Finance一样,都是依靠群众的力量,一步步被破解出来的。没有官方文档,没有官方客服,随时可能改格式、加限制甚至停更。用它做个人 demo 没问题,一旦要放到线上产品、交易终端或者交易所系统里,几乎必然踩坑。

作为 Infoway,我们为海内外多家交易所和量化团队提供行情数据,接到过大量从新浪接口迁过来的需求,于是就有了这篇文章。我们将详细讲解新浪财经 API ,如果你之前没有了解过它,这篇教程能帮助你快速上手,如果你正在寻找新浪财经API的替代品,我们也会给出如何平滑迁移到 Infoway的方案。

一、新浪财经 API 到底是什么

正如前文所述,新浪财经并没有像专业数据商那样发布一套 RESTful API,它真正被大家当接口用的,其实是新浪股票页面背后的数据源地址。当年很多爬虫、看板都是直接读这个地址,久而久之就成了事实上的新浪财经 API

它主要包含三类数据:

数据类型地址(域名)返回格式
实时行情 + 五档盘口hq.sinajs.cnJS 变量赋值字符串
历史 K 线money.finance.sina.com.cnJSON(伪 JSON)
分时数据money.finance.sina.com.cnJSON

覆盖市场包括 A 股、港股、美股,其中 A 股的实时买卖五档是它最受欢迎的部分。下面逐个拆解。

1.1 实时行情接口

最核心的接口,用法是在 list= 后面拼股票代码:

Python
http://hq.sinajs.cn/list=sh601006

代码前缀规则:

  • 上交所股票加 sh,如大秦铁路 sh601006
  • 深交所股票加 sz,如平安银行 sz000001
  • s_ 前缀(如 s_sh601006)返回简略数据,只有价格、涨跌、成交量几个字段;不加则返回详细数据,包含五档盘口。

批量查询直接用逗号拼接多个代码:

Python
http://hq.sinajs.cn/list=sh601006,sz000001,sh600519

接口返回一段以 var hq_str_股票代码= 开头的文本,例如:

Python
var hq_str_sh601006="大秦铁路,27.55,27.25,26.91,27.55,26.20,26.91,26.92,...";

1.2 返回字段下标全解析

这是新浪接口最劝退的地方😢,所有数据挤在一个逗号分隔的字符串里,没有任何字段名,全靠下标记忆。以详细数据为例,各下标含义如下(A 股):

下标含义下标含义
0股票名称1今日开盘价
2昨日收盘价3当前价格
4今日最高价5今日最低价
6竞买价(买一)7竞卖价(卖一)
8成交量(股,除以 100 得”手”)9成交额(元,除以 10000 得”万元”)
10 / 11买一量 / 买一价12 / 13买二量 / 买二价
……买三~买五(14~19)20 / 21卖一量 / 卖一价
……卖二~卖五(22~29)30日期
31时间32停牌标记等

有两个几乎人人踩过的换算坑:

  • 第 8 项成交量是股,A 股以 100 股为一手,通常要除以 100
  • 第 9 项成交额单位是元,为了直观一般除以 10000 换算成万元

1.3 历史 K 线接口

新浪的历史 K 线走的是另一个域名,返回相对规整的 JSON:

Python
http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol=sh000001&scale=60&ma=5&datalen=1023

参数含义:symbol 股票代码、scale 周期(分钟,如 5/15/30/60,日线用 240)、ma 均线周期、datalen 返回条数。

1.4 Referer 防盗链

这是新浪接口最大的一个版本断层。2022 年下半年起,新浪对 hq.sinajs.cn 增加了 Referer 校验:直接在浏览器里打开 http://hq.sinajs.cn/list=sh600519,会返回 Forbidden(403)。

解决办法是在请求头里带上 Referer

Python
import requests

headers = {
    "Referer": "https://finance.sina.com.cn",  # 关键:不带会返回 403
    "User-Agent": "Mozilla/5.0",
}
url = "http://hq.sinajs.cn/list=sh601006,sz000001"
resp = requests.get(url, headers=headers)

# 关键第二坑:返回内容是 GB2312/GBK 编码,直接读会中文乱码
resp.encoding = "gbk"
print(resp.text)

注意上面代码里的第二个坑:编码。新浪接口返回的是 GB2312/GBK 编码,如果不手动指定 encoding="gbk",股票名称会变成乱码。

1.5 解析示例

把上面的知识点串起来,一个能用的新浪实时行情解析脚本大致长这样:

Python
import requests

def fetch_sina(codes):
    """codes 形如 ['sh601006', 'sz000001']"""
    url = "http://hq.sinajs.cn/list=" + ",".join(codes)
    headers = {"Referer": "https://finance.sina.com.cn", "User-Agent": "Mozilla/5.0"}
    resp = requests.get(url, headers=headers)
    resp.encoding = "gbk"

    result = {}
    for line in resp.text.strip().split(";"):
        line = line.strip()
        if not line or "=" not in line:
            continue
        var, payload = line.split("=", 1)
        code = var.replace("var hq_str_", "")
        fields = payload.strip('"').split(",")
        if len(fields) < 32:      # 简略数据或停牌,字段不全,直接跳过
            continue
        result[code] = {
            "name": fields[0],
            "open": float(fields[1]),
            "prev_close": float(fields[2]),
            "price": float(fields[3]),
            "high": float(fields[4]),
            "low": float(fields[5]),
            "volume_hand": float(fields[8]) / 100,       # 股 → 手
            "amount_wan": float(fields[9]) / 10000,      # 元 → 万元
            "bid1_price": float(fields[11]),
            "ask1_price": float(fields[21]),
            "date": fields[30],
            "time": fields[31],
        }
    return result

print(fetch_sina(["sh601006", "sz000001"]))

到这里,你已经掌握了网上 90% 教程会讲的内容。但真正决定能不能上生产的,是接下来这部分。

二、新浪财经 API 到底靠不靠谱?

说实话,新浪接口用来学习、做个人 demo 完全够用。但当你要把它塞进一个需要长期稳定运行的系统时,很多你未曾设想过问题会一个接一个冒出来。这也是绝大多数教程避而不谈的部分。

2.1 稳定性

由于这个接口从来没有获得过官方的承认,新浪自然不会承诺它的稳定性。字段顺序、Referer 规则、编码方式全靠社区口口相传,2022 年那次防盗链改动就是典型,一夜之间大量脚本集体 403,没有任何公告,更没有提前通知,说变就变。你的系统建立在一个对方随时可以推翻的地基上。

2.2 只能轮询,没有实时推送

新浪接口是纯 HTTP 拉取,想要实时数据只能不停轮询。这带来两个后果:一是延迟不可控,你的刷新频率就是你的延迟下限;二是极易触发限流,高频轮询同一个 IP,很快就会被风控封禁一段时间。对于逐笔成交、盘口异动这类需要毫秒级响应的场景,轮询架构从原理上就做不到。

2.3 维护成本高

前面那张字段下标表已经说明了问题:数据没有字段名、类型全是字符串、还得手动做单位换算和编码转换。代码里到处是 fields[21] 这样的魔法下标,一旦新浪调整字段顺序,排查起来非常痛苦。

2.4 覆盖与深度有限

新浪在 A 股实时行情上表现不错,但历史数据深度、复权因子、基本面财报、以及港股美股的字段完整度都比较有限,多市场统一接入更是无从谈起。

三、新浪财经 API vs Infoway:一张表看懂差异

下面把两者放在同一维度对比。需要说明:我们无意贬低新浪前辈(Respect ❤️),时至今日,它在免费快速上手这件事上依然是最好的选择之一,但两者的定位本就不同,一个是页面数据源,一个是面向生产的专业行情 API。

对比维度新浪财经 APIInfoway API
定位网页数据源(非正式 API)面向生产的专业行情 API
官方文档 / SLA无文档、无 SLA完整文档,99.96% SLA
数据格式逗号分隔字符串,靠下标标准化 JSON,带字段名
接入方式仅 HTTP 轮询REST + WebSocket 推送
实时性取决于轮询频率,易被限流平均 60–150ms 低延迟推送
编码GB2312/GBK,需手动转码UTF-8,开箱即用
防盗链 / 反爬需伪造 Referer,随时可能加码标准 API Key 鉴权
盘口五档五档 / 十档
市场覆盖A 股 / 港股 / 美股(字段不一)A股、港股、美股、日股、印度、韩股、加密货币、外汇、期货、大宗商品等 30,000+ 品种
历史 K 线有,深度有限1 分钟~年线,可翻页取历史
复权 / 基本面 / 财报基本没有复权因子、三大报表、估值指标
稳定性随时变格式、无保障面向交易所的生产级稳定性

如果你在做玩具,用新浪,如果你在做产品,用一套真正的 API。

四、如何从新浪财经接口迁移到 Infoway API

很多人担心换数据源要大改代码。其实迁移的核心只有两件事:换 symbol 格式换字段读取方式。Infoway 的返回是带字段名的标准 JSON,读起来比数下标舒服得多。

4.1 symbol 格式对照

新浪用前缀区分市场,Infoway 用后缀,规则更统一:

市场新浪格式Infoway 格式
A 股·上交所sh600519600519.SH
A 股·深交所sz000001000001.SZ
港股hk0070000700.HK
美股gb_aaplAAPL.US

4.2 实时成交明细(对应新浪的实时行情)

新浪那段字符串里的价格、成交量、成交额,在 Infoway 里对应 /stock/batch_trade 这个接口,一次最多查 100 个代码:

Python
import requests

API_KEY = "YOUR_API_KEY"          # 官网注册即送 7 天试用
BASE = "https://data.infoway.io"

def infoway_trade(codes):
    url = f"{BASE}/stock/batch_trade/{','.join(codes)}"
    resp = requests.get(url, headers={"apiKey": API_KEY})
    return resp.json()["data"]

for item in infoway_trade(["600519.SH", "000001.SZ"]):
    print(item["s"], "价格:", item["p"], "成交量:", item["v"], "成交额:", item["vw"])

返回是干净的 JSON,字段一目了然:

Python
{
  "s": "600519.SH",
  "t": 1750177346523,
  "p": "1685.20",
  "v": "300",
  "vw": "505560.00",
  "td": 1
}

新浪字段下标 → Infoway 字段迁移对照表(把老代码搬过来时直接对照):

含义新浪下标Infoway 字段说明
标的代码变量名解析s直接给出
最新价fields[3]p无需换算
成交量fields[8](需 /100)v单位已规整
成交额fields[9](需 /10000)vw直接可用
成交时间fields[30]+[31] 拼接t毫秒时间戳,无需拼字符串
主动买卖方向td0 默认 / 1 买 / 2 卖,新浪没有

4.3 五档盘口(对应新浪的买卖五档)

新浪把买一到卖五塞在下标 10–29 里,Infoway 用 /stock/batch_depth 直接返回结构化的买卖盘数组:

Python
def infoway_depth(codes):
    url = f"{BASE}/stock/batch_depth/{','.join(codes)}"
    resp = requests.get(url, headers={"apiKey": API_KEY})
    return resp.json()["data"]

d = infoway_depth(["000001.SZ"])[0]
# a = 卖盘, b = 买盘;每个都是 [价格数组, 数量数组]
ask_prices, ask_vols = d["a"]
bid_prices, bid_vols = d["b"]
print("卖一:", ask_prices[0], ask_vols[0])
print("买一:", bid_prices[0], bid_vols[0])

不用再记 fields[11] 是买一价、fields[21] 是卖一价,买盘 b、卖盘 a、价格和数量分开成数组,第 0 档就是买一/卖一。

4.4 历史 K 线(对应新浪的 getKLineData)

新浪的 K 线接口只能拉近端有限的数据,Infoway 的 /stock/v2/batch_kline 支持从 1 分钟到年线共 12 种周期,单个产品一次可取 500 根,还能按秒级时间戳向前翻页取历史:

Python
def infoway_kline(codes, kline_type=8, num=100):
    # kline_type: 1=1分 2=5分 3=15分 4=30分 5=1时 8=日 9=周 10=月
    url = f"{BASE}/stock/v2/batch_kline"
    body = {"klineType": kline_type, "klineNum": num, "codes": ",".join(codes)}
    resp = requests.post(url, json=body, headers={"apiKey": API_KEY})
    return resp.json()["data"]

for row in infoway_kline(["600519.SH"], kline_type=8, num=30)[0]["respList"]:
    print(row["t"], "", row["o"], "", row["h"], "", row["l"], "", row["c"])

小提示:多个产品一起查 K 线时,每个产品只返回最近 2 根;要取某只票的长历史,请单产品查询并配合 timestamp 参数向前翻页。

五、WebSocket 实时推送

前面说过,新浪接口只能轮询,这是它和生产级 API 最本质的差距。Infoway 提供 WebSocket 长连接,服务端主动推送成交、盘口、K 线,延迟从轮询间隔,直接降到毫秒级。下面是一个可直接跑的精简 Python 客户端:

Python
import asyncio, json, uuid, websockets

API_KEY = "YOUR_API_KEY"
WS_URL = f"wss://data.infoway.io/ws?business=stock&apikey={API_KEY}"

def trace():
    return str(uuid.uuid4())

async def main():
    async with websockets.connect(WS_URL) as ws:
        # 订阅实时成交明细(协议号 10000)
        await ws.send(json.dumps({
            "code": 10000, "trace": trace(),
            "data": {"codes": "600519.SH,000001.SZ"}
        }))
        # 订阅五档盘口(协议号 10003)
        await ws.send(json.dumps({
            "code": 10003, "trace": trace(),
            "data": {"codes": "600519.SH"}
        }))

        async def heartbeat():          # 每 30 秒心跳,超时会被断开
            while True:
                await asyncio.sleep(30)
                await ws.send(json.dumps({"code": 10010, "trace": trace()}))

        asyncio.create_task(heartbeat())
        async for msg in ws:
            data = json.loads(msg)
            if data.get("code") == 10002:      # 成交推送
                print("成交:", data["data"])
            elif data.get("code") == 10005:    # 盘口推送
                print("盘口:", data["data"])

asyncio.run(main())

几个生产环境要点:

订阅请求码 +2 就是对应的推送码(10000→10002 成交、10003→10005 盘口、10006→10008 K 线)

心跳必须保持(30 秒一次),否则会被判定超时断开

断线重连后必须重新发送订阅。股票、加密货币、外汇/期货分别是 business=stock/crypto/common 三个通道,同时订阅只算一个连接。

六、如何选择

结合我们服务大量客户的经验,给出比较中肯的建议:

  • 个人学习 / 一次性脚本 / 课程作业:新浪财经 API 足够了,免费、零门槛,本文第一部分够你用。
  • 量化研究 / 策略回测:如果只需要 A 股日线历史,新浪 + 一点清洗能凑合;但只要涉及分钟级、多市场、复权或财报数据,用 Infoway 会省掉大量爬虫维护成本。
  • 实盘交易 / 高频策略:必须用 WebSocket 推送,轮询接口从原理上就不满足延迟要求,选 Infoway
  • 交易所 / 对外产品:这个场景就很明显了,抓取新浪不是好不好用的问题,而是能不能用的问题,Infoway是更好的选择

我们提供 7 天免费试用(官网注册即得),试用期内可以查询全部市场数据,你完全可以先用上面的代码把新浪那部分逻辑平移过来,跑通了再决定。

常见问题(FAQ)

新浪财经 API 为什么突然返回 403 Forbidden?
2022 年下半年起新浪对 hq.sinajs.cn 增加了 Referer 校验,请求头里必须带上 Referer: https://finance.sina.com.cn,否则一律 403。直接在浏览器地址栏打开也会 403,这是正常现象。

新浪接口返回的中文是乱码怎么办?
接口返回的是 GB2312/GBK 编码。用 Python 时手动设置 resp.encoding = "gbk" 再读取;其他语言同理,按 GBK 解码即可。

从新浪迁移到 Infoway,代码改动大吗?
主要改两处:一是 symbol 格式(sh600519600519.SH),二是把”按下标读字符串”改成”按字段名读 JSON”。本文第四章的迁移对照表可以直接照着改,通常半天就能完成平移。

Infoway 支持哪些新浪没有的能力?
最关键的是 WebSocket 实时推送(新浪只能轮询)、标准化 JSON、多市场统一接入(A股/港股/美股/日股/印股/韩股/加密/外汇/期货等)、复权因子与财报基本面数据。

Infoway 有免费额度可以先试吗?
有。官网注册即自动获得 7 天试用会员,试用期内可查询所有市场数据,REST 每分钟 60 次、WebSocket 可订阅 10 个产品,足够完成完整的迁移验证。