显示带有标签的帖子 读者要求. 显示所有帖子
显示带有标签的帖子 读者要求. 显示所有帖子

2013年7月1日,星期一

广告系列和关键字效果报告

老板要求您汇总的许多每日或每周报告任务都可以使用AdWords脚本自动执行。我的一位读者通过了以下要求脚本的请求,该脚本可以节省他每天的时间,并将其一些绩效报告汇总在一起。也许它也可以节省您一些时间。

以下脚本将构建具有五个标签的Google Spreadsheet:
  1. 过去7天的广告系列效果摘要
  2. 迄今为止的广告系列效果月份
  3. 上个月的广告系列效果
  4. 过去7天的关键字效果摘要
  5. 过去7天的每日关键字效果

您需要做的就是创建一个 新的Google电子表格 并将网址粘贴到脚本中。然后,您可以安排此脚本每天运行,并在早上开始工作时,将刷新所有数据。

谢谢,
拉斯

/************************************
* Campaign and Keyword Summary Report
* Version: 1.2
* Changelog v1.2 - Fixed INVALID_PREDICATE_ENUM_VALUE
* ChangeLog v1.1 - Removed apiVersion from 报告 呼叫
* Created By: 拉斯 Savage
* FreeAdWordsScripts.com
************************************/
var SPREADSHEET_URL = "PASTE GOOGLE SPREADSHEET URL HERE";

function main() {
  //These names are important. change them with caution
  var tabs = ['camp_perf_7_days','camp_perf_mtd','camp_perf_last_month','keyword_perf_7_days','keyword_perf_7_days_daily'];
  for(var i in tabs) {
    var results = runQuery(tabs[i]);
    writeToSpreadsheet(tabs[i],results);
  }
}

//Helper function to get or 创造 the 电子表格
function getSheet(tab) {
  var s_sheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
  var sheet;
  try {
    sheet = s_sheet.getSheetByName(tab);
    if(!sheet) {
      sheet = s_sheet.insertSheet(tab, 0);
    }
  } catch(e) {
    sheet = s_sheet.insertSheet(tab, 0);
  }
  return sheet
}

//Function to write the rows of the report to the sheet
function writeToSpreadsheet(tab,rows) {
  var to_write = 兑换RowsToSpreadsheetRows(tab,rows);
  var s_sheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
  var sheet = getSheet(tab);
  sheet.clear();
  
  var numRows = sheet.getMaxRows();
  if(numRows < to_write.length) {
    sheet.insertRows(1,to_write.length-numRows); 
  }
  var range = sheet.getRange(1,1,to_write.length,to_write[0].length);
  range.setValues(to_write);
}

//A generic function used to build and run the report query
function runQuery(tab) {
  var API_VERSION = { includeZeroImpressions : false };
  var cols = getColumns(tab);
  var report = getReport(tab);
  var date_range = getDateRange(tab);
  var where = getWhereClause(tab);
  var query = ['select',cols.join(','),'from',report,where,'during',date_range].join(' ');
  var report_iter = AdWordsApp.report(query, API_VERSION).rows();
  var rows = [];
  while(report_iter.hasNext()) { 
    rows.push(report_iter.next());
  }
  return rows;
}
 
//This function will 兑换 row data into a format easily pushed into a 电子表格
function 兑换RowsToSpreadsheetRows(tab,rows) {
  var cols = getColumns(tab);
  var ret_val = [cols];
  for(var i in rows) {
    var r = rows[i];
    var ss_row = [];
    for(var x in cols) {
      ss_row.push(r[cols[x]]);
    }
    ret_val.push(ss_row);
  }
  return ret_val;
}

//Based on the tab name, this returns the report type to use for the query
function getReport(tab) {
  if(tab.indexOf('camp_') == 0) {
    return 'CAMPAIGN_PERFORMANCE_REPORT';
  }
  if(tab.indexOf('keyword_') == 0) {
    return 'KEYWORDS_PERFORMANCE_REPORT';
  }
  throw new Exception('tab name not recognized: '+tab);
}

//Based on the tab name, this returns the where clause for the query
function getWhereClause(tab) {
  if(tab.indexOf('camp_') == 0) {
    return 'where CampaignStatus = ENABLED';
  }
  if(tab.indexOf('keyword_') == 0) {
    return 'where CampaignStatus = ENABLED and AdGroupStatus = ENABLED and Status = ENABLED';
  }
  throw new Exception('tab name not recognized: '+tab);
}

