教程

用 ChatGPT Sites 搭一个 A 股情绪看板

ChatGPT Sites 能用一段话生成网页,数据靠浏览器里一个 fetch 拿。免费端点已开放跨域,不用后端、不用 Key,页面直接调。代码见下。

为什么不用后端?因为接口已经允许跨域

浏览器要调别的域名,会先问对方「允不允许」。实测两个免费端点都返回 access-control-allow-origin: *(2026-10-28 验证)⇒ 页面里直接 fetch 就能取到数据,不需要自己搭服务器做代理。

先自己验一下,返回头里要有那一行:

命令行(验证跨域头)
curl -s -D - -o /dev/null \
  -H "Origin: https://example.chatgpt.site" \
  https://api.ashareapi.com/v1/changedist | grep -i access-control

# access-control-allow-origin: *

先定看板要显示什么

一张情绪看板用前三行就够了。全部 96 个端点见端点清单,其中 7 个免费、无需注册。

上涨 / 下跌家数
/v1/changedist
不要
家
涨停 / 跌停家数
/v1/changedist
不要
家
两市成交额
/v1/changedist
不要
亿元(在 data 文本里)
个股最新价
/v1/quote?code=sh600519
不要
元
热搜榜
/v1/hot
不要
—

第一步:把页面描述交给 ChatGPT

新建一个 Site,把下面这段直接贴进去。它决定布局,数据部分下一步再补:

给 ChatGPT 的描述(可直接粘贴)
做一个单页的 A 股情绪看板,要求:
1. 顶部四个卡片:上涨家数、下跌家数、涨停家数、两市成交额
2. 数据从 https://api.ashareapi.com/v1/changedist 取,
   用浏览器里的 fetch 直接调,不要写后端
3. 涨用红色、跌用绿色,深色背景
4. 每 30 秒自动刷新一次

生成后站点地址形如 <站点名>.<你的账号>.chatgpt.site。AI 在生成时并不知道真实字段名,取值逻辑多半对不上,用下一步的代码整段替换即可。

第二步:把数据接进去(完整代码,整段替换)

下面这份是对着真实返回写死的,把 AI 生成的 <script> 整段换掉即可(页面结构也一并给全,方便直接替换整个文件):

