关于从雅虎财经抓取数据的合法性,这是否会被认定为非法行为?
请别担心,雅虎财经网站上的大多数数据都是开源的,是公开信息。我们可以抓取的雅虎财经数据包括:
尽管从原则上讲是正确的,但为了安全起见,您仍然需要注意当地的网络抓取法律和法规。
在抓取之前,确定原因很重要。我们为什么要抓取它?在这里,我们可以为您提供分析。
通过抓取最近的数据,投资者可以获得最新的股票价格、交易量和市场动态,从而做出及时的投资决策。此外,通过分析历史数据,投资者可以构建基本的模型来预测股价走势,并协助投资策略的制定。
我们总是害怕风险,可以通过获取不同股票的绩效数据,帮助我们优化投资组合,降低风险。
财务报告、新闻和其他事件对股价有重大影响。通过抓取数据,我们可以清楚地了解股票市场,帮助投资者做出正确的投资决策。
经过一个投资周期,我们需要对投资资金的进展情况进行反馈总结。使用 Browserless 进行数据抓取可以及时有效地测试历史数据,验证交易策略的有效性,从而提高交易成功率。
然而,雅虎财经可能会使用IP 阻断、验证码和请求速率限制等措施来阻止自动抓取。而且由于某些数据可能是通过 JavaScript 动态加载的,我们需要使用更强大、更稳定的程序来处理动态网页。
别难过!Browserless 擅长处理这些问题。
Browserless 是一个基于云的解决方案,专为可扩展的浏览器自动化、网络抓取和网络测试而设计。Browserless 与 Playwright 和 Puppeteer 具有原生兼容性。它还设计了自动验证码解决和代理服务。此外,它配备了一个可扩展的平台,通过 API 集成实时视图并检索日志和记录。
您对网络抓取和 Browserless 有任何很棒的想法或疑问吗?
让我们看看其他开发人员在 Discord 上分享了什么!
我们需要 Browserless 服务来抓取雅虎财经。Nstbrowser 的 Browserless 是一款强大的工具,可以处理复杂的网络抓取和大规模自动化任务,并且支持完全托管的云部署。
Browserless 采用以浏览器为中心的方案,提供强大的无头部署功能,并提供更高的性能和可靠性。有关 Browserless 的更多信息,您可以从我们的 Browserless 文档 中学习。
puppeteer-core
:# pnpm
pnpm i puppeteer-core
# yarn
yarn add puppeteer-core
# npm
npm i --save puppeteer-core
apiKey
和 proxy
就可以开始后续的 Browserless 操作:import puppeteer from "puppeteer-core";
const apiKey = "your ApiKey"; // 必须填写
const config = {
proxy: 'your proxy', // 必须填写;输入格式:schema://user:password@host:port 例如:http://user:password@localhost:8080
// platform: 'windows', // 支持:windows、mac、linux
// kernel: 'chromium', // 只支持:chromium
// kernelMilestone: '128', // 支持:128
// args: {
// "--proxy-bypass-list": "detect.nstbrowser.io"
// }, // 浏览器参数
// fingerprint: {
// userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.85 Safari/537.36', // userAgent 自 v0.15.0 版本开始支持
// },
};
const query = new URLSearchParams({
token: apiKey, // 必须填写
config: JSON.stringify(config),
});
const browserlessWSEndpoint = `https://less.nstbrowser.io/connect?${query.toString()}`;
在开始抓取雅虎财经之前,我们可以先观察一下雅虎财经的 URL:https://finance.yahoo.com/quote/AAPL/。其中,AAPL
是股票代码。
显然,您可以通过更改股票代码路径来切换到需要抓取的股票页面。然后打开开发者工具 (F12) 检查页面的 HTML 结构,并将光标定位到当前的市场价格。
接下来,我们将尝试抓取这个价格:
在以上准备工作中,我们已经获得了 Browserless 连接端口,因此可以直接开始爬取。
// 连接到 browserless
const browser = await puppeteer.connect({
browserWSEndpoint: browserlessWSEndpoint,
defaultViewport: null,
})
const page = await browser.newPage();
await page.goto('https://finance.yahoo.com/quote/AAPL');
// 添加截图,方便后续排查问题
await page.screenshot({ path: 'yahoo.png' });
const selector = '[data-symbol="AAPL"][data-field="regularMarketPrice"]';
// 提取与选择器匹配的元素的内部文本(即股票价格)
const regularMarketPrice = await page.$eval(selector, el => el.innerText);
console.log(`Apple 当前股价为:${regularMarketPrice}`);
等等!如果我们现在运行上面的脚本,它很可能无法运行。为什么?让我们看看运行脚本时生成的截图 finance.png
。
可以看出,爬取失败的原因是我们还没有进行 Cookie 授权。那么我们将使用 Puppeteer 来帮助我们跳过 Cookie 授权:
接受全部
元素,并获得其对应的类选择器以上操作只需几行简单的代码就能轻松完成!
以下代码用于等待页面上出现类名为 .consent-overlay
的元素,然后点击层中的 "接受全部" (.accept-all
) 按钮。我们需要使用 try catch
来排除 Cookie 已授权的情况。
try {
await page.waitForSelector('.consent-overlay');
// 点击 "接受全部" 按钮
await page.click('.consent-overlay .accept-all');
} catch (e) {
console.log('Cookie 已授权');
}
import puppeteer from "puppeteer-core";
const apiKey = "your ApiKey"; // 'your proxy'
const config = {
proxy: 'your proxy', // 必须填写;输入格式:schema://user:password@host:port 例如:http://user:password@localhost:8080
// platform: 'windows', // 支持:windows、mac、linux
// kernel: 'chromium', // 只支持:chromium
// kernelMilestone: '128', // 支持:128
// args: {
// "--proxy-bypass-list": "detect.nstbrowser.io"
// }, // 浏览器参数
// fingerprint: {
// userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.85 Safari/537.36', // userAgent 自 v0.15.0 版本开始支持
// },
};
const query = new URLSearchParams({
token: apiKey, // 必须填写
config: JSON.stringify(config),
});
const browserlessWSEndpoint = `https://less.nstbrowser.io/connect?${query.toString()}`;
const browser = await puppeteer.connect({
browserWSEndpoint: browserlessWSEndpoint,
defaultViewport: null,
})
const page = await browser.newPage();
await page.goto('https://finance.yahoo.com/quote/AAPL/');
await page.screenshot({ path: 'yahoo.png' });
try {
await page.waitForSelector('.consent-overlay');
// 点击 "接受全部" 按钮
await page.click('.consent-overlay .accept-all');
} catch (e) {
console.log('Cookie 已授权');
}
const selector = '[data-symbol="AAPL"][data-field="regularMarketPrice"]';
const regularMarketPrice = await page.$eval(selector, el => el.innerText);
console.log(`Apple 当前股价为:${regularMarketPrice}`);
但是,直接在代码中编写股票代码不够灵活。因此,我们最好在脚本顶部添加以下代码。以下代码将强制脚本使用脚本参数运行:股票代码。
const tickerSymbols = process.argv.slice(2);
if (tickerSymbols.length === 0) {
console.error('Ticker symbol CLI 参数缺失!');
process.exit(2);
}
由于可能有多个股票代码,我们需要定义一个数组 (stockList
) 来接收抓取的结果。在以下代码中,我们将使用简单的循环来遍历和处理传入的股票代码列表。
// 包含所有抓取数据的数组
const stockList = [];
for (const tickerSymbol of tickerSymbols) {
console.log(`正在抓取 ${tickerSymbol} 的数据`);
// 导航到雅虎财经页面
await page.goto(`https://finance.yahoo.com/quote/${tickerSymbol}`);
try {
await page.waitForSelector('.consent-overlay');
// 点击 "接受全部" 按钮
await page.click('.consent-overlay .accept-all');
} catch (e) { }
// 使用模板字面量和股票代码定义选择器
const selectors = {
regularMarketPrice: `[data-symbol="${tickerSymbol}"][data-field="regularMarketPrice"]`,
regularMarketChange: `[data-symbol="${tickerSymbol}"][data-field="regularMarketChange"]`,
regularMarketChangePercent: `[data-symbol="${tickerSymbol}"][data-field="regularMarketChangePercent"]`,
preMarketPrice: `[data-symbol="${tickerSymbol}"][data-field="preMarketPrice"]`,
preMarketChange: `[data-symbol="${tickerSymbol}"][data-field="preMarketChange"]`,
preMarketChangePercent: `[data-symbol="${tickerSymbol}"][data-field="preMarketChangePercent"]`
};
// 初始化一个空对象来存储财务数据
const financialData = { tickerSymbol };
// 循环遍历每个选择器以提取文本内容
for (const [key, selector] of Object.entries(selectors)) {
try {
financialData[key] = await page.$eval(selector, el => el.innerText);
// 删除百分比值的括号
if (key.includes('ChangePercent')) {
financialData[key] = financialData[key].replace('(', '').replace(')', '');
}
} catch {
financialData[key] = 'N/A'; // 如果元素未找到,则将值设置为 N/A
}
}
// 将当前股票代码的财务数据添加到股票数组中
stockList.push(financialData);
}
console.log(JSON.stringify(stockList, null, 2));
运行以下脚本:
node yahoo.mjs AAPL TSLA
如果成功,将在控制台中打印以下内容:
显然,为了更好地进行数据分析,仅仅在控制台中打印数据是不够的。这里有一个简单的例子。只需手动拼接以下 CSV,然后使用 fs 模块创建抓取结果的 CSV 文件:
// 生成 csv 字符串并写入 csv 文件
let csvData = 'Ticker Symbol,Regular Market Price,Regular Market Change,Regular Market Change Percent,Pre Market Price,Pre Market Change,Pre Market Change Percent\n';
stockList.forEach(stock => {
csvData += `${stock.tickerSymbol},${stock.regularMarketPrice},${stock.regularMarketChange},${stock.regularMarketChangePercent},${stock.preMarketPrice},${stock.preMarketChange},${stock.preMarketChangePercent}\n`;
});
fs.writeFileSync('stocks_data.csv', csvData);
import puppeteer from "puppeteer-core";
import fs from 'fs'
const tickerSymbols = process.argv.slice(2);
if (tickerSymbols.length === 0) {
console.error('Ticker symbol CLI 参数缺失!');
process.exit(2);
}
const apiKey = "your ApiKey"; // 'your proxy'
const config = {
proxy: 'your proxy', // 必须填写;输入格式:schema://user:password@host:port 例如:http://user:password@localhost:8080
// platform: 'windows', // 支持:windows、mac、linux
// kernel: 'chromium', // 只支持:chromium
// kernelMilestone: '128', // 支持:128
// args: {
// "--proxy-bypass-list": "detect.nstbrowser.io"
// }, // 浏览器参数
// fingerprint: {
// userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.85 Safari/537.36', // userAgent 自 v0.15.0 版本开始支持
// },
};
const query = new URLSearchParams({
token: apiKey, // 必须填写
config: JSON.stringify(config),
});
const browserlessWSEndpoint = `https://less.nstbrowser.io/connect?${query.toString()}`;
const browser = await puppeteer.connect({
browserWSEndpoint: browserlessWSEndpoint,
defaultViewport: null,
})
console.info('已连接!');
const page = await browser.newPage();
// 包含所有抓取数据的数组
const stockList = [];
for (const tickerSymbol of tickerSymbols) {
console.log(`正在抓取 ${tickerSymbol} 的数据`);
// 导航到雅虎财经页面
await page.goto(`https://finance.yahoo.com/quote/${tickerSymbol}`);
try {
await page.waitForSelector('.consent-overlay');
// 点击 "接受全部" 按钮
await page.click('.consent-overlay .accept-all');
} catch (e) { }
// 使用模板字面量和股票代码定义选择器
const selectors = {
regularMarketPrice: `[data-symbol="${tickerSymbol}"][data-field="regularMarketPrice"]`,
regularMarketChange: `[data-symbol="${tickerSymbol}"][data-field="regularMarketChange"]`,
regularMarketChangePercent: `[data-symbol="${tickerSymbol}"][data-field="regularMarketChangePercent"]`,
preMarketPrice: `[data-symbol="${tickerSymbol}"][data-field="preMarketPrice"]`,
preMarketChange: `[data-symbol="${tickerSymbol}"][data-field="preMarketChange"]`,
preMarketChangePercent: `[data-symbol="${tickerSymbol}"][data-field="preMarketChangePercent"]`
};
// 初始化一个空对象来存储财务数据
const financialData = { tickerSymbol };
// 循环遍历每个选择器以提取文本内容
for (const [key, selector] of Object.entries(selectors)) {
try {
financialData[key] = await page.$eval(selector, el => el.innerText);
// 删除百分比值的括号
if (key.includes('ChangePercent')) {
financialData[key] = financialData[key].replace('(', '').replace(')', '');
}
} catch {
financialData[key] = 'N/A'; // 如果元素未找到,则将值设置为 N/A
}
}
// 将当前股票代码的财务数据添加到股票数组中
stockList.push(financialData);
}
console.log(JSON.stringify(stockList, null, 2));
// 生成 csv 字符串并写入 csv 文件
let csvData = 'Ticker Symbol,Regular Market Price,Regular Market Change,Regular Market Change Percent,Pre Market Price,Pre Market Change,Pre Market Change Percent\n';
stockList.forEach(stock => {
csvData += `${stock.tickerSymbol},${stock.regularMarketPrice},${stock.regularMarketChange},${stock.regularMarketChangePercent},${stock.preMarketPrice},${stock.preMarketChange},${stock.preMarketChangePercent}\n`;
});
fs.writeFileSync('stocks_data.csv', csvData);
await browser.close();
现在,运行脚本后,您不仅可以看到控制台打印,还可以看到在当前路径下写入的 stocks_data.csv
文件。
您可以在 Nstbrowser 客户端的 Browserless 菜单中查看最近请求的统计信息和剩余会话时间。
Nstbrowser 的 Browserless 是一款功能强大的网络抓取和自动化工具。它可以轻松绕过检测并确保抓取股价时的稳定性。在本教程中,您学习了:
雅虎财经是一个典型的动态网站,基于 JavaScript 的强大功能,内置了高级数据保护技术。
因此,如果您想轻松地抓取雅虎财经数据,您必须使用同样强大的抓取工具。我们免费的 Browserless 为您提供了最方便、最快捷的抓取方式。只需调用几行代码,您就可以做到。
免责声明: 本文提到的任何数据和网站仅供演示之用。我们坚决反对任何非法和侵权行为。如果您有任何问题或疑虑,请立即与我们联系。