求助:Google Apps Script抓取Yahoo Finance历史数据失败
修复Yahoo Finance历史数据抓取脚本
原脚本抛出"No data"错误的核心原因是Yahoo Finance页面结构更新,导致原正则匹配逻辑失效,同时密钥的存储位置也发生了变化。以下是修复后的完整代码及关键修改说明:
修复后的代码
function Scrapeyahoo(symbol) { // 抓取Yahoo Finance历史数据 const s = encodeURI(symbol); const url = `https://finance.yahoo.com/quote/${s}/history?p=${s}`; const res = UrlFetchApp.fetch(url, { muteHttpExceptions: true }).getContentText(); const $ = Cheerio.load(res); // 修改正则表达式,适配当前Yahoo Finance的页面结构 const data = $('script').toArray().reduce((ar, x) => { const scriptContent = $(x).text().trim(); // 匹配包含context的加密数据脚本 const match = scriptContent.match(/({"context".*?"dispatcher":.*?});\s*\}\(this\);/); if (match && match.length === 2) { try { ar.push(JSON.parse(match[1])); } catch (e) { // 解析失败跳过当前脚本 } } return ar; }, []); if (data.length === 0) throw new Error("No data."); const header = ["date", "open", "high", "low", "close", "adjclose", "volume"]; // 调整密钥获取逻辑:当前Yahoo将加密密钥存储在context._csrf字段 const key = data[0].context._csrf; if (!key) return; // 加载CryptoJS用于解密 const cdnjs = "https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"; eval(UrlFetchApp.fetch(cdnjs).getContentText()); // 解密并提取历史价格数据 const encryptedStores = data[0].context.dispatcher.stores; const obj2 = JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(encryptedStores, key))); const ar = obj2.HistoricalPriceStore.prices.map(o => header.map(h => h === "date" ? new Date(o[h] * 1000) : (o[h] || ""))); return ar; }
关键修改点
正则表达式适配:
- 移除原正则中错误的HTML转义符
",使用正常引号匹配页面源码 - 调整匹配结尾为
;\s*\}\(this\);,适配Yahoo当前的脚本包裹格式 - 增加
"dispatcher"关键词匹配,缩小目标脚本范围,避免无效匹配
- 移除原正则中错误的HTML转义符
密钥获取逻辑更新:
- 原脚本通过排除
context/plugins属性找密钥的方式已失效,当前Yahoo将加密密钥直接存储在context._csrf字段中,直接读取该字段即可
- 原脚本通过排除
增加异常容错:
- 为JSON解析添加
try-catch块,避免单个无效脚本导致整个抓取流程中断
- 为JSON解析添加
内容的提问来源于stack exchange,提问作者ejooroo
相关产品推荐
相关产品推荐