//Based on the tab name, this returns the columns to 广告 d into the report
function getColumns(tab) {
  var ret_array = [];
  if(tab.indexOf('daily') >= 0) {
    ret_array.push('Date');
  }
  ret_array.push('CampaignName');
  ret_array.push('CampaignStatus');
  
  if(tab.indexOf('keyword_') == 0) {
    ret_array = ret_array.concat(['AdGroupName',
                                  'AdGroupStatus',
                                  'Id',
                                  'KeywordText',
                                  'KeywordMatchType']);
  }
  return ret_array.concat(['Clicks',
                           'Impressions',
                           'Ctr',
                           'AverageCpc',
                           'Cost',
                           'AveragePosition',
                           'Conversions',
                           'ConversionRate',
                           'ConversionValue']);
}

//Based on the tab name, this returns the date range for the data.
function getDateRange(tab) {
  if(tab.indexOf('7_days') >= 0) {
    return 'LAST_7_DAYS';
  }
  if(tab.indexOf('mtd') >= 0) {
    return 'THIS_MONTH';
  }
  if(tab.indexOf('last_month') >= 0) {
    return 'LAST_MONTH';
  }
  throw new Exception('tab name not recognized: '+tab);
}

2013年6月22日,星期六

广告创意测试自动化脚本

这是我已经工作了一段时间的脚本,我认为它确实很有用。我希望你也这样做。

每个有价值的SEM经理都在不断进行创造性的测试。而且,由于您正在阅读此博客,因此许多人可能以某种方式使用脚本来简化此过程。但是,您如何确定测试何时开始?对于每个广告组,它们可能会有所不同。

我见过有些人使用标签,有些人使用时间表,但是我从不真正喜欢跟踪那些东西。因此,我创建了此脚本,该脚本将自动跟踪创意测试的开始日期。

我采用的方法是将您的广告ID副本存储在Google电子表格中。然后,它会对照电子表格中的广告检查广告组中的当前广告,并通过查看广告ID找出是否有所更改。如果已经存在,则脚本假定已开始新的测试,并相应地在电子表格中记录了日期。使用此方法,营销人员可以确保脚本正在比较适当时间范围内的统计信息以确定测试获胜者。

但是后来一位读者提到,他们希望能够选择度量标准来衡量广告,并希望使用阈值仅在广告组中获得一定点击次数后才开始进行衡量。因此,我也将该功能添加到了脚本中。您只需要在脚本顶部调整一些参数,即可使用功能齐全的广告素材测试脚本。

每当它通过暂停对广告采取行动时,结果都会通过电子邮件发送给您,以便您可以为该广告组创建新的挑战者广告。

我用这个脚本做了一些不同的事情。我一直很讨厌让我的读者进入Google文档,并为我的脚本创建一个空白电子表格以用作存储。因此,为了解决这个问题,此脚本将检查存储电子表格ID的帐户中是否存在特殊标签。如果找到一个,它将使用它。并且如果缺少它(如第一次运行),它将创建电子表格和标签。这样,脚本中不会出现混乱的电子表格网址。这是一个变通办法,但是直到Google允许我们为脚本存储其他配置数据之前,我认为这是处理此问题的一种好方法。

与往常一样,我们欢迎您反馈此脚本是否对您有用。您还通过哪些其他指标来判断广告效果?该脚本还缺少什么?

谢谢,
拉斯

/************************************
* 广告创意测试自动化脚本
* Version: 1.3
* Changelog v1.3 - Data is written to the 电子表格 a little faster
* Changelog v1.2 - Added 广告 ditional threshold options
* Changelog v1.1 - Fixed issue with 日期 in 电子邮件
* Created By: 拉斯 Savage
* FreeAdWordsScripts.com
************************************/
// You can use any of the same values here as you can for METRIC below
var THRESHOLD = { metric : 'Clicks', value : 100 };
var TO = ['[email protected]'];
  
//Try any of these values for METRIC:
//AverageCpc, AverageCpm, AveragePageviews, AveragePosition, 
//AverageTimeOnSite, BounceRate, Clicks, ConversionRate, 
//Conversions, Cost, Ctr, Impressions
var METRIC = 'Ctr';
var ASC_OR_DESC = 'ASC'; //ASC - 暂停广告 with lowest value, DESC - 暂停广告 with highest value
  
