将被刮擦
完整代码
如果您不需要解释,请看一下the full code example in the online IDE
const cheerio = require("cheerio");
const axios = require("axios");
const AXIOS_OPTIONS = {
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36",
}, // adding the User-Agent header as one way to prevent the request from being blocked
params: {
hl: "en", // parameter defines the language to use for the Google search
},
};
function getGoogleFinanceResults() {
return axios.get("https://www.google.com/finance/markets/indexes", AXIOS_OPTIONS).then(function ({ data }) {
let $ = cheerio.load(data);
const scripts = Array.from($("script"))
.map((el) => $(el).prop("outerHTML"))
.filter((el) => el.includes("key: 'ds:"))
.join("");
const allScriptsPattern = /key: '(?<key>[^']+)'.+?<\/script>/gm; //https://regex101.com/r/YUTocp/1
const scriptObjects = [...scripts.matchAll(allScriptsPattern)].map((el) => {
let script = `{${el[0].slice(0, -11)}`;
eval(`script = ${script}`);
script = JSON.stringify(script);
return script;
});
let markets = scriptObjects.find((el) => el.includes('"key":"ds:6"'));
const marketsRegionPattern =
/\[null,\[\["\/m\/.+?],"(?<name>[^"]+)".+?\[(?<price>[^,]+),(?<value>[^,]+),(?<percentage>[^,]+).+?\]."(?<region>[^\/]+).+?null,"(?<stock>[^"]+)/gm; //https://regex101.com/r/jM9hbY/2
const marketsRegions = [...markets.matchAll(marketsRegionPattern)].reduce((result, { groups }) => {
const { name, price, value, percentage, region, stock } = groups;
const index = {
stock,
link: `https://www.google.com/finance/quote/${stock}`,
name,
price,
priceMovement: {
percentage,
value,
movement: parseFloat(value) === 0 ? undefined : value[0] === "-" ? "Down" : "Up",
},
};
if (result[region]) result[region].push(index);
else result[`${region}`] = [index];
return result;
}, {});
markets.match(marketsRegionPattern).forEach((el) => (markets = markets.replace(el, "")));
const marketsCurrenciesAndCryptoPattern =
/\[null,\[\["\/g\/.+?null,"(?<name>[^":]+)",\d.+?\[(?<price>\d[^,]+),(?<value>[^,]+),(?<percentage>[^,]+).+?null,"(?<stock>[^"]+)/gm; //https://regex101.com/r/vu6yI2/1
const marketsCurrenciesAndCrypto = [...markets.matchAll(marketsCurrenciesAndCryptoPattern)].reduce((result, { groups }) => {
const { name, price, value, percentage, stock } = groups;
const index = {
stock,
link: `https://www.google.com/finance/quote/${stock}`,
name,
price,
priceMovement: {
percentage,
value,
movement: parseFloat(value) === 0 ? undefined : value[0] === "-" ? "Down" : "Up",
},
};
if (name.includes("(")) {
if (result.crypto) result.crypto.push(index);
else result.crypto = [index];
} else {
if (result.currencies) result.currencies.push(index);
else result.currencies = [index];
}
return result;
}, {});
markets.match(marketsCurrenciesAndCryptoPattern).forEach((el) => (markets = markets.replace(el, "")));
const marketsFuturesPattern =
/".+?",\d.+?\[(?<price>\d[^,]+),(?<value>[^,]+),(?<percentage>[^,]+).+?",null,"(?<stock>[^"]+)"\]\],"(?<name>[^"]+)/gm; //hhttps://regex101.com/r/50gPod/1
const marketsFutures = [...markets.matchAll(marketsFuturesPattern)].reduce((result, { groups }) => {
const { name, price, value, percentage, stock } = groups;
const index = {
stock,
link: `https://www.google.com/finance/quote/${stock}`,
name,
price,
priceMovement: {
percentage,
value,
movement: parseFloat(value) === 0 ? undefined : value[0] === "-" ? "Down" : "Up",
},
};
if (result.futures) result.futures.push(index);
else result.futures = [index];
return result;
}, {});
const marketsResults = { ...marketsRegions, ...marketsCurrenciesAndCrypto, ...marketsFutures };
const marketTrends = Array.from($(".Sy70mc")).map((el) => ({
title: $(el)
.find(".r6XbWb")
.contents()
.filter((i, el) => el.nodeType === 3)
.text(),
link: `https://www.google.com/finance${$(el).find(".r6XbWb a").attr("href").slice(1)}`,
results: Array.from($(el).find(".sbnBtf li")).map((el) => ({
stock: $(el).find("a").attr("href").slice(8),
link: `https://www.google.com/finance${$(el).find("a").attr("href").slice(1)}`,
name: $(el).find(".ZvmM7").text(),
price: $(el).find(".YMlKec").text(),
priceMovement: {
percentage: $(el).find(".JwB6zf").text(),
value: $(el).find(".P2Luy").text(),
movement: $(el).find(".NydbP").attr("aria-label").split(" ")[0],
},
})),
}));
const news = Array.from($(".yY3Lee")).map((el) => ({
source: $(el).find(".sfyJob").text(),
link: $(el).find(".z4rs2b a").attr("href"),
date: $(el).find(".Adak").text(),
snippet: $(el).find(".mRjSYb").text(),
thumbnail: $(el).find(".a9REI").attr("src"),
stocks: Array.from($(el).find(".wxtCmb")).map((el) => ({
stock: $(el).attr("href").slice(8),
link: `https://www.google.com/finance${$(el).attr("href").slice(1)}`,
name: $(el).find(".X18JZ").text(),
priceMovement: {
percentage: $(el).find(".JwB6zf").text(),
movement: $(el).find(".NydbP").attr("aria-label").split(" ")[0],
},
})),
}));
const discoverMore = Array.from($(".NBZP0e > div[role='listitem']")).map((el) => ({
stock: $(el).find(".tOzDHb").attr("href").slice(8),
link: `https://www.google.com/finance${$(el).find(".tOzDHb").attr("href").slice(1)}`,
name: $(el).find(".RwFyvf").text(),
price: $(el).find(".YMlKec").text(),
priceMovement: {
percentage: $(el).find(".JwB6zf").text(),
movement: $(el).find(".NydbP").attr("aria-label").split(" ")[0],
},
}));
return { markets: marketsResults, marketTrends, news, discoverMore };
});
}
getGoogleFinanceResults().then((result) => console.dir(result, { depth: null }));
准备
首先,我们需要创建一个node.js* project,然后添加koude0软件包koude1将koude1和koude2和koude2添加到网站上。
。为此,在我们项目的目录中,打开命令行并输入:
$ npm init -y
,然后:
$ npm i cheerio axios
*如果您没有安装node.js,则可以download it from nodejs.org并遵循安装documentation。
Process
首先,我们需要从HTML元素中提取数据。通过SelectorGadget Chrome extension,获得合适的CSS选择器的过程非常容易,通过单击浏览器中的所需元素,我们能够获取CSS选择器。但是,它并不总是完美地工作,尤其是当JavaScript大量使用该网站时。
如果您想了解更多有关它们的信息,我们在Serpapi上有专门的web Scraping with CSS Selectors博客文章。
下面的GIF说明了选择结果不同部分的方法。
代码说明
const cheerio = require("cheerio");
const axios = require("axios");
接下来,我们使用koude6编写请求选项:koude5,用于用作“真实”用户访问,以及提出请求的必要参数:
const AXIOS_OPTIONS = {
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36",
}, // adding the User-Agent header as one way to prevent the request from being blocked
params: {
hl: "en", // parameter defines the language to use for the Google search
},
};
ð注意:Default koude2 request user-agent is koude8因此,网站了解这是一个发送请求并可能阻止其的脚本。 Check what's your user-agent。
接下来,我们编写一个函数,该功能使请求并从页面返回接收到的数据。我们收到了koude2请求的响应,该请求具有我们destructured的data
键,并用koude1对其进行解析:
function getGoogleFinanceResults() {
return axios
.get("https://www.google.com/search", AXIOS_OPTIONS)
.then(function ({ data }) {
let $ = cheerio.load(data);
...
})
}
接下来,我们从页面上的所有脚本标签(使用koude13方法)中制作了一个新数组(koude12方法),并找到其中哪个包含"key: 'ds:6"
字符串:
const script = Array.from($("script"))
.map((el) => $(el).prop("outerHTML"))
.find((el) => el.includes("key: 'ds:6"));
然后,我们需要从script
字符串(koude16和koude17方法)的开始和末端中删除不必要的部分,并执行它(使用koude18方法)从字符串中获取对象并制造有效的JSON字符串(我们需要这样做,因为启动器script
字符串具有编码的符号(例如'\ u0026'),当我们执行它时,字符串已解码):
let markets;
const scriptObject = script.slice(script.indexOf("AF_initDataCallback") + 20, -11);
eval(`markets = JSON.stringify(${scriptObject})`);
然后,我们需要从markets
字符串中获取区域,货币,加密和期货市场数据,因为它们在页面上只显示一个,并且在浏览器中通过JavaScript更改。
首先,我们定义了koude21,然后使用koude22我们从koude23方法中收到的iterable iterator制作数组。
接下来,我们取得匹配结果,并使用koude24方法制作新对象:
//https://regex101.com/r/jM9hbY/2
const marketsRegionPattern =
/\[null,\[\["\/m\/.+?],"(?<name>[^"]+)".+?\[(?<price>[^,]+),(?<value>[^,]+),(?<percentage>[^,]+).+?\]."(?<region>[^\/]+).+?null,"(?<stock>[^"]+)/gm;
const marketsRegions = [...markets.matchAll(marketsRegionPattern)].reduce((result, { groups }) => {
...
}, {});
接下来,在reduce
方法的每次迭代中,我们destructure groups
对象,检查results
对象中是否存在带有当前region
的数组,我们将index
对象我们在此数组中,否则我们使用index
元素创建一个新数组对象:
const { name, price, value, percentage, region, stock } = groups;
const index = {
stock,
link: `https://www.google.com/finance/quote/${stock}`,
name,
price,
priceMovement: {
percentage,
value,
movement: parseFloat(value) === 0 ? undefined : value[0] === "-" ? "Down" : "Up",
},
};
if (result[region]) result[region].push(index);
else result[`${region}`] = [index];
return result;
接下来,我们从markets
字符串中删除解析部分:
markets.match(marketsRegionPattern).forEach((el) => (markets = markets.replace(el, "")));
然后,我们重复采用不同的货币,加密和期货市场的正则义务模式的解析:
//https://regex101.com/r/vu6yI2/1
const marketsCurrenciesAndCryptoPattern =
/\[null,\[\["\/g\/.+?null,"(?<name>[^":]+)",\d.+?\[(?<price>\d[^,]+),(?<value>[^,]+),(?<percentage>[^,]+).+?null,"(?<stock>[^"]+)/gm;
const marketsCurrenciesAndCrypto = [...markets.matchAll(marketsCurrenciesAndCryptoPattern)].reduce((result, { groups }) => {
const { name, price, value, percentage, stock } = groups;
const index = {
stock,
link: `https://www.google.com/finance/quote/${stock}`,
name,
price,
priceMovement: {
percentage,
value,
movement: parseFloat(value) === 0 ? undefined : value[0] === "-" ? "Down" : "Up",
},
};
if (name.includes("(")) {
if (result.crypto) result.crypto.push(index);
else result.crypto = [index];
} else {
if (result.currencies) result.currencies.push(index);
else result.currencies = [index];
}
return result;
}, {});
markets.match(marketsCurrenciesAndCryptoPattern).forEach((el) => (markets = markets.replace(el, "")));
//https://regex101.com/r/50gPod/1
const marketsFuturesPattern = /".+?",\d.+?\[(?<price>\d[^,]+),(?<value>[^,]+),(?<percentage>[^,]+).+?",null,"(?<stock>[^"]+)"\]\],"(?<name>[^"]+)/gm;
const marketsFutures = [...markets.matchAll(marketsFuturesPattern)].reduce((result, { groups }) => {
const { name, price, value, percentage, stock } = groups;
const index = {
stock,
link: `https://www.google.com/finance/quote/${stock}`,
name,
price,
priceMovement: {
percentage,
value,
movement: parseFloat(value) === 0 ? undefined : value[0] === "-" ? "Down" : "Up",
},
};
if (result.futures) result.futures.push(index);
else result.futures = [index];
return result;
}, {});
之后,我们从不同市场制作marketsResults
对象:
const marketsResults = { ...marketsRegions, ...marketsCurrenciesAndCrypto, ...marketsFutures };
接下来,要获取marketTrends
,news
和discoverMore
结果,我们需要使用下一个方法来获取页面的不同部分:
const marketTrends = Array.from($(".Sy70mc")).map((el) => ({
title: $(el)
.find(".r6XbWb")
.contents()
.filter((i, el) => el.nodeType === 3)
.text(),
link: `https://www.google.com/finance${$(el).find(".r6XbWb a").attr("href").slice(1)}`,
results: Array.from($(el).find(".sbnBtf li")).map((el) => ({
stock: $(el).find("a").attr("href").slice(8),
link: `https://www.google.com/finance${$(el).find("a").attr("href").slice(1)}`,
name: $(el).find(".ZvmM7").text(),
price: $(el).find(".YMlKec").text(),
priceMovement: {
percentage: $(el).find(".JwB6zf").text(),
value: $(el).find(".P2Luy").text(),
movement: $(el).find(".NydbP").attr("aria-label").split(" ")[0],
},
})),
}));
const news = Array.from($(".yY3Lee")).map((el) => ({
source: $(el).find(".sfyJob").text(),
link: $(el).find(".z4rs2b a").attr("href"),
date: $(el).find(".Adak").text(),
snippet: $(el).find(".mRjSYb").text(),
thumbnail: $(el).find(".a9REI").attr("src"),
stocks: Array.from($(el).find(".wxtCmb")).map((el) => ({
stock: $(el).attr("href").slice(8),
link: `https://www.google.com/finance${$(el).attr("href").slice(1)}`,
name: $(el).find(".X18JZ").text(),
priceMovement: {
percentage: $(el).find(".JwB6zf").text(),
movement: $(el).find(".NydbP").attr("aria-label").split(" ")[0],
},
})),
}));
const discoverMore = Array.from($(".NBZP0e > div[role='listitem']")).map((el) => ({
stock: $(el).find(".tOzDHb").attr("href").slice(8),
link: `https://www.google.com/finance${$(el).find(".tOzDHb").attr("href").slice(1)}`,
name: $(el).find(".RwFyvf").text(),
price: $(el).find(".YMlKec").text(),
priceMovement: {
percentage: $(el).find(".JwB6zf").text(),
movement: $(el).find(".NydbP").attr("aria-label").split(" ")[0],
},
}));
最后,我们返回一个带有结果的新对象:
return { markets: marketsResults, marketTrends, news, discoverMore };
现在我们可以启动我们的解析器:
$ node YOUR_FILE_NAME # YOUR_FILE_NAME is the name of your .js file
输出
{
"markets":{
"America":[
{
"stock":".DJI:INDEXDJX",
"link":"https://www.google.com/finance/quote/.DJI:INDEXDJX",
"name":"Dow Jones Industrial Average",
"price":"33745.69",
"priceMovement":{
"percentage":"0.5943158",
"value":"199.3711",
"movement":"Up"
}
},
...and other stocks
],
"Europe":[
{
"stock":"DAX:INDEXDB",
"link":"https://www.google.com/finance/quote/DAX:INDEXDB",
"name":"DAX PERFORMANCE-INDEX",
"price":"14431.86",
"priceMovement":{
"percentage":"1.1599331",
"value":"165.48047",
"movement":"Up"
}
},
...and other stocks
],
"Asia":[
{
"stock":"NI225:INDEXNIKKEI",
"link":"https://www.google.com/finance/quote/NI225:INDEXNIKKEI",
"name":"Nikkei 225",
"price":"27899.77",
"priceMovement":{
"percentage":"-0.11027624",
"value":"-30.800781",
"movement":"Down"
}
},
...and other stocks
],
"currencies":[
{
"stock":"EUR-USD",
"link":"https://www.google.com/finance/quote/EUR-USD",
"name":"EUR / USD",
"price":"1.0345499999999999",
"priceMovement":{
"percentage":"0",
"value":"0",
"movement":"undefined"
}
},
...and other stocks
],
"futures":[
{
"stock":"YMW00:CBOT",
"link":"https://www.google.com/finance/quote/YMW00:CBOT",
"name":"Dow Futures",
"price":"33766",
"priceMovement":{
"percentage":"0.5509068",
"value":"185",
"movement":"Up"
}
},
...and other stocks
]
},
"marketTrends":[
{
"title":"Americas",
"link":"https://www.google.com/finance/markets/indexes/americas",
"results":[
{
"stock":".INX:INDEXSP",
"link":"https://www.google.com/finance/quote/.INX:INDEXSP",
"name":"S&P 500",
"price":"3,965.34",
"priceMovement":{
"percentage":"0.48%",
"value":"+18.78",
"movement":"Up"
}
},
...and other stocks
]
},
...and other regions
],
"news":[
{
"source":"Investor's Business Daily",
"link":"https://www.investors.com/market-trend/stock-market-today/dow-jones-futures-market-rally-faces-key-resistance-time-to-buy-apple-stock-or-short/",
"date":"1 hour ago",
"snippet":"Dow Jones Futures: Market Rally Faces Key Resistance; Time To Buy Apple \n""+""Stock — Or Short? | Investor's Business ...",
"thumbnail":"https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRVfTCLlCLoj0slVCJA8XImDiE6s4Tqf-nMDcrzDyvN6CePx9R0d0hDkE1gHNY",
"stocks":[
{
"stock":".DJI:INDEXDJX",
"link":"https://www.google.com/finance/quote/.DJI:INDEXDJX",
"name":".DJI",
"priceMovement":{
"percentage":"0.59%",
"movement":"Up"
}
},
...and other stocks
]
},
...and other news
],
"discoverMore":[
{
"stock":".INX:INDEXSP",
"link":"https://www.google.com/finance/quote/.INX:INDEXSP",
"name":"S&P 500",
"price":"3,965.34",
"priceMovement":{
"percentage":"0.48%",
"movement":"Up"
}
},
... and other stocks
]
}
usuingaoqian36从serpapi
本节是为了显示DIY解决方案与我们的解决方案之间的比较。
最大的区别是您不需要从头开始创建解析器并维护它。
也有可能在Google的某个时候阻止请求,我们在后端处理它,因此无需弄清楚如何自己做或弄清楚要使用哪个验证码,代理提供商。 p>
首先,我们需要安装koude42:
npm i google-search-results-nodejs
这是full code example,如果您不需要说明:
const SerpApi = require("google-search-results-nodejs");
const search = new SerpApi.GoogleSearch(process.env.API_KEY); //your API key from serpapi.com
const params = {
engine: "google_finance_markets", // search engine
trend: "indexes", // parameter is used for retrieving different market trends
hl: "en", // parameter defines the language to use for the Google search
};
const getJson = () => {
return new Promise((resolve) => {
search.json(params, resolve);
});
};
exports.getResults = async () => {
const json = await getJson();
delete json.search_metadata;
delete json.search_parameters;
return json;
};
getResults().then((result) => console.dir(result, { depth: null }));
代码说明
首先,我们需要从koude42库中声明SerpApi
,并使用SerpApi的API键定义新的search
实例:
const SerpApi = require("google-search-results-nodejs");
const search = new SerpApi.GoogleSearch(API_KEY);
接下来,我们为提出请求的必要参数编写:
const params = {
engine: "google_finance_markets", // search engine
trend: "indexes", // parameter is used for retrieving different market trends
hl: "en", // parameter defines the language to use for the Google search
};
接下来,我们从Serpapi库中包装搜索方法,以便进一步处理搜索结果:
const getJson = () => {
return new Promise((resolve) => {
search.json(params, resolve);
});
};
最后,我们声明了从每个页面获取数据并返回的函数getResult
:
const getResults = async () => {
...
};
在此功能中,我们获得了带有结果的json
,删除search_metadata
和search_parameters
,然后返回此json
:
const json = await getJson();
delete json.search_metadata;
delete json.search_parameters;
return json;
之后,我们运行getResults
函数并使用koude52方法在控制台中打印所有接收的信息,该方法允许您使用带有必要参数的对象来更改默认输出选项:
getResults().then((result) => console.dir(result, { depth: null }));
输出
{
"markets":{
"us":[
{
"stock":".DJI:INDEXDJX",
"link":"https://www.google.com/finance/quote/.DJI:INDEXDJX",
"name":"Dow Jones",
"price":33745.69,
"price_movement":{
"percentage":0.5943158,
"value":199.3711,
"movement":"Up"
}
},
{
"stock":".INX:INDEXSP",
"link":"https://www.google.com/finance/quote/.INX:INDEXSP",
"name":"S&P 500",
"price":3965.34,
"price_movement":{
"percentage":0.47585818,
"value":18.78003,
"movement":"Up"
}
},
{
"stock":".IXIC:INDEXNASDAQ",
"link":"https://www.google.com/finance/quote/.IXIC:INDEXNASDAQ",
"name":"Nasdaq",
"price":11146.0625,
"price_movement":{
"percentage":0.009910241,
"value":1.1044922,
"movement":"Up"
}
},
{
"stock":"RUT:INDEXRUSSELL",
"link":"https://www.google.com/finance/quote/RUT:INDEXRUSSELL",
"name":"Russell",
"price":1849.7319,
"price_movement":{
"percentage":0.5768315,
"value":10.608643,
"movement":"Up"
}
},
{
"stock":"VIX:INDEXCBOE",
"link":"https://www.google.com/finance/quote/VIX:INDEXCBOE",
"name":"VIX",
"price":23.12,
"price_movement":{
"percentage":3.3848703,
"value":0.80999947,
"movement":"Down"
}
}
],
"europe":[
{
"stock":"DAX:INDEXDB",
"link":"https://www.google.com/finance/quote/DAX:INDEXDB",
"name":"DAX",
"price":14431.86,
"price_movement":{
"percentage":1.1599331,
"value":165.48047,
"movement":"Up"
}
},
{
"stock":"UKX:INDEXFTSE",
"link":"https://www.google.com/finance/quote/UKX:INDEXFTSE",
"name":"FTSE 100",
"price":7385.52,
"price_movement":{
"percentage":0.53058964,
"value":38.97998,
"movement":"Up"
}
},
{
"stock":"PX1:INDEXEURO",
"link":"https://www.google.com/finance/quote/PX1:INDEXEURO",
"name":"CAC 40",
"price":6644.46,
"price_movement":{
"percentage":1.0392122,
"value":68.33984,
"movement":"Up"
}
},
{
"stock":"SX5E:INDEXSTOXX",
"link":"https://www.google.com/finance/quote/SX5E:INDEXSTOXX",
"name":"STOXX 50",
"price":3924.84,
"price_movement":{
"percentage":1.1968834,
"value":46.420166,
"movement":"Up"
}
}
],
"asia":[
{
"stock":"NI225:INDEXNIKKEI",
"link":"https://www.google.com/finance/quote/NI225:INDEXNIKKEI",
"name":"Nikkei 225",
"price":27899.77,
"price_movement":{
"percentage":0.11027624,
"value":30.800781,
"movement":"Down"
}
},
{
"stock":"000001:SHA",
"link":"https://www.google.com/finance/quote/000001:SHA",
"name":"SSE",
"price":3097.2432,
"price_movement":{
"percentage":0.5839201,
"value":18.19165,
"movement":"Down"
}
},
{
"stock":"HSI:INDEXHANGSENG",
"link":"https://www.google.com/finance/quote/HSI:INDEXHANGSENG",
"name":"HSI",
"price":17992.54,
"price_movement":{
"percentage":0.29437047,
"value":53.121094,
"movement":"Down"
}
},
{
"stock":"SENSEX:INDEXBOM",
"link":"https://www.google.com/finance/quote/SENSEX:INDEXBOM",
"name":"SENSEX",
"price":61663.48,
"price_movement":{
"percentage":0.14108542,
"value":87.12109,
"movement":"Down"
}
},
{
"stock":"NIFTY_50:INDEXNSE",
"link":"https://www.google.com/finance/quote/NIFTY_50:INDEXNSE",
"name":"NIFTY 50",
"price":18307.65,
"price_movement":{
"percentage":0.19761337,
"value":36.25,
"movement":"Down"
}
}
],
"currencies":[
{
"stock":"EUR-USD",
"link":"https://www.google.com/finance/quote/EUR-USD",
"name":"EUR / USD",
"price":1.0345499999999999,
"price_movement":{
"percentage":0,
"value":0
}
},
...and other stocks
],
"crypto":[
{
"stock":"BTC-USD",
"link":"https://www.google.com/finance/quote/BTC-USD",
"name":"Bitcoin",
"price":16561.8,
"price_movement":{
"percentage":0.7264880417191196,
"value":121.20000000000073,
"movement":"Down"
}
},
...and other stocks
],
"futures":[
{
"stock":"YMW00:CBOT",
"link":"https://www.google.com/finance/quote/YMW00:CBOT",
"name":"Dow Futures",
"price":33766,
"currency":"USD",
"price_movement":{
"percentage":0.5509068,
"value":185,
"movement":"Up"
}
},
...and other stocks
]
},
"market_trends":[
{
"title":"Americas",
"link":"https://www.google.com/finance/markets/indexes/americas",
"serpapi_link":"https://serpapi.com/search.json?engine=google_finance_markets&hl=en&index_market=americas&trend=indexes",
"results":[
{
"stock":".INX:INDEXSP",
"link":"https://www.google.com/finance/quote/.INX:INDEXSP",
"name":"S&P 500",
"price":"3,965.34",
"extracted_price":3965.34,
"price_movement":{
"percentage":0.48,
"value":18.78,
"movement":"Up"
}
},
...and other stocks
]
},
...and other regions
],
"news_results":[
{
"source":"Investor's Business Daily",
"link":"https://www.investors.com/market-trend/stock-market-today/dow-jones-futures-market-rally-faces-key-resistance-time-to-buy-apple-stock-or-short/",
"date":"1 hour ago",
"snippet":"Dow Jones Futures: Market Rally Faces Key Resistance; Time To Buy Apple Stock — Or Short? | Investor's Business ...",
"thumbnail":"https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRVfTCLlCLoj0slVCJA8XImDiE6s4Tqf-nMDcrzDyvN6CePx9R0d0hDkE1gHNY",
"stocks":[
{
"name":"Dow Jones Industrial Average",
"stock":".DJI",
"price_movement":{
"percentage":0.59,
"movement":"Up"
}
},
...and other stocks
]
},
...and other news
],
"discover_more":[
{
"stock":".INX:INDEXSP",
"link":"https://www.google.com/finance/quote/.INX:INDEXSP",
"name":"S&P 500",
"price":"3,965.34",
"extracted_price":3965.34,
"price_movement":{
"percentage":0.48,
"movement":"Up"
}
},
...and other stocks
]
}
链接
如果您想查看一些用Serpapi制造的项目,write me a message。
添加一个Feature Requestð«或Bugð