Google Yahoo Finance 的 Sheets Scraping Options Chain,结果不完整

Google Sheets Scraping Options Chain from Yahoo Finance, Incomplete Results

我正在尝试从 Google 表格中的 Yahoo Finance 抓取期权定价数据。虽然我能够很好地拉动期权链,即

=IMPORTHTML("https://finance.yahoo.com/quote/TCOM/options?date=1610668800","table",2)

我发现它返回的结果与 Yahoo Finance 上的实际显示不完全匹配。具体来说,抓取的结果是不完整的——他们缺少一些罢工。即图表的前 5 行可能匹配,但随后它将开始仅返回每隔一次罢工(也就是跳过每隔一次罢工)。

为什么 IMPORTHTML 会返回与页面上实际显示的内容不匹配的“缩写”结果?更重要的是,是否有某种方法可以抓取 完整 数据(即不会跳过可用罢工的某些部分)?

我相信你的目标如下。

  • 您想从 https://finance.yahoo.com/quote/TCOM/options?date=1610668800 的 URL 中检索完整的 table,并想将其放入 Spreadsheet。

问题和解决方法:

我可以复制你的问题。当我看到 HTML 数据时,不幸的是,我找不到 HTML 显示行和不显示行之间的区别。而且,我可以确认完整的 table 包含在 HTML 数据中。顺便说一句,当我使用 =IMPORTXML(A1,"//section[2]//tr") 对其进行测试时,会出现与 IMPORTHTML 相同的结果。所以我认为在这种情况下,IMPORTHTMLIMPORTXML可能无法检索到完整的table。

因此,在这个答案中,作为一种解决方法,我想建议使用 Sheets API 解析完整的 table。在这种情况下,使用 Google Apps 脚本。通过这个,我可以确认可以通过用 Sheet API.

解析 HTML table 来检索完整的 table

示例脚本:

请将以下脚本复制并粘贴到Spreadsheet和please enable Sheets API at Advanced Google services的脚本编辑器中。并且,请在脚本编辑器中运行 myFunction 的功能。这样,检索到的 table 被放入 sheetName.

的 sheet
function myFunction() {
  // Please set the following variables.
  const url ="https://finance.yahoo.com/quote/TCOM/options?date=1610668800";
  const sheetName = "Sheet1";  // Please set the destination sheet name.
  const sessionNumber = 2;  // Please set the number of session. In this case, the table of 2nd session is retrieved.

  const html = UrlFetchApp.fetch(url).getContentText();
  const section = [...html.matchAll(/<section[\s\S\w]+?<\/section>/g)];
  if (section.length >= sessionNumber) {
    if (section[sessionNumber].length == 1) {
      const table = section[sessionNumber][0].match(/<table[\s\S\w]+?<\/table>/);
      if (table) {
        const ss = SpreadsheetApp.getActiveSpreadsheet();
        const body = {requests: [{pasteData: {html: true, data: table[0], coordinate: {sheetId: ss.getSheetByName(sheetName).getSheetId()}}}]};
        Sheets.Spreadsheets.batchUpdate(body, ss.getId());
      }
    } else {
      throw new Error("No table.");
    }
  } else {
    throw new Error("No table.");
  }
}
  • const sessionNumber = 2; 表示 =IMPORTHTML("https://finance.yahoo.com/quote/TCOM/options?date=1610668800","table",2)2

参考文献:

这里有一个更简单的方法来获取给定期权的最后市场价格。为您添加此功能 Google Sheets 脚本编辑器。

function OPTION(ticker) {
    var ticker = ticker+"";
    var URL = "finance.yahoo.com/quote/"+ticker;
    var html = UrlFetchApp.fetch(URL).getContentText();
    var count = (html.match(/regularMarketPrice/g) || []).length;
    var query = "regularMarketPrice";
    var loc = 0;
    var n = parseInt(count)-2;
    for(i = 0; i<n; i++) {
        loc = html.indexOf(query,loc+1);
    }

    var value = html.substring(loc+query.length+9, html.indexOf(",", loc+query.length+9));
    return value*100;
}

在您的 google 工作表中输入 Yahoo Finance 选项代码,如下所示

=OPTION("AAPL210430C00060000")

在雅虎金融中,所有数据都可以在一个名为 root.App.main 的大 json 中使用。所以要得到完整的数据集,进行如下操作

  var source = UrlFetchApp.fetch(url).getContentText()
  var jsonString = source.match(/(?<=root.App.main = ).*(?=}}}})/g) + '}}}}'
  var data = JSON.parse(jsonString)

然后您可以选择获取您需要的信息。复制此示例 https://docs.google.com/spreadsheets/d/1sTA71PhpxI_QdGKXVAtb0Rc3cmvPLgzvXKXXTmiec7k/copy

编辑

如果您想获得可用数据的完整列表,您可以通过这个简单的脚本检索它

// mike.steelson
let result = []; 
function getAllDataJSON(url = 'https://finance.yahoo.com/quote/TCOM/options?date=1610668800') {
  var source = UrlFetchApp.fetch(url).getContentText()
  var jsonString = source.match(/(?<=root.App.main = ).*(?=}}}})/g) + '}}}}'
  var data = JSON.parse(jsonString)
  getAllData(eval(data),'data')
  var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
  sh.getRange(1, 1, result.length, result[0].length).setValues(result);
}
function getAllData(obj,id) {
  const regex = new RegExp('[^0-9]+');
  for (let p in obj) {
    var newid = (regex.test(p)) ? id + '["' + p + '"]' : id + '[' + p + ']';
    if (obj[p]!=null){
      if (typeof obj[p] != 'object' && typeof obj[p] != 'function'){
        result.push([newid, obj[p]]);
      }
      if (typeof obj[p] == 'object') {
        getAllData(obj[p], newid );
      }
    }
  }
}