function main() {
  //Start by finding what has changed in the account
  var 广告 _map = buildCurrentAdMap();
  var prev_ad_map = readMapFromSpreadsheet();
  prev_ad_map = 更新PreviousAdMap(prev_ad_map,ad_map);
  writeMapToSpreadsheet(prev_ad_map);
    
  //Now run through the 广告群组 to find creative tests
  var ag_iter = AdWordsApp.adGroups().get();
  var 暂停d_ads = [];
  while(ag_iter.hasNext()) {
    var ag = ag_iter.next();
    if(!prev_ad_map[ag.getId()]) { continue; }
      
    //Here is the date range for the test metrics
    var last_touched_str = _getDateString(prev_ad_map[ag.getId()].last_touched,'yyyyMMdd');
    var get_today_str = _getDateString(new Date(),'yyyyMMdd');
      
    var ag_stats = ag.getStatsFor(last_touched_str, get_today_str);
    if(ag_stats['get'+THRESHOLD.metric]() >= THRESHOLD.value) {
      var 广告 _iter = ag.ads().withCondition('Status = ENABLED')
                            .forDateRange(last_touched_str, get_today_str)
                            .orderBy(METRIC+" "+ASC_OR_DESC).get();
      var 广告  = 广告 _iter.next();
      var metric = 广告 .getStatsFor(last_touched_str, get_today_str)['get'+METRIC]();
      ad.pause();
      paused_ads.push({a : 广告 , m : metric});
    }
  }
  sendEmailForPausedAds(paused_ads);
}
  
// A function to send an 电子邮件 with an 在tached report of 广告 it has 暂停d
function sendEmailForPausedAds(ads) {
  if(ads.length == 0) { return; } //No 广告 暂停d, no 电子邮件
  var 电子邮件_body = '"' + ['CampaignName','AdGroupName','Headline','Desc1','Desc2','DisplayUrl',METRIC].join('","') + '"\n';
  for(var i in 广告) {
    var 广告  = 广告[i].a;
    var metric = 广告[i].m;
    email_body += '"' + [ad.getCampaign().getName(),
                         ad.getAdGroup().getName(),
                         ad.getHeadline(),
                         ad.getDescription1(),
                         ad.getDescription2(),
                         ad.getDisplayUrl(),
                         metric
                        ].join('","') +
                  '"\n';
  }
  var date_str = _getDateString(new Date(),'yyyy-MM-dd');
  var options = { 附件: [Utilities.newBlob(email_body, 'text/csv', "FinishedTests_"+date_str+'.csv')] };
  var subject = 'Finished Tests - ' + date_str;
  for(var i in TO) {
    MailApp.sendEmail(TO[i], subject, 'See 在tached.', options);
  }
}
  
//Given two lists of 广告, this checks to make sure they are the same.
function sameAds(ads1,ads2) {
  for(var i in 广告1) {
    if(ads1[i] != 广告2[i]) { return false; }
  }
  return true;
}
  
//This reads the stored data from the 电子表格
function readMapFromSpreadsheet() {
  var 广告 _map = {};
  var sheet = SpreadsheetApp.openById(findSpreadsheetId()).getActiveSheet();
  var data = sheet.getRange('A:C').getValues();
  for(var i in data) {
    if(data[i][0] == '') { break; }
    var [ag_id,last_touched,ad_ids] = data[i];
    ad_map[ag_id] = { 广告 _ids : (''+ad_ids).split(','), last_touched : new Date(last_touched) };
  }
  return 广告 _map;
}
  
//This will search for a 标签 containing the 电子表格 id
//If one isn't found, it will 创造 a new one and the 标签 as well
function findSpreadsheetId() {
  var 电子表格_id = "";
  var 标签_iter = AdWordsApp.labels().withCondition("Name STARTS_WITH 'history_script:'").get();
  if(label_iter.hasNext()) {
    var 标签 = 标签_iter.next();
    return 标签.getName().split(':')[1]; 
  } else {
    var sheet = SpreadsheetApp.create('AdGroups History');
    var sheet_id = sheet.getId();
    AdWordsApp.createLabel('history_script:'+sheet_id, 'stores sheet id for 广告群组 changes script.');
    return sheet_id;
  }
}
  
//This will store the data from the account into a 电子表格
function writeMapToSpreadsheet(ad_map) {
  var toWrite = [];
  for(var ag_id in 广告 _map) {
    var 广告 _ids = 广告 _map[ag_id].ad_ids;
    var last_touched = 广告 _map[ag_id].last_touched;
    toWrite.push([ag_id,last_touched,ad_ids.join(',')]);
  }
  writeToSpreadsheet(toWrite);
}

