js实时获取股票数据,如何实现跨域请求与数据解析?
摘要:
核心挑战:数据源最重要的一点是:你需要一个可靠的数据源,股票数据由专业的金融数据公司提供,国际: Yahoo Finance, Alpha Vantage, IEX Cloud,... 核心挑战:数据源
最重要的一点是:你需要一个可靠的数据源,股票数据由专业的金融数据公司提供,
- 国际: Yahoo Finance, Alpha Vantage, IEX Cloud, Polygon.io, Finnhub.io
- 国内: 新浪财经、腾讯财经、东方财富、同花顺、AKShare (开源项目) 等
这些数据源通常会提供 免费 和 付费 两种 API,免费版通常有请求频率限制(例如每分钟5次)和数据延迟(例如15分钟延迟),而付费版则提供更高频率、更低延迟甚至实时的数据。
注意: 直接从网页上抓取数据(俗称“爬虫”)虽然可行,但非常不稳定,网站结构一变你的代码就失效,且可能违反网站的使用条款。强烈推荐使用官方或第三方提供的 API。
轮询 - 最常用、最简单的实现方式
这是最直接的方法,你的前端代码会定期(例如每5秒)向后端服务器或直接向数据源API发送一个请求,获取最新的股票数据,然后更新到页面上。
工作流程:
- 页面加载时,第一次获取数据。
- 设置一个定时器(
setInterval)。 - 定时器每隔一段时间触发,再次发起请求获取新数据。
- 拿到新数据后,更新DOM(页面显示)。
代码示例 (使用 fetch 和 Alpha Vantage API)
准备工作:
- 注册一个 Alpha Vantage 账号,获取你的免费 API Key。
- 在你的HTML中创建一个显示区域。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">Real-time Stock Price</title>
<style>
body { font-family: sans-serif; text-align: center; margin-top: 50px; }
#stock-container { font-size: 2em; }
.price { font-weight: bold; color: #333; }
.change { font-size: 0.8em; }
</style>
</head>
<body>
<h1>实时股票行情 (示例: AAPL)</h1>
<div id="stock-container">
<div>名称: <span id="name">--</span></div>
<div>当前价格: <span id="price" class="price">--</span></div>
<div>变化: <span id="change" class="change">--</span></div>
</div>
<script src="app.js"></script>
</body>
</html>
JavaScript 代码 (app.js)
// --- 配置 ---
const API_KEY = 'YOUR_API_KEY'; // 替换成你的 Alpha Vantage API Key
const SYMBOL = 'AAPL'; // 苹果公司股票代码
const INTERVAL = 5000; // 每5秒更新一次 (5000毫秒)
const API_URL = `https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${SYMBOL}&apikey=${API_KEY}`;
// --- DOM 元素 ---
const nameElement = document.getElementById('name');
const priceElement = document.getElementById('price');
const changeElement = document.getElementById('change');
/**
* 从API获取股票数据并更新页面
*/
async function fetchAndUpdateStockData() {
try {
const response = await fetch(API_URL);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// Alpha Vantage 的 GLOBAL_QUOTE 数据结构
const quote = data['Global Quote'];
if (!quote) {
throw new Error('无法获取股票数据,请检查API Key和股票代码。');
}
const price = parseFloat(quote['05. price']);
const change = parseFloat(quote['09. change']);
const changePercent = quote['10. change percent'];
const name = quote['02. name'];
// 更新DOM
nameElement.textContent = name;
priceElement.textContent = `$${price.toFixed(2)}`;
changeElement.textContent = `${change >= 0 ? '+' : ''}${change} (${changePercent})`;
// 根据涨跌设置颜色
if (change > 0) {
priceElement.style.color = 'green';
changeElement.style.color = 'green';
} else if (change < 0) {
priceElement.style.color = 'red';
changeElement.style.color = 'red';
} else {
priceElement.style.color = '#333';
changeElement.style.color = '#333';
}
} catch (error) {
console.error('获取股票数据失败:', error);
priceElement.textContent = 'Error';
priceElement.style.color = 'red';
}
}
// --- 初始化 ---
// 页面加载时立即获取一次数据
fetchAndUpdateStockData();
// 设置定时器,定期获取数据
setInterval(fetchAndUpdateStockData, INTERVAL);
优缺点:
- 优点: 实现简单,兼容性好,几乎所有后端都支持。
- 缺点:
- 效率低: 即使数据没有变化,也会频繁请求,浪费服务器资源和API配额。
- 延迟高: 两次请求之间的间隔就是你能达到的“实时”频率,无法做到毫秒级响应。
- 服务器压力大: 如果有大量用户同时访问,你的服务器(或API)会承受很大压力。
WebSocket - 真正的实时通信
对于需要低延迟、高频率更新的应用(如交易软件),轮询是不够的,WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,一旦连接建立,服务器就可以主动推送数据给客户端,无需客户端反复请求。
工作流程:
- 前端 JavaScript 使用
new WebSocket()建立与服务器(或支持WebSocket的API)的连接。 - 连接成功后,客户端可以订阅它关心的股票代码。
- 服务器在有数据更新时,通过这个已建立的连接将数据推送给客户端。
- 客户端通过监听
onmessage事件来接收并处理这些实时数据。
代码示例 (使用 Finnhub.io 的 WebSocket)
准备工作:
- 注册一个 Finnhub.io 账号,获取你的免费 API Key。
- Finnhub 提供了专门的 WebSocket 端点。
<!-- HTML部分和上面一样 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">Real-time Stock Price (WebSocket)</title>
<style>
body { font-family: sans-serif; text-align: center; margin-top: 50px; }
#stock-container { font-size: 2em; }
.price { font-weight: bold; color: #333; }
.change { font-size: 0.8em; }
</style>
</head>
<body>
<h1>实时股票行情 (WebSocket: AAPL)</h1>
<div id="stock-container">
<div>当前价格: <span id="price" class="price">--</span></div>
<div>变化: <span id="change" class="change">--</span></div>
</div>
<script src="websocket_app.js"></script>
</body>
</html>
JavaScript 代码 (websocket_app.js)
// --- 配置 ---
const API_KEY = 'YOUR_FINNHUB_API_KEY'; // 替换成你的 Finnhub API Key
const SYMBOL = 'AAPL';
const wsUrl = `wss://ws.finnhub.io?token=${API_KEY}`;
// --- DOM 元素 ---
const priceElement = document.getElementById('price');
const changeElement = document.getElementById('change');
// --- WebSocket 连接 ---
const ws = new WebSocket(wsUrl);
ws.onopen = () => {
console.log('WebSocket 连接已建立');
// 连接成功后,订阅股票数据
ws.send(JSON.stringify({ "type": "subscribe", "symbol": SYMBOL }));
};
ws.onmessage = (event) => {
// 收到服务器推送的消息
const data = JSON.parse(event.data);
// 检查消息类型和数据
if (data.type === 'trade' && data.data && data.data.length > 0) {
// Finnhub 会推送一个交易数组,我们取最新的一个
const trade = data.data[0];
const price = trade.p;
const change = trade.p - trade.prev_price; // 简单计算变化
// 更新DOM
priceElement.textContent = `$${price.toFixed(2)}`;
changeElement.textContent = `${change >= 0 ? '+' : ''}${change.toFixed(2)}`;
// 根据涨跌设置颜色
if (change > 0) {
priceElement.style.color = 'green';
changeElement.style.color = 'green';
} else if (change < 0) {
priceElement.style.color = 'red';
changeElement.style.color = 'red';
} else {
priceElement.style.color = '#333';
changeElement.style.color = '#333';
}
}
};
ws.onclose = () => {
console.log('WebSocket 连接已关闭');
// 可以在这里实现重连逻辑
};
ws.onerror = (error) => {
console.error('WebSocket 发生错误:', error);
};
优缺点:
- 优点:
- 真正的实时: 服务器主动推送,延迟极低。
- 高效: 没有不必要的请求,节省带宽和API资源。
- 可扩展性强: 适合需要同时处理大量客户端和实时数据更新的场景。
- 缺点:
- 实现复杂: 需要后端支持 WebSocket 服务(或者使用第三方提供的WebSocket API)。
- 兼容性: 需要现代浏览器支持(IE10以下不支持)。
服务器端事件 - 轮询的优雅替代
SSE 是一种服务器向客户端推送事件的技术,它基于 HTTP 协议,连接是持久的,可以看作是单向的 WebSocket(服务器 -> 客户端)。
工作流程:
- 客户端发起一个 HTTP 请求,并告诉服务器它希望接收“事件流”。
- 服务器保持这个连接打开,并在有新数据时通过这个连接发送数据。
- 客户端通过
EventSourceAPI 监听这些事件。
代码示例 (概念性,需要一个支持 SSE 的后端)
前端代码非常简单:
const eventSource = new EventSource('/api/stocks/AAPL'); // 假设你的后端提供了这个SSE端点
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('收到新数据:', data);
// 在这里更新你的DOM
priceElement.textContent = `$${data.price.toFixed(2)}`;
};
eventSource.onerror = (err) => {
console.error('SSE 发生错误:', err);
eventSource.close(); // 发生错误时关闭连接
};
优缺点:
- 优点: 比
setInterval轮询更高效,实现比 WebSocket 简单(尤其在后端),天然支持断线重连。 - 缺点: 主要是单向通信(服务器->客户端),不适用于需要客户端向服务器发送消息的场景。
总结与推荐
| 方法 | 实时性 | 实现复杂度 | 效率 | 适用场景 |
|---|---|---|---|---|
| 轮询 | 低 (秒级) | 非常简单 | 低 | 个人项目、学习、对实时性要求不高的应用 |
| WebSocket | 极高 (毫秒级) | 较复杂 (需要后端支持) | 非常高 | 专业交易软件、实时聊天、需要低延迟的金融应用 |
| SSE | 高 | 简单 (后端需支持) | 高 | 新闻推送、通知系统、需要服务器单向推送数据的场景 |
给你的建议:
-
如果你是初学者或在做个人项目/原型:
- 强烈推荐使用【轮询】,它最简单,最快能跑起来,而且很多免费API本身就足够支持轮询,先用它实现功能,再考虑优化。
-
如果你在做专业的、对实时性要求高的应用:
- 必须使用【WebSocket】,你需要寻找一个提供WebSocket接口的数据服务商(如Finnhub, Polygon.io等),虽然实现起来麻烦一点,但这是构建高性能实时应用的标准做法。
-
如果你的需求介于两者之间:
可以考虑【SSE】,如果你的后端技术栈(如Node.js + Express)很容易集成SSE的话,它是一个很好的折中方案。
最后的重要提醒:
- API Key 安全: 不要将你的 API Key 直接暴露在前端代码中,尤其是在生产环境中,任何人都可以在浏览器开发者工具中看到它,一个更安全的做法是前端请求你自己的后端,再由后端去调用第三方API。
- 频率限制: 务必仔细阅读你所用数据源的API文档,严格遵守其请求频率限制,否则你的API Key可能会被暂时或永久封禁。
文章版权及转载声明
作者:咔咔本文地址:https://jits.cn/content/698.html发布于 2025-10-31
文章转载或复制请以超链接形式并注明出处杰思科技・AI 股讯



还没有评论,来说两句吧...