HTML + 原生 JS(无依赖,可直接跑)
<!doctype html>
<html lang="zh">
<meta charset="utf-8">
<title>A股情绪看板</title>
<style>
  body{margin:0;padding:24px;background:#0b0b0f;color:#e9e9f2;
       font:14px/1.5 -apple-system,"Segoe UI",sans-serif}
  .row{display:flex;gap:12px;flex-wrap:wrap}
  .card{min-width:120px;padding:14px 18px;border-radius:10px;
        background:#16161d;border:1px solid #2a2a36}
  .k{font-size:12px;color:#8a8aa0}
  .v{margin-top:4px;font-size:26px;font-weight:600}
  .up{color:#ff4d4f}.down{color:#00c853}
  #ts{margin-top:16px;font-size:12px;color:#8a8aa0}
</style>
<div class="row" id="cards"></div>
<div id="ts"></div>

<script>
var API = "https://api.ashareapi.com/v1";

function card(k, v, cls) {
  return '<div class="card"><div class="k">' + k + '</div>' +
         '<div class="v ' + (cls || "") + '">' + v + '</div></div>';
}

async function loadMood() {
  var r = await fetch(API + "/changedist");
  var b = await r.json();
  if (!b.ok) throw new Error("changedist 返回失败");

  var s = (b.structured && b.structured[0]) || {};        // key 是中文
  var m = String(b.data).match(/两市成交额:([\d.]+)亿/);   // 成交额只在 data 文本里

  document.getElementById("cards").innerHTML =
    card("上涨", s["上涨"], "up") +
    card("下跌", s["下跌"], "down") +
    card("涨停", s["涨停"], "up") +
    card("跌停", s["跌停"], "down") +
    card("上涨占比", s["上涨占比"]) +
    card("两市成交额", m ? m[1] + " 亿" : "—");

  document.getElementById("ts").textContent =
    "更新于 " + new Date().toLocaleTimeString();
}

loadMood();
setInterval(loadMood, 30000);   // 30 秒;别低于 12 秒
</script>
</html>

⚠️ 三个真实踩坑

  • 字段名是中文 —— structured[0] 的 key 就是 "上涨" "下跌" "涨停",不是 up / down。AI 生成的代码几乎一定猜成英文,务必对一遍真实返回。
  • 上涨占比 是 "20%" 这样的字符串,不是数字 20 —— 带百分号。要参与计算先 parseFloat(),直接丢进图表库会变成 NaN。
  • 成交额不在 structured 里 —— structured 只装了第一张表(涨跌家数);成交额在 data 这段 Markdown 文本里,只能正则提取:b.data.match(/两市成交额:([\d.]+)亿/)。

第三步:想加个股,就再调一个端点

JavaScript(接在同一个 script 里)
async function loadStock(code) {
  var r = await fetch(API + "/quote?code=" + code);
  var b = await r.json();
  if (!b.ok || !b.data || !b.data.length) return null;

  var bar = b.data[0];          // 按日期倒序,data[0] 是最新一根
  return {
    date: bar.date,
    last: Number(bar.last),
    high: Number(bar.high),
    low: Number(bar.low),
    volume: Number(bar.volume),     // 手
    amount: Number(bar.amount),     // 元
    turnover: Number(bar.turnover)  // %
  };
}

loadStock("sh600519").then(console.log);
date
交易日
—
2026-10-29
last
最新价
元
1344.93
high / low
当日最高 / 最低
元
1349.99 / 1330.01
volume
成交量
手
8251
amount
成交额
元
1105305033
turnover
换手率
%
0.07

volume 是手(1 手 = 100 股)、amount 是元 —— 这两个单位是最常见的错误来源,建议在代码里写注释。自查办法:last × volume × 100 ≈ amount,对得上说明单位没读错(示例:1344.93 × 8251 × 100 ≈ 11.1 亿,与 amount 同一量级)。表内数值随行情变化,单位是固定的。

看板跑起来之后要注意的三件事

  • 匿名限流 5 次/分钟 —— 自动刷新间隔别小于 12 秒,否则会拿到 429。上面代码用的 30 秒是安全的。
  • 别在前端硬编码付费 Key —— 页面源码是公开的,Key 会被抄走。需要更高频率就在服务端取数,Key 只放在服务端。
  • 看板只描述状态,不预测方向 —— 上涨家数远多于下跌家数,只说明「今天普涨」,不等于「明天该买」。情绪读数要和历史均值、量能一起看。

这套东西不适合做什么

  • 不适合秒级刷新 —— 免费额度 5 次/分,做高频轮询只会被限流。要高频请用 Key 并在服务端聚合。
  • 不适合直接做成多用户产品 —— 所有访客共用你这一层匿名额度,人一多就互相挤。
  • 不适合当作交易信号 —— 本文只讲怎么取数和展示,不构成投资建议。

常见问题

ChatGPT 生成的页面调接口会被跨域拦住吗?

不会。 实测免费端点返回 access-control-allow-origin: *(2026-10-28 验证),浏览器里直接 fetch 即可。自己验一行命令就能确认,见第一步。

要注册或申请 Key 吗?

不用。 changedist / quote / hot 都在 7 个免费端点里 —— 无需注册、无需 Key,匿名可调(5 次/分钟)。

做好的页面能分享给别人看吗?

站点地址可以分享,形如 <站点名>.<你的账号>.chatgpt.site。能否匿名访问取决于你在 ChatGPT Sites 里的站点设置 —— 建议用无痕窗口打开验一次:若提示登录,就是站点还没开放。

为什么我的涨跌家数和别的平台不一样?

先核对口径:/v1/changedist 是当期(今天);而 /v1/market-overview?type=updown 是 T-1(返回里会标数据日期)。另外各平台对统计范围(是否含 ST / 北交所 / 停牌)的处理可能不同。

能加 K 线图吗?

可以。/v1/kline?code=sh600519&count=60 取日线(免费、前复权),交给任意前端图表库画即可。字段与参数见端点清单里的 kline。

最后更新: 2026-10-28

代码与字段取自线上真实返回(2026-10-29 复核):/v1/changedist 的 structured[0] key 为中文(上涨 / 下跌 / 涨停 / 跌停 / 上涨占比 / 停牌 / 平盘),上涨占比 为带百分号字符串,两市成交额只在 data 文本中;/v1/quote 的 data 按日期倒序,volume 单位为手、amount 单位为元;两个端点均返回 access-control-allow-origin: *。文中数值为示例,随行情变化;字段与限流以端点文档为准。