微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

应用脚本 - 创建可安装的 onEdit 触发器以调用发出 API 请求的函数 - 不起作用 API 具有突发保护的速率限制解决方法参考资料

如何解决应用脚本 - 创建可安装的 onEdit 触发器以调用发出 API 请求的函数 - 不起作用 API 具有突发保护的速率限制解决方法参考资料

所以我对 app-script 比较陌生,并且已经成功地使用 urlFetchApp 发出 API 请求并将数据拉到我的谷歌表上。现在我感兴趣的是每当我编辑特定单元格的内容时运行这个 API 请求代码。并且单元格的内容将被集成到请求查询中。 更具体地说,我正在通过 API 提取公司财务报告,我希望能够在单元格中输入新的公司代码,并通过 API 请求将该公司的财务报告立即提取到我的工作表中。

我了解(根据经验)由于权限问题,简单的触发器 onEdit(e) 不起作用,我需要创建一个可安装的触发器。但出于某种原因,即使 UrlFetchApp 在从脚本编辑器运行时运行良好,但在我创建的可安装触发器触发时,它无法提取相同的数据。任何有关如何使其工作以及我做错了什么的建议将不胜感激。

这是我的代码

// make an API request and pull the historical income statements 
// for the company ticker in cell B1 of my sheet
function getIncomeStatement() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var url = 'https://www.alphavantage.co/query?function=INCOME_STATEMENT&symbol='
    + SpreadsheetApp.getActiveSheet().getRange('B1').getValue()
    + '&apikey=*****************';
  var response = UrlFetchApp.fetch(url);
  var financials = JSON.parse(response.getContentText());
  return financials;
}

// get the company's ticker and historic annual income statement reports 
// and print them to the active sheet
function getKeysVals() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var financials = getIncomeStatement();

  // get ticker and paste to sheet
  var symbol = financials['symbol'];
  rgMyRange = sheet.getRange(2,1,1);
  rgMyRange.setValue('Requested Ticker');
  rgMyRange = sheet.getRange(2,2,1);
  rgMyRange.setValue(symbol);

  // get Income Statement annual reports
  var annualReport = financials['annualReports'];

  // loop over nested objects in annualReports
  colToPaste = 1;
  for (var i = 1; i < annualReport.length; i++) {
    yearKeys = [];
    yearValues = [];

    // loop over keys/values within a specific year and paste keys/values to arrays
    var currentYear = annualReport[i];
    for (var key in currentYear) {
      yearKeys.push(key);
      yearValues.push(currentYear[key]);
    }

    // Combine the 2 arrays into one 2-Dimensional array and paste to sheet
    var values = yearKeys.map(function (e,i) { return [e,yearValues[i]] });
    rgMyRange = sheet.getRange(3,colToPaste,values.length,values[0].length);
    rgMyRange.setValues(values);

    // Move the range by 2 columns to the right avoid overwriting the next year's figures 
    colToPaste = colToPaste + 3;
  }
}

// create an installable trigger for onEdit
function createSpreadsheetEditTrigger() {
  var ss = SpreadsheetApp.getActive();
  ScriptApp.newTrigger('newOnEdit')
      .forSpreadsheet(ss)
      .onEdit()
      .create();
}

// create a new onEdit function to look for changes in cell B1
function newOnEdit(e) {
  var cellAddress = e.range.getA1Notation();
  if (cellAddress === 'B1') {
    getKeysVals();
  }
}

解决方法

API 具有突发保护的速率限制

对于许多 API,当他们说,例如:

每分钟最多 5 个 API 请求

这实际上意味着您每 12 秒只能发出一个请求。您不能在 10 秒内发出 5 个请求,然后等待 50 秒再发出 5 个请求。

我不确定为什么有些 API 在他们的文档中没有明确说明这一点,因为很容易假设,如果他们说每分钟 5 个请求,那么如果您愿意,您可以在 0.5 秒内发出 5 个请求。

这样做的一个可能原因是它可以防止 DDOS 攻击。想象一下,如果有人获得了数千个免费的 API 密钥,然后设置协调每个 API 密钥同时发送 5 个请求。这可能会破坏服务器。

解决方法

除了获得高级会员资格外,您还可以设置一个时间驱动的触发器,每 12 秒发送一次请求,以检查是否有任何需要检查的股票价格,然后一点一点地填写。如果它没有找到股票,那么它不会发出请求。

或者您可以尝试使用 onEdit 触发器存储时间与 PropertiesService

function onEdit(e) {
  // Get current time of edit
  let time = new Date();
  // Get the time of last request
  let scriptProperties = PropertiesService.getScriptProperties()
  let property = scriptProperties.getProperty("lastRequest")
  let lastRequest = new Date(property)

  // Calculate time since last request
  let timeSinceLastRequest = time.getTime() - lastRequest.getTime()

  // If more than 12 seconds ago,make request and reassign property
  if (timeSinceLastRequest > 12000) {

    // MAKE THE REQUEST HERE

    scriptProperties.setProperty("lastRequest",new Date())
  }
}


// Run this first to set the property for the first time.
function init(){
  let scriptProperties = PropertiesService.getScriptProperties()
  scriptProperties.setProperty("lastRequest",new Date())
}

参考资料

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。