用 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 个免费、无需注册。
| 读数 | 端点 | 要 Key 吗 | 单位 |
|---|---|---|---|
| 上涨 / 下跌家数 | /v1/changedist | 不要 | 家 |
| 涨停 / 跌停家数 | /v1/changedist | 不要 | 家 |
| 两市成交额 | /v1/changedist | 不要 | 亿元(在 data 文本里) |
| 个股最新价 | /v1/quote?code=sh600519 | 不要 | 元 |
| 热搜榜 | /v1/hot | 不要 | — |
/v1/changedist/v1/changedist/v1/changedistdata 文本里)/v1/quote?code=sh600519/v1/hot第一步:把页面描述交给 ChatGPT
新建一个 Site,把下面这段直接贴进去。它决定布局,数据部分下一步再补:
做一个单页的 A 股情绪看板,要求:
1. 顶部四个卡片:上涨家数、下跌家数、涨停家数、两市成交额
2. 数据从 https://api.ashareapi.com/v1/changedist 取,
用浏览器里的 fetch 直接调,不要写后端
3. 涨用红色、跌用绿色,深色背景
4. 每 30 秒自动刷新一次生成后站点地址形如 <站点名>.<你的账号>.chatgpt.site。AI 在生成时并不知道真实字段名,取值逻辑多半对不上,用下一步的代码整段替换即可。
第二步:把数据接进去(完整代码,整段替换)
下面这份是对着真实返回写死的,把 AI 生成的 <script> 整段换掉即可(页面结构也一并给全,方便直接替换整个文件):
<!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.]+)亿/)。
第三步:想加个股,就再调一个端点
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);| 字段 | 含义 | 单位 | 示例值(sh600519 · 2026-10-29 盘中) |
|---|---|---|---|
date | 交易日 | — | 2026-10-29 |
last | 最新价 | 元 | 1344.93 |
high / low | 当日最高 / 最低 | 元 | 1349.99 / 1330.01 |
volume | 成交量 | 手 | 8251 |
amount | 成交额 | 元 | 1105305033 |
turnover | 换手率 | % | 0.07 |
datelasthigh / lowvolumeamountturnovervolume 是手(1 手 = 100 股)、amount 是元 —— 这两个单位是最常见的错误来源,建议在代码里写注释。自查办法:last × volume × 100 ≈ amount,对得上说明单位没读错(示例:1344.93 × 8251 × 100 ≈ 11.1 亿,与 amount 同一量级)。表内数值随行情变化,单位是固定的。
看板跑起来之后要注意的三件事
- 匿名限流 5 次/分钟 —— 自动刷新间隔别小于 12 秒,否则会拿到 429。上面代码用的 30 秒是安全的。
- 别在前端硬编码付费 Key —— 页面源码是公开的,Key 会被抄走。需要更高频率就在服务端取数,Key 只放在服务端。
- 看板只描述状态,不预测方向 —— 上涨家数远多于下跌家数,只说明「今天普涨」,不等于「明天该买」。情绪读数要和历史均值、量能一起看。
这套东西不适合做什么
- 不适合秒级刷新 —— 免费额度 5 次/分,做高频轮询只会被限流。要高频请用 Key 并在服务端聚合。
- 不适合直接做成多用户产品 —— 所有访客共用你这一层匿名额度,人一多就互相挤。
- 不适合当作交易信号 —— 本文只讲怎么取数和展示,不构成投资建议。
常见问题
不会。 实测免费端点返回 access-control-allow-origin: *(2026-10-28 验证),浏览器里直接 fetch 即可。自己验一行命令就能确认,见第一步。
不用。 changedist / quote / hot 都在 7 个免费端点里 —— 无需注册、无需 Key,匿名可调(5 次/分钟)。
站点地址可以分享,形如 <站点名>.<你的账号>.chatgpt.site。能否匿名访问取决于你在 ChatGPT Sites 里的站点设置 —— 建议用无痕窗口打开验一次:若提示登录,就是站点还没开放。
先核对口径:/v1/changedist 是当期(今天);而 /v1/market-overview?type=updown 是 T-1(返回里会标数据日期)。另外各平台对统计范围(是否含 ST / 北交所 / 停牌)的处理可能不同。
可以。/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: *。文中数值为示例,随行情变化;字段与限流以端点文档为准。