如何解决应用脚本 - 创建可安装的 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 举报,一经查实,本站将立刻删除。