Google apps script Google Adword脚本中止,出现以下错误:传递给回调函数的返回值必须是字符串
需要谷歌adwords脚本的帮助 我的脚本在启动后的第二秒内中止。脚本确实会间歇性运行 错误消息显示: 2018年4月10日上午10:53:08中止脚本 2018年10月4日上午10:53:09传递给回调函数的返回值必须是字符串 以下是整个脚本:该脚本使用来自谷歌的未经批准的关键字更新电子表格Google apps script Google Adword脚本中止,出现以下错误:传递给回调函数的返回值必须是字符串,google-apps-script,google-ads-api,Google Apps Script,Google Ads Api,需要谷歌adwords脚本的帮助 我的脚本在启动后的第二秒内中止。脚本确实会间歇性运行 错误消息显示: 2018年4月10日上午10:53:08中止脚本 2018年10月4日上午10:53:09传递给回调函数的返回值必须是字符串 以下是整个脚本:该脚本使用来自谷歌的未经批准的关键字更新电子表格 /** * This report Finds broken URLs */ //Standard Global Variables var details = ""; var fobGro
/**
* This report Finds broken URLs
*/
//Standard Global Variables
var details = "";
var fobGroupNum = 0;
var runStage = 0;
var fobGroup = {};
var cur_sheet = "";
var fobGroupName = "";
var ss = "";
var accountIds = [];
var reportDescription = '';
//FOB Global Vars
var fobGroups = [{
fobList: ['Apparel'],
sheets: {
DisapprovedKeywords: 'https://docs.google.com/spreadsheets/d/abc1',
NoAdGroups: 'https://docs.google.com/spreadsheets/d/abc2',
BrokenURLs: 'https://docs.google.com/spreadsheets/d/abc3',
DisapprovedAds: 'https://docs.google.com/spreadsheets/d/abc4',
History: 'https://docs.google.com/spreadsheets/d/abc5'
}
}, {
fobList: ['Center Core', 'Hispanic'],
sheets: {
DisapprovedKeywords: 'https://docs.google.com/spreadsheets/d/xyz1',
NoAdGroups: 'https://docs.google.com/spreadsheets/d/xyz2',
BrokenURLs: 'https://docs.google.com/spreadsheets/d/xyz3',
DisapprovedAds: 'https://docs.google.com/spreadsheets/d/xyz4',
History: 'https://docs.google.com/spreadsheets/d/xyz5'
}
}, {
fobList: ['Home'],
sheets: {
DisapprovedKeywords: 'https://docs.google.com/spreadsheets/d/def1',
NoAdGroups: 'https://docs.google.com/spreadsheets/d/def2',
BrokenURLs: 'https://docs.google.com/spreadsheets/d/def3',
DisapprovedAds: 'https://docs.google.com/spreadsheets/d/def4',
History: 'https://docs.google.com/spreadsheets/d/def5'
}
}, {
fobList: ['TM/Seasonal'],
sheets: {
DisapprovedKeywords: 'https://docs.google.com/spreadsheets/d/mno1',
NoAdGroups: 'https://docs.google.com/spreadsheets/d/mno2',
BrokenURLs: 'https://docs.google.com/spreadsheets/d/mno3',
DisapprovedAds: 'https://docs.google.com/spreadsheets/d/mno4',
History: 'https://docs.google.com/spreadsheets/d/mno5'
}
}];
var reportDescriptions = {
DisapprovedKeywords: 'Disapproved Keywords',
NoAdGroups: 'Ad Groups with No Active Ads',
BrokenURLs: 'Keywords with Invalid URLs',
DisapprovedAds: 'Disapproved Ads'
}
/**
* The function that starts the process
*/
function main() {
//Initialize Variables
var canRun = init(true);
if(!canRun){
Logger.log("Aborted the script");
return false;
}
//Clear all sheets in spreadsheet
clearSheets(ss);
//Get the accounts from accountIds
var accountSelector = MccApp.accounts().withIds(accountIds);
// Process the account in parallel.
accountSelector.executeInParallel('processAccount', 'allFinished', 1);
}
/**
* Post-process the results from processAccount. This method will be called
* once all the accounts have been processed by the executeInParallel method
* call.
*/
function allFinished(results) {
init();
var numErrors = 0;
var sheets = ss.getSheets();
for(var n in sheets){
var rows = sheets[n].getLastRow()-1;
if(rows>0){
numErrors+=rows;
}
}
//log if there were issues?
if(numErrors>0){
Logger.log("%s had %s %s", fobGroupName, numErrors, reportDescription);
//Consolidate all data to a single sheet
consolidateSheets(ss, "All Results");
//Compile the list of Managers and emails to send report to
var fobs = getFobs();
var managers = [];
var emails = [];
for( hob in fobGroup.fobList ){
managers = managers.concat(fobs[fobGroup.fobList[hob]].getManagers());
emails = emails.concat(fobs[fobGroup.fobList[hob]].getContacts());
}
//Normalize the list to make sure there are no repeat emails sent
var contacts = {};
for(var n in managers){
contacts[emails[n]]=managers[n];
}
if(debug){
//overwrite contacts with contacts on the debug list if we're debuggin'
contacts = {"abc@abc.com":"abc",
"xyz@xyz.com":"xyz" }
else {
;
}
//Compile the message subject and body
var subject = (Number(numErrors)-1)+" "+reportDescription+" found in "+fobGroup.fobList.join(' & ')+" Today.";
var body = "There are "+subject+"\n The detailed report can be accessed at the following URL: \n "+fobGroup.sheets[reportName];
//Send message to each contact individually (not sure how to do it all at once)
for(var e in contacts){
MailApp.sendEmail(e, subject, "Hi "+contacts[e].split(" ")[0]+", \n"+body);
Logger.log("Sending email to %s at %s", contacts[e], e);
}
} else {
Logger.log("%s had no %s", fobGroupName, reportDescription);
}
details.setErrors(numErrors);
details.setStatus("Complete");
Logger.log("The script is done");
}
//A safe way to select or add a sheet (tab) to a spreadsheet
function getSheetByAccount(ss, accountName){
try {
ss.insertSheet(accountName);
Logger.log("Sheet %s was created", accountName);
} catch (e) {
Logger.log("Sheet %s exists, Selecting it %s", accountName, e);
}
return ss.getSheetByName(accountName);
}
//Add sheet headers to sheet
function addSheetHeaders(sheet){
// Append header rows based on the selected column from the report including Account Name.
for(var n in sheetHeaders){
sheet.getRange(1, Number(n)+1).setValue(sheetHeaders[n]);
}
//Set the formatting of the headers
var heads = sheet.getRange(1, 1, 1, sheetHeaders.length);
heads.setBorder(false, true, true, true, true, null).setFontWeight('bold');
sheet.setFrozenRows(1);
}
//Consolidate all sheets into one and delete the individual results
function consolidateSheets(ss, sheetName){
var sName = sheetName || "Default";
var resSheet = getSheetByAccount(ss, sName);
resSheet.clear();
addSheetHeaders(resSheet);
var resRow = 2;
var cols = resSheet.getMaxColumns();
var sheets = ss.getSheets();
for(var n in sheets){
//Skip the Results sheet
if(sheets[n].getName()!=resSheet.getName()){
//Get number of rows in sheet
Logger.log("Getting rows for %s Sheet.", sheets[n].getName());
var rows = 0;
try {
rows = sheets[n].getLastRow()-1;
} catch (e){
Logger.log("Oops, can't get rows in sheet %s : %s", sheets[n].getName(), e);
}
if(rows>0){
//Get the range to copy start at second row to not copy header
var fromRange = sheets[n].getRange(2, 1, rows, cols);
//Copy data to consolidated sheet
fromRange.copyValuesToRange(resSheet, 1, cols, resRow, rows+resRow);
//Add better headers to the account's sheet
try {
addSheetHeaders(sheets[n]);
} catch(e){
Logger.log("Oops, can't set headers for sheet %s : %s", sheets[n].getName(), e);
}
//Increment the starting row of consolidated sheet
resRow+=rows;
} else {
//Delete the sheet with no data
try {
ss.deleteSheet(sheets[n]);
} catch(e) {
Logger.log("Can't delete sheet %s : %s", sheets[n].getName(), e);
}
}
}
}
}
//Delete all of the sheets except for one (can't delete all of them)
function clearSheets(ss, sName){
var sheetName = sName || "Default";
//See if there's a default sheet
getSheetByAccount(ss, sheetName);
//Clear all sheets in spreadsheet
var sheets = ss.getSheets();
for(var n in sheets){
if(sheets[n].getName() == sheetName){
sheets[n].clear();
} else {
ss.deleteSheet(sheets[n]);
}
}
Logger.log("Removed %s sheets from spreadsheet", sheets.length);
}
//Don't change this stuff
function getGroupNum(){
var details = runDetails();
return details.getFOB();
}
/* Run Details Manager
* This portion takes care of the FOB group selection
* so this report can be run multiple times to handle
* all of the FOBs with a single script as a workaround
* for the executeInParallel limitation
*/
function runDetails(){
this.dateRow = 2;
this.fobRow = 3;
this.statusRow = 4;
this.stageRow = 5;
this.errorsRow = 5;
this.reportField = 0;
this.group = 0;
this.run_sheet_url = 'https://docs.google.com/spreadsheets/d/stu';
this.run_ss = SpreadsheetApp.openByUrl(this.run_sheet_url);
this.run_sheet = this.run_ss.getActiveSheet();
this.runDate = "";
this.runFOB = "";
this.runStatus = "";
this.runStage = "";
this.getDetails = function(){
var runData = this.run_ss.getDataRange().getValues();
//get the mapping of date field and report field
for(var n in runData[0]){
if(runData[0][n]==reportName){
//Logger.log("We found the report name in %s", n);
this.reportField = n;
break;
}
}
//Logger.log("runData = %s", runData);
var lastDate = runData[dateRow-1][reportField];
//var lastDate = runData[1][1];
var numRuns = runData[fobRow-1][reportField];
this.runDate = lastDate;
this.runFOB = numRuns;
this.runStatus = runData[statusRow-1][reportField];
this.runStage = runData[stageRow-1][reportField];
return {
'date':this.runDate,
'FOB':this.runFOB,
'status':this.runStatus,
'stage':this.runStage
};
}
this.getFOB = function(){
var runData = this.getDetails();
//Converting report field to sheet-compatible (starts at 1 not 0);
var thiscol = Number(this.reportField)+1;
var runtimes = 0;
var today = getDateString();
if(runData.date == today){
if(runData.status=="Running"){
return runData.FOB;
} else {
Logger.log("FOB report done for %s, attempting to run it for %s", runData.FOB, Number(runData.FOB)+1);
this.setStatus("Running");
//this.setStage(1);
this.setFOB(Number(runData.FOB)+1);
return this.runFOB;
}
} else {
//wasn't run today yet
this.setStatus("Running");
//this.setStage(1);
this.setDate(today);
this.setFOB(0);
return 0;
}
};
this.setStatus = function(status){
var thiscol = Number(this.reportField)+1;
this.runStatus = status;
Logger.log("Attempting to set status to %s in row %s column %s", status, this.statusRow, thiscol);
this.run_sheet.getRange(this.statusRow, thiscol).setValue(status);
};
this.setFOB = function(num){
var thiscol = Number(this.reportField)+1;
this.runFOB = num;
this.run_sheet.getRange(this.fobRow, thiscol).setValue(num);
};
this.setDate = function(day){
var thiscol = Number(this.reportField)+1;
this.runDate = day;
this.run_sheet.getRange(this.dateRow, thiscol).setValue(day);
};
this.setStage = function(stage){
var thiscol = Number(this.reportField)+1;
this.runStage = stage;
Logger.log("Setting to stage %s", stage);
this.run_sheet.getRange(this.stageRow, thiscol).setValue(stage);
};
this.setErrors = function(errors){
var thiscol = Number(this.reportField)+1;
var thisrow = this.errorsRow + this.runFOB;
this.run_sheet.getRange(thisrow, thiscol).setValue(errors);
}
this.getDetails();
return this;
}
/**
* Initialize the process by getting FOBs, sheets and account IDs
* this function doesn't have much value anymore since accessing the sheet
* variable from the global scope was quite problematic
*/
function init(begin){
details = runDetails();
fobGroupNum = details.getFOB();
fobGroup = fobGroups[fobGroupNum];
reportDescription = reportDescriptions[reportName];
//Fails if there's no FOB group so it won't keep running and sending erroneous emails
if(!fobGroup){
return false;
}
ss = SpreadsheetApp.openByUrl(fobGroup.sheets[reportName]);
fobGroupName = fobGroup.fobList.join(', ');
if(begin){
//do this only for the first run to get account IDs for accountSelector
var fobs = getFobs();
// Select the accounts to be processed. You can process up to 50 accounts.
// Get the account IDs in this fob group
for( hob in fobGroup.fobList ){
accountIds = accountIds.concat(fobs[fobGroup.fobList[hob]].getAccountIds());
}
Logger.log("Opening %s %s FOB Accounts", accountIds.length, fobGroupName);
}
return true;
}
/**
* Get the FOBs
*/
function AccountListMapper(head){
that = {};
that.accountName = head.indexOf("Account");
that.accountId = head.indexOf("Customer ID");
that.fob = head.indexOf("FOB");
that.hob = head.indexOf("HOB");
that.manager = head.indexOf("FOB Manager");
that.contact = head.indexOf("Contact E-mail");
return that;
}
function Fob(options, mapper){
this.name = options[mapper.hob];
this.accounts = [];
this.accountIds = [];
this.managers = options[mapper.manager].replace(", ", ",").split(",");
this.contacts = options[mapper.contact].replace(", ", ",").split(",");
// this.mapper = mapper;
this.getName = function(){
return this.name;
};
this.getManagers = function(){
return this.managers;
}
this.getContacts = function(){
return this.contacts;
}
this.addAccount = function(data){
//make sure the account fob matches
if(this.getName() == data[mapper.hob]){
var account = {
name: data[mapper.accountName],
id: data[mapper.accountId],
fob: data[mapper.fob],
hob: data[mapper.hob]
};
this.accounts.push(account);
this.accountIds.push(account.id);
//Logger.log("Adding account %s %s to %s FOB", data[mapper.accountName], data[mapper.accountId], data[mapper.hob]);
return true;
} else {
//Logger.log("%s is not %s", this.getName(), data[mapper.hob]);
}
return false;
}
this.getAccountIds = function(){
return this.accountIds;
}
this.getAccounts = function(){
return this.accounts;
}
this.getAccount = function(id){
return this.accounts[this.accountIds.indexOf(id)];
}
}
/**
* Left pad numbers to normalize dates
*/
function padLeft(nr, n, str){
if(String(nr).length >= n){
return nr;
} else {
return Array(n-String(nr).length+1).join(str||'0')+nr;
}
}
/**
* Normalize Any Date String
*/
var normalizeDateString = function(dateString){
outDate = "";
if(dateString.length < 12){
d = new Date();
return(dateString + "T" + padLeft(d.getHours(), 2) + ":" +
padLeft(d.getMinutes(), 2) + ":" + padLeft(d.getSeconds(), 2)+"-"+
padLeft(d.getTimezoneOffset()/60, 2)+":"+
padLeft(d.getTimezoneOffset()%60, 2));
} else {
return(dateString);
}
}
function getDateString(){
return getTodayDateString()+" What!?";
}
function getTodayDateString(){
var d = new Date();
return d.getFullYear() + "-" + padLeft(d.getMonth()+1, 2) + "-" + padLeft(d.getDate(), 2);
}
function getFobs(){
var sheet_URL = 'https://docs.google.com/spreadsheets/d/stu';
//var fob_col = "D";
var ss = SpreadsheetApp.openByUrl(sheet_URL);
//var rows = ss.getDataRange().getNumRows(); //number of rows in sheet
var fobData = ss.getDataRange().getValues();
var fobs = new Object();
var mapper = AccountListMapper(fobData[0]);
for(i=1; i<fobData.length; i++){
if(!fobs[fobData[i][mapper.hob]]){
fobs[fobData[i][mapper.hob]]=new Fob(fobData[i], mapper);
}
fobs[fobData[i][mapper.hob]].addAccount(fobData[i]);
//Logger.log("Added %s to %s FOB", fobData[i][mapper.accountName], fobData[i][mapper.hob]);
}
return fobs;
}
/**
*此报表发现断开的URL
*/
//标准全局变量
var详细信息=”;
var fobGroupNum=0;
var-runStage=0;
var fobGroup={};
var cur_sheet=“”;
var fobGroupName=“”;
var ss=“”;
var accountIds=[];
var reportDescription='';
//FOB全球Vars
变量fobGroups=[{
fobList:[“服装”],
工作表:{
不批准的关键字:'https://docs.google.com/spreadsheets/d/abc1',
NoAdGroups:'https://docs.google.com/spreadsheets/d/abc2',
布罗克努尔斯:'https://docs.google.com/spreadsheets/d/abc3',
不赞成https://docs.google.com/spreadsheets/d/abc4',
历史:'https://docs.google.com/spreadsheets/d/abc5'
}
}, {
fobList:[“中心核心”、“西班牙裔”],
工作表:{
不批准的关键字:'https://docs.google.com/spreadsheets/d/xyz1',
NoAdGroups:'https://docs.google.com/spreadsheets/d/xyz2',
布罗克努尔斯:'https://docs.google.com/spreadsheets/d/xyz3',
不赞成https://docs.google.com/spreadsheets/d/xyz4',
历史:'https://docs.google.com/spreadsheets/d/xyz5'
}
}, {
fobList:['Home'],
工作表:{
不批准的关键字:'https://docs.google.com/spreadsheets/d/def1',
NoAdGroups:'https://docs.google.com/spreadsheets/d/def2',
布罗克努尔斯:'https://docs.google.com/spreadsheets/d/def3',
不赞成https://docs.google.com/spreadsheets/d/def4',
历史:'https://docs.google.com/spreadsheets/d/def5'
}
}, {
fobList:['TM/季节性]],
工作表:{
不批准的关键字:'https://docs.google.com/spreadsheets/d/mno1',
NoAdGroups:'https://docs.google.com/spreadsheets/d/mno2',
布罗克努尔斯:'https://docs.google.com/spreadsheets/d/mno3',
不赞成https://docs.google.com/spreadsheets/d/mno4',
历史:'https://docs.google.com/spreadsheets/d/mno5'
}
}];
var reportDescriptions={
未批准的关键字:“未批准的关键字”,
NoAdGroups:“没有活动广告的广告组”,
BrokerNurls:'具有无效URL的关键字',
不赞成的广告:“不赞成的广告”
}
/**
*启动进程的函数
*/
函数main(){
//初始化变量
var canRun=init(true);
如果(!canRun){
log(“中止脚本”);
返回false;
}
//清除电子表格中的所有工作表
透明纸(ss);
//从AccountID获取帐户
var accountSelector=MccApp.accounts().withid(accountid);
//并行处理帐户。
accountSelector.executeInParallel('processAccount','allFinished',1);
}
/**
*对processAccount中的结果进行后期处理。将调用此方法
*一旦所有帐户都通过executeInParallel方法处理完毕
*打电话。
*/
功能全部完成(结果){
init();
var数值=0;
var sheets=ss.getSheets();
用于(表中的变量n){
var rows=sheets[n].getLastRow()-1;
如果(行数>0){
数值+=行;
}
}
//记录是否有问题?
如果(数值错误>0){
Logger.log(“%s有%s%s”,fobGroupName,numerors,reportDescription);
//将所有数据合并到单个工作表中
合并报表(ss,“所有结果”);
//编制经理名单和发送报告的电子邮件
var fobs=getFobs();
var经理人=[];
var=[];
for(fobGroup.fobList中的hob){
managers=managers.concat(fobs[fobGroup.fobList[hob]].getManagers());
emails=emails.concat(fobs[fobGroup.fobList[hob]].getContacts());
}
//规范化列表以确保没有重复发送的电子邮件
var联系人={};
for(管理器中的var n){
联系人[电子邮件[n]]=经理[n];
}
如果(调试){
//如果我们正在调试,则使用调试列表中的联系人覆盖联系人'
联系人={”abc@abc.com“:“abc”,
"xyz@xyz.com“:“xyz”}
否则{
;
}
//编译消息主题和正文
var subject=(Number(numerors)-1)+“+fobGroup.fobList.join('&')+”中的“+reportDescription+”;
var body=“有“+subject+”\n可以通过以下URL访问详细报告:\n“+fobGroup.sheets[reportName];
//分别向每个联系人发送消息(不确定如何一次完成)
用于(触点中的var e){
MailApp.sendmail(e,主题,“Hi”+联系人[e].split(“”[0]+“,\n”+正文);
Logger.log(“向%s发送电子邮件,地址为%s”,联系人[e],e];
}
}否则{
Logger.log(“%s没有%s”,fobGroupName,reportDescription);
}
详细信息。设置错误(数字错误);
详细信息。设置状态(“完成”);
log(“脚本完成”);
}
//选择工作表(选项卡)或将其添加到电子表格的安全方法
函数getSheetByAccount(ss,accountName){
试一试{
ss.插入页(账户名称);
Logger.log(“创建了工作表%s”,accountName);
}捕获(e){
Logger.log(“工作表%s存在,选择它%s”,accountName,e);
}
返回ss.getSheetByName(accountName);
}
//将图纸标题添加到图纸
函数addSheetHeaders(工作表){
//根据报告中选定的列(包括帐户名)追加标题行。
用于(页眉中的变量n){
sheet.getRange(1,编号(n)+1).setValue(sheetHeaders[n]);
}
//设置标题的格式
var heads=sheet.getRange(1,1,1,sheetHeaders.length);
heads.setboorder(false,true,true,true,null).setFontWeight('bold');
活页。设置冻结行(1);
}
//将所有工作表合并为一个,并删除单个结果
功能整合表(ss,表名){
var sName=sheetName | |“默认”;
var resSheet=getSheetByAccount(ss,sName);
resSheet.clear();
添加页眉(res
accountSelector.executeInParallel('processAccount', 'allFinished', 1);