首先,我不是一个有经验的程序员,我对Google Apps Script非常陌生。
我正在运行一个谷歌应用程序脚本,我卡住了。脚本的作用:它将工作表的一部分复制到临时工作表,将其转换为PDF并通过邮件发送。
我想为(现在)40个邮件地址做这个。如果我运行这个脚本,在5到8个地址之后,它会给我一个429(请求太多)错误。这是沉重的部分,我发现:var response = UrlFetchApp.fetch(url, params).getBlob();
如果我把它注释出来,它工作得很好,甚至复制粘贴临时表和发送电子邮件。
为了防止这种情况,我添加了一个睡眠计时器。我必须达到12秒,但没有得到错误。太好了。但是现在的剧本超过了6分钟(最长时间),所以时间太长,没有完成(大约一半)。
在阅读了一些我认为脚本(纠正我,如果我错了)是非常理想的,我需要"连锁函数调用"。但我不知道该怎么做。我将这个脚本分配给表单中的一个按钮。但是我看不出我如何运行一个函数并触发其他函数,而不考虑相同的函数(因此在6分钟后停止)。我该怎么做呢?
下面是完整的代码。对不起,荷兰语文本(它们只是一些确认窗口之类的):
function exportNamedRangesAsPDF() {
var y = 1
var sec = 40
var ui = SpreadsheetApp.getUi();
var result = ui.alert('Weet je zeker dat je alle maandstaten wil versturen via mail?',
ui.ButtonSet.YES_NO);
var html = HtmlService.createHtmlOutputFromFile('Page')
.setWidth(400)
.setHeight(200);
if (result == ui.Button.YES) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Maandstaten print');
var namenSheet = ss.getSheetByName('Alle_namen');
var namenSheetLastRow = namenSheet.getLastRow();
var namenSheetAantalX = namenSheet.getRange("Q1").getValue()
var startKol = 4
var namenVerzonden = [];
var mailOntbreekt = [];
//Logger.log(namenSheetLastRow)
var newSheet = ss.getSheetByName('print');
if (!newSheet) {
newSheet = ss.insertSheet('print');
}
newSheet.showSheet();
var gid = newSheet.getSheetId();
var ssID = "138zfRxR_SQ6oRJouQsMwKQZdyZYbqarUuMCfZTc8fGs";
var url = "https://docs.google.com/spreadsheets/d/"+ssID+"/export"+
"?format=pdf&"+
"size=7&"+
"fzr=false&"+
"portrait=true&"+
"fitw=true&"+
"gridlines=false&"+
"printtitle=false&"+
"sheetnames=false&"+
"pagenum=UNDEFINED&"+
"gid=1186495600&"+
"top_margin=0.75&"+
"bottom_margin=0.75&"+
"left_margin=0.2&"+
"right_margin=0.2&"+
"attachment=true";
var params = {method:"GET",headers:{"authorization":"Bearer "+ ScriptApp.getOAuthToken()}};
var i;
for (i = 1; i < namenSheetLastRow; i++) { //////// START FOR LOOP
if( namenSheet.getRange(i+1,16, 1, 1).getValue() == "x" ) { /////// START IF 1
var startRij = namenSheet.getRange(i+1,15, 1, 1).getValue()
var voornaam = sheet.getRange(startRij+10, startKol-1, 1, 1).getValues();
var zoeknaam = sheet.getRange(startRij+4, startKol-1, 1, 1).getValues();
ui.showModalDialog(html, "Bezig met versturen... " + y + " van " + namenSheetAantalX);
/*if (y % 5 == 0) { // Wait (sleep) every 5th time the script runs, to prevent 429 error (too many reqests)
ui.showModalDialog(html, "Wachten... "+ sec + " sec");
Utilities.sleep(sec*1000); // https://stackoverflow.com/questions/47648338/creating-multiple-google-sheets-pdfs-throws-429-error
Logger.log("Sleep: "+ sec + " sec")
}
y = y+1*/
if( namenSheet.getRange(i+1,16, 1, 1).getValue() == "x" && namenSheet.getRange(i+1,14, 1, 1).getValue() != "" ) { ////////// START IF 2
var volleNaam = sheet.getRange(startRij+2, startKol-2, 1, 1).getValues();
var maand = sheet.getRange(1, 2, 1, 1).getValues();
var mailAdres = sheet.getRange(startRij+9, startKol-1, 1, 1).getValue();
Logger.log(mailAdres + " " + volleNaam);
namenVerzonden.push(" " + zoeknaam);
sheet.getRange(startRij, startKol, 39, 16).copyTo(newSheet.getRange(1, 1, 39, 16), {contentsOnly: true}); //copy the right part of the sheet to the new sheet, content only
sheet.getRange(startRij, startKol, 39, 16).copyTo(newSheet.getRange(1, 1, 39, 16), {formatOnly: true});//copy the right part of the sheet to the new sheet, formatting only
var response = UrlFetchApp.fetch(url, params).getBlob(); // This is the super heavy part, running it too often causes a 429 (too many requests) error
//DriveApp.createFile(response); //save to drive
var message = { //send as email
to: mailAdres,
subject: "Maandstaat "+ maand,
body: "Beste "+ voornaam + ",nnIn de bijlage vind je de maandstaat van maand " + maand + ".nnMet vriendelijke groet,nCJ Hendriks Group",
name: "CJ Hendriks",
attachments: [{
fileName: "Maandstaat - " + maand + " - " + volleNaam + ".pdf",
content: response.getBytes(),
mimeType: "application/pdf"
}]
}
//MailApp.sendEmail(message); // This is the actual mail action
} ////////// END IF 2
} /////// END IF 1
else if( namenSheet.getRange(i+1,16, 1, 1).getValue() == "x" && namenSheet.getRange(i+1,14, 1, 1).getValue() == "" ) {
mailOntbreekt.push(" " + zoeknaam);
}
} //////// END FOR LOOP
ui.showModalDialog(html, "Maandstaten verzonden naar: " + namenVerzonden);
Logger.log('Maandstaten verzonden naar: n'+namenVerzonden);
if( mailOntbreekt.length != 0) {
ui.alert('Mail adres ontbreekt bij: n'+mailOntbreekt);
}
newSheet.hideSheet(); // hide the "print" sheet
}
else {
ui.alert('Maandstaten NIET verzonden.');
}
Logger.log("Succesvol voltooid")
}
谢谢!
您的脚本在效率方面很复杂
正如在注释部分提到的,您应该使用数组而不是获取所有数组,这对于您的代码来说是非常不可行的。第80行上的更多内容var response = UrlFetchApp.fetch(url, params).getBlob();
你应该在循环外发出这个请求,这就是你得到429的原因因为你的脚本生成了namenSheetLastRow乘以一个请求,这是相同的响应。请记住,当涉及到非计费帐户时,Sheets API有其限制,每个用户每100秒100个请求。
作为变通
将第80行移动到第50行,如下所示:
...
var params = {method:"GET",headers:{"authorization":"Bearer "+ ScriptApp.getOAuthToken()}};
var response = UrlFetchApp.fetch(url, params).getBlob();
...
在这样做时,您只需要发出一次请求,并且字节将存储在响应中。. 参考表API限值