// Write the 关键词 data to the 电子表格
function writeToSpreadsheet(toWrite) {
  var sheet = SpreadsheetApp.openById(findSpreadsheetId()).getActiveSheet();
  sheet.clear();
  
  var numRows = sheet.getMaxRows();
  if(numRows < toWrite.length) {
    sheet.insertRows(1,toWrite.length-numRows); 
  }
  var range = sheet.getRange(1,1,toWrite.length,toWrite[0].length);
  range.setValues(toWrite);
}
  
//This builds a map of the 广告 in the account so that it is easy to compare
function buildCurrentAdMap() {
  var 广告 _map = {}; // { ag_id : { 广告 _ids : [ 广告 _id, ... ], last_touched : date } }
  var 广告 _iter = AdWordsApp.ads().withCondition('Status = ENABLED').get();
  while(ad_iter.hasNext()) {
    var 广告  = 广告 _iter.next();
    var ag_id = 广告 .getAdGroup().getId();
    if(ad_map[ag_id]) {
      ad_map[ag_id].ad_ids.push(ad.getId());
      ad_map[ag_id].ad_ids.sort();
    } else {
      ad_map[ag_id] = { 广告 _ids : [ad.getId()], last_touched : new Date() };
    }
  }
  return 广告 _map;
}
  
//This takes the old 广告  map and the current 广告  map and returns an
//updated map with all changes.
function 更新PreviousAdMap(prev_ad_map,ad_map) {
  for(var ag_id in 广告 _map) {
    var current_ads = 广告 _map[ag_id].ad_ids;
    var previous_ads = (prev_ad_map[ag_id]) ? prev_ad_map[ag_id].ad_ids : [];
    if(!sameAds(current_ads,previous_ads)) {
      prev_ad_map[ag_id] = 广告 _map[ag_id];
    }
  }
  return prev_ad_map;
}
  
//Helper function to format the date
function _getDateString(date,format) {
  return Utilities.formatDate(date,AdWordsApp.currentAccount().getTimeZone(),format); 
}

2013年4月5日,星期五

v2.0

2013年4月6日更新:请确保将每日预算乘以30.5,以将其转化为每月预算(第150行)。

2013年6月6日更新:请确保在重置预算后,将预算除以30.5,以将其转化为每日预算(第95行)。

更新2013-04-07:非常感谢FoxSUP帮助我跟踪更新预算的问题。修复了第78行,将当前预算乘以1 + to_change,而不仅仅是to_change。还修复了计算更改时的错误(第56行)。


这是我放在一起的上一个脚本的更新 动态调整广告系列预算。一些评论提出了一些要求,我认为将它们合并到一个新帖子中会更容易。

现在,该脚本将跟踪您在本月初通过Google Spreadsheet设置的预算。如果只希望此标签在具有该标签名称的广告系列上运行,则也可以填写LABEL值。将其保留为空白可在所有广告系列上使用。

谢谢,
拉斯

/********************************
* 动态调整广告系列预算 v2.1
* Changelog v2.1 - Fixed opening of 电子表格
* Created By: 拉斯 Savage
* FreeAdWordsScripts.com
********************************/
// Let's set some constants
var TIMEFRAME = "THIS_MONTH";
//if the 运动 is not in the 电子表格, the 预算 is reset
//to this value 在 the beginning of the month.
var DEFAULT_BUDGET = 100; 
var SPREADSHEET_URL = "PLACE EMPYT SPREADSHEET URL HERE";
var LABEL = ""; //Fill in if you only want to operate on 运动s with this 标签
 
var SIG_FIGS = 1000; //this 意思s round all calculations to 3 decimal places
var MONTHLY_BUDGET = 0; // we will set this later
 
function main() {
  MONTHLY_BUDGET = _pull_budget_data_from_spreadsheet();
  var tot_cost_mtd = _get_total_cost();
  var is_first_of_the_month = ((new Date()).getDate() == 1);
  is_first_of_the_month = (is_first_of_the_month && ((new Date()).getHours() == 0));
  Logger.log("Total cost: " + tot_cost_mtd + ", Monthly 预算:" + MONTHLY_BUDGET);
   
  if(is_first_of_the_month) {
    _reset_budgets();
  } else {
    _adjust_campaign_budget(tot_cost_mtd);
  }
   
}
 
// Returns the total cost for the set TIMEFRAME
function _get_total_cost() {
  var camp_iter = (LABEL == "") ? AdWordsApp.campaigns().get() :
                                  AdWordsApp.campaigns()
                                    .withCondition("LabelNames CONTAINS_ANY ['"+LABEL+"']")
                                    .get();
   
  var tot_cost = 0;
  while(camp_iter.hasNext()) {
    tot_cost += camp_iter.next().getStatsFor(TIMEFRAME).getCost();
  }
  return tot_cost;
}
 
// Calculates 运行速度 and 广告 justs 运动 竞标 as needed.
function _adjust_campaign_budget(my_tot_cost) {
  var today = new Date();
  // Accounting for December
  var eom = (today.getMonth() == 11) ? new Date(today.getFullYear()+1,0,1) : 
                                       new Date(today.getFullYear(),today.getMonth()+1,1);
  var days_left = Math.round((eom-today)/1000/60/60/24);
  var days_spent = today.getDate();
  var run_rate = Math.round(my_tot_cost/days_spent*SIG_FIGS)/SIG_FIGS;
  var projected_total = my_tot_cost + (run_rate * days_left);
  var perc_over = Math.round(((MONTHLY_BUDGET-projected_total)/projected_total)*SIG_FIGS)/SIG_FIGS; 
  _change_spend(perc_over,my_tot_cost);
}
 
//Adjusts the 预算 for a given 运动 based on percentage of total spend
//Note: if the cost of a 运动 is $0 mtd, the 预算 is not changed.
function _change_spend(perc_to_change,my_tot_cost) {
  var camp_iter = (LABEL == '') ? AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .get() :
                                  AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .withCondition("LabelNames CONTAINS_ANY ['"+LABEL+"']")
                                    .get();
   
  while(camp_iter.hasNext()) {
    var camp = camp_iter.next();
    var camp_cost = camp.getStatsFor(TIMEFRAME).getCost();
    var perc_of_total = Math.round(camp_cost/my_tot_cost*SIG_FIGS)/SIG_FIGS;
    //If there is no cost for the 运动, let's not change it.
    var to_change = (perc_of_total) ? (perc_of_total*perc_to_change) : 0;
    camp.setBudget(camp.getBudget()*(1+to_change));
  }
}
 
// Resets the 预算 unevenly
function _reset_budgets() {
  var camp_budget_map = _pull_campaign_data_from_spreadsheet();
  var camp_iter = (LABEL == '') ? AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .get() :
                                  AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .withCondition("LabelNames CONTAINS_ANY ['"+LABEL+"']")
                                    .get();
  while(camp_iter.hasNext()) {
    var camp = camp_iter.next();
    if(camp_budget_map[camp.getName()]) {
      camp.setBudget(camp_budget_map[camp.getName()]/30.5);
    } else {
      camp.setBudget(DEFAULT_BUDGET);
    }
  }
}
 
function _pull_campaign_data_from_spreadsheet() {
  var 电子表格 = getSpreadsheet(SPREADSHEET_URL);
  var sheet = 电子表格.getActiveSheet();
  var data = sheet.getRange("A:B").getValues();
  if(data[0][0] == "") {
    //This 意思s this is the first run and we should populate the data.
    _populate_spreadsheet(sheet);
    data = sheet.getRange("A:B").getValues();
  }
  var 运动_budget_map = {};
  for(var i in data) {
    if(i == 0) { continue; } //ignore the header
    if(data[i][0] == "") { break; } //stop when there is no more data
    campaign_budget_map[data[i][0]] = parseFloat(data[i][1]);
  }
  return 运动_budget_map;
}
 
function _pull_budget_data_from_spreadsheet() {
  var 电子表格 = getSpreadsheet(SPREADSHEET_URL);
  var sheet = 电子表格.getActiveSheet();
  var data = sheet.getRange("A:B").getValues();
  if(data[0][0] == "") {
    //This 意思s this is the first run and we should populate the data.
    _populate_spreadsheet(sheet);
    data = sheet.getRange("A:B").getValues();
  }
  var tot_budget = 0;
  for(var i in data) {
    if(i == 0) { continue; } //ignore the header
    if(data[i][1] == "") { break; } //stop when there is no more data
    tot_budget += parseFloat(data[i][1]);
  }
  return tot_budget;
}
 
function _populate_spreadsheet(sheet) {
  sheet.clear();
  sheet.appendRow(['Campaign Name','Monthly Budget']);
  var camp_iter = (LABEL == '') ? AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .get() :
                                  AdWordsApp.campaigns()
                                    .withCondition("Status = ENABLED")
                                    .withCondition("LabelNames CONTAINS_ANY ['"+LABEL+"']")
                                    .get();
  while(camp_iter.hasNext()) {
    var camp = camp_iter.next();
    sheet.appendRow([camp.getName(),(camp.getBudget()*30.5)]);
  }
}
 
function getSpreadsheet(spreadsheetUrl) {
  return SpreadsheetApp.openByUrl(spreadsheetUrl);
}

2013年3月18日,星期一

动态调整广告系列预算

UPDATE 2013-04-05:此脚本有更新版本。看看这个。 v2.0.

更新2013-04-07:非常感谢FoxSUP帮助我跟踪更新预算的问题。修复了第78行,将当前预算乘以1 + to_change,而不仅仅是to_change。还修复了计算更改的错误(第76行)。

这是读者的请求:
我管理着许多小型企业PPC帐户,其中一些帐户有多个广告系列,并且它们通常具有相对较小的每月点击预算。我正在寻找一种方法来暂停所有广告系列,前提是整个帐户自一个月至今已花费了一定金额。

实际上,这是一个非常容易组合的脚本。下面是一个脚本,将执行此操作。您可以在脚本的开头设置MONTHLY_BUDGET,并每天在您的帐户上运行此脚本。一旦这些广告系列的总费用高于指定的预算,它将暂停该帐户中的所有广告系列。

然后,在下个月的第一天,它将再次启用这些广告系列。如果您未对以下脚本进行任何更改,则只需执行此操作。但是,让我们更进一步。

实际上,您可以使用脚本来获取和设置广告系列预算。假设您的每月预算是$ 100,但是您要确保您的广告在整个月中的投放量都没有变化。我在下面添加了一个名为_adjust_campaign_budget()的函数,可以通过脚本顶部的标志ADJUST_BUDGETS启用该函数。

然后,脚本将尝试计算广告系列的运行率,以确定您是否要满足预算。如果您要结束,它将降低每个广告系列的预算(按广告系列费用加权),从而使您实现目标。如果您的支出不足,它还会尝试增加您的广告系列预算,以使您达到目标。我还添加了一个_reset_budgets()函数,该函数在每月的第一天被调用。如果您更频繁地运行此脚本,则应启用代码以检查是否是该月第一天的第一个小时。

现在可以理解,此脚本带有一些注意事项。 该脚本可能使您花费很多钱。 我确信我正在测试的广告系列比您的广告系列要小得多,而且预算可以匹配。

谢谢,
拉斯

/******************************************
* Keep Your Campaigns In Budget
* Version 1.1
* ChangeLog v1.1 
*   - cleaned up code
*   - 广告 ded ability for any 日期
* Created By: 拉斯 Savage
* FreeAdWordsScripts.com
******************************************/
// Let's set some constants
var MONTHLY_BUDGET = 5000.00;

//If you want to work with a monthly 预算, leave START_DATE and END_DATE blank.
var TIMEFRAME = "THIS_MONTH";
//But if you want to work with a specific timeframe, fill these in.
//Use the format yyyyMMdd, so for Jan 12th, 2014, you would put 20140112.
var START_DATE = '';
var END_DATE = '';
 
//Set this to true if you want to 调整预算 or
//keep set to false if you want to just 暂停 all the 运动s
//when you hit your 预算
var ADJUST_BUDGETS = false;
var DECIMAL_PLACES = 3;
 
function main() {
  var totalCostMTD = getTotalCost();
  var isFirstOfTheMonth = ((new Date()).getDate() == 1);
  if(START_DATE && END_DATE) {
    var today = new Date();
    today.setHours(0,0,0,0);
    var startDate = new Date(START_DATE.substring(0,4),
                             parseFloat(START_DATE.substring(4,6))-1,
                             START_DATE.substring(6,8));
    isFirstOfTheMonth = (startDate.getTime() == today.getTime());
  }
  //if you run this script more than once per day, uncomment the next line
  //isFirstOfTheMonth = (isFirstOfTheMonth && ((new Date()).getHour() == 0));
  Logger.log("Total cost: " + totalCostMTD + 
           ", Monthly 预算:" + MONTHLY_BUDGET +
           ", isFirstOfTheMonth: "+isFirstOfTheMonth);
   
  if(ADJUST_BUDGETS) {
    if(isFirstOfTheMonth) {
      resetBudgets();
    } else {
      adjustCampaignBudget(totalCostMTD);
    }
  } else {
    if(totalCostMTD >= MONTHLY_BUDGET) {
      //If we have hit the limit, 暂停 all 广告
      enableOrDisableCampaigns(true);
    } else {
      // let's check if it's the first day of the month
      if((new Date()).getDate() == 1) {
        //enable all the 运动s
        enableOrDisableCampaigns(false);
      }
    }
  }
}
 
// Returns the total cost for the set TIMEFRAME
function getTotalCost() {
  var campIter = AdWordsApp.campaigns().get();
   
  var totalCost = 0;
  while(campIter.hasNext()) {
    if(START_DATE && END_DATE) {
      totalCost += campIter.next().getStatsFor(START_DATE,END_DATE).getCost();
    } else {
      totalCost += campIter.next().getStatsFor(TIMEFRAME).getCost();
    }
  }
  return totalCost;
}
 
// Enables or Disables All Campaigns In Account
function enableOrDisableCampaigns(shouldDisable) {
  var campIter = AdWordsApp.campaigns().get();
  while(campIter.hasNext()) { 
    if(shouldDisable) { 
      campIter.next().pause(); 
    } else { 
      campIter.next().enable(); 
    }
  }
}
 
// Calculates 运行速度 and 广告 justs 运动 竞标 as needed.
function 广告 justCampaignBudget(myTotalCost) {
  var today = new Date();
  // Accounting for December
  var eom;
  if(START_DATE && END_DATE) {
    eom = new Date(END_DATE.substring(0,4),
                   parseFloat(END_DATE.substring(4,2))-1,
                   END_DATE.substring(6,2));
  } else {
    eom = (today.getMonth() == 11) ? new Date(today.getFullYear()+1,0,1) : 
                                     new Date(today.getFullYear(),today.getMonth()+1,1);
  }
  var daysLeft = Math.round((eom-today)/1000/60/60/24);
  var daysSpent;
  if(START_DATE && END_DATE) {
    var startDate = new Date(START_DATE.substring(0,4),
                             parseFloat(START_DATE.substring(4,2))-1,
                             START_DATE.substring(6,2));
    daysSpent = Math.round((today-startDate)/1000/60/60/24);
  } else {
    daysSpent = today.getDate();
  }
  var runRate = round(myTotalCost/daysSpent);
  var projectedTotal = myTotalCost + (runRate * daysLeft);
  var percOver = round((MONTHLY_BUDGET-projectedTotal)/projectedTotal);
   
  changeSpend(percOver,myTotalCost);
}
 
//Adjusts the 预算 for a given 运动 based on percentage of total spend
//Note: if the cost of a 运动 is $0 mtd, the 预算 is not changed.
function changeSpend(percToChange,myTotalCost) {
  var campIter = AdWordsApp.campaigns().withCondition("Status = ENABLED").get();
   
  while(campIter.hasNext()) {
    var camp = campIter.next();
    var campCost = (START_DATE && END_DATE) ? camp.getStatsFor(START_DATE,END_DATE).getCost()
                                            : camp.getStatsFor(TIMEFRAME).getCost();
    var percOfTotal = round(campCost/myTotalCost);
    //If there is no cost for the 运动, let's not change it.
    var toChange = (percOfTotal) ? (percOfTotal*percToChange) : 0;
    camp.setBudget(camp.getBudget()*(1+toChange));
  }
}
 
// Resets the 预算 evenly across all 运动s
function resetBudgets() {
  Logger.log('Resetting 预算s 在 the first of the period.');
  var campIter = AdWordsApp.campaigns().withCondition("Status = ENABLED").get();
  var campCount = 0;
  while(campIter.hasNext()) {
    campCount++;
    campIter.next();
  }
  campIter = AdWordsApp.campaigns().withCondition("Status = ENABLED").get();
  while(campIter.hasNext()) {
    campIter.next().setBudget(MONTHLY_BUDGET/campCount);
  }
}

// A helper function to make rounding a little easier
function round(value) {
  var decimals = Math.pow(10,DECIMAL_PLACES);
  return Math.round(value*decimals)/decimals;
}