显示带有标签的帖子 广告. 显示所有帖子
显示带有标签的帖子 广告. 显示所有帖子

2013年10月20日,星期日

使用Excel管理您的AdWords广告

自上一篇文章以来,Google一直在忙于发布AdWords脚本的大量新功能。 其中之一就是可以直接与您的Google云端硬盘文件进行交互的功能。 这之所以令人赞叹,有几个原因,其中一个原因是,它使您可以通过电子表格管理您的帐户,这些电子表格会每小时自动同步回您的Google AdWords帐户。

有机会利用Excel电子表格的功能来创建关键字,管理广告,广告组或广告附加信息。还是不服气?您还可以每天将所有帐户指标自动发送到Google云端硬盘,并自动下载到计算机上。

因此,我想我将演示如何使用此新功能来管理广告。

您需要做的第一件事是 将Google云端硬盘安装到您的计算机上。这很容易做到,但确实需要计算机的管理员权限。 如果您现在无法安装,则无需担心。 您可以通过浏览器更新Google云端硬盘中的文件来管理站点链接。

现在看下面的脚本。您应该设置一些配置选项。 FOLDER_PATH 是要在其中存储这些文件的文件夹的路径。 例如,“ AdWords /广告素材”。如果文件夹路径不存在,此脚本将为您创建它。

下一个参数是FILE_NAME,它将是广告素材数据将存储在其中的文件。在此示例中,该文件必须写为.CSV。 Google使得使用解析CSV文件非常容易 Utilities.parseCsv函数.

使用此脚本,您可以使用Excel从csv文件中更改标题,说明,URL,状态和设备首选项。 然后,只需将文件保存回Google云端硬盘,下一次脚本运行(每天或每小时),您的更改就会反映出来。

通过Excel而不是通过某些UI可以更容易地管理AdWords的哪些其他功能?

谢谢,
拉斯

/******************************************
 * Manage AdWords 广告 Using Excel
 * Version 1.0
 * Author: 拉斯 Savage
 * FreeAdWordsScripts.com
 ****************************************/
var FOLDER_PATH = 'AdWordsData'; //The path where the file will be stored on GDrive
var FILE_NAME = 'creatives.csv'; //The name of the file on GDrive
 
var INCLUDE_STATS = true; // Set to false to 去掉 统计资料 from the file
var DATE_RANGE = 'LAST_30_DAYS'; //The date range for the 统计资料
 
var INCLUDE_PAUSED_ADS = true; //Set to false to only report on active 广告
var DELETE_ORIGINAL_ADS = true; //When set to false, the original 广告 will be 暂停d instead of 删除d
 
function main() {
  var file = getFile(FILE_NAME,FOLDER_PATH);
  if(!file) {
    file = 创造NewFile(FILE_NAME,FOLDER_PATH,buildCreativesFile());
    return;
  }
  
  var fileContent = file.getBlob().getDataAsString();
  var 广告素材 = {};
  if(fileContent) {
    广告素材 = parseFileContent(fileContent);
  }
  
  var creativeIter = getAdIterator();
  while(creativeIter.hasNext()) {
    var creative = creativeIter.next();
    var 广告 Id = creative.getId();
    if(creatives[adId]) {
      //ok we found the 广告 .
      //Checking status
      var isEnabledFile = (creatives[adId]['Status'] === 'Enabled');
      if(creative.isEnabled() != isEnabledFile) {
        if(isEnabledFile) { 
          creative.enable(); 
        } else { 
          creative.pause(); 
        }
      }
      
      if(hadAdChanged(creative,creatives[adId])) {
        if(DELETE_ORIGINAL_ADS) {
          creative.remove();
        } else {
          creative.pause();
        }
        创造NewAd(creative.getAdGroup(),creatives[creative.getId()]);
      }
    }
  }
  file.setContent(buildCreativesFile());
}
 
//Helper function to 创造 a new 广告 
function 创造NewAd(ag,newAd) {
  var optArgs = {
    isMobilePreferred: (newAd['Device'] === 'Mobile') ? true : false
  };
  ag.createTextAd(newAd['Headline'],newAd['Desc1'],newAd['Desc2'],newAd['DisplayUrl'],newAd['DestinationUrl'],optArgs);
}
 
//This checks to see if the 广告  has been changed
function hadAdChanged(ad,oldAd) {
  var newAdText = [ad.getHeadline(),
                   广告 .getDescription1(),
                   广告 .getDescription2(),
                   广告 .getDisplayUrl(),
                   广告 .getDestinationUrl(),
                   (ad.isMobilePreferred()) ? 'Mobile' : 'Desktop'].join('~~!~~');
  var oldAdText = [oldAd['Headline'],
                   oldAd['Desc1'],
                   oldAd['Desc2'],
                   oldAd['DisplayUrl'],
                   oldAd['DestinationUrl'],
                   oldAd['Device']].join('~~!~~');
  Logger.log(newAdText);
  Logger.log(oldAdText);
  return (newAdText !== oldAdText);
}
 
//This builds the 广告素材 file from all the 广告 in the account.
function buildCreativesFile() {
  var report = getReportColumns();
  var creativeIter = getAdIterator();
  while(creativeIter.hasNext()) {
    var creative = creativeIter.next();
    report += getReportRow(creative);
  }
  return report;
}
 
//This returns the 广告  iterator based on options.
function getAdIterator() {
  var 广告 Selector = AdWordsApp.ads().withCondition("Type = 'TEXT_AD'"); 
  if(!INCLUDE_PAUSED_ADS) {
    广告 Selector = 广告 Selector.withCondition('CampaignStatus = ENABLED')
                           .withCondition('AdGroupStatus = ENABLED')
                           .withCondition('Status = ENABLED');
  }
  return 广告 Selector.get();
}
 
//This returns a CSV fow for the report.
function getReportRow(ad) {
  var retVal = [
    广告 .getId(),
    广告 .getCampaign().getName(),(ad.getCampaign().isPaused()) ? 'Paused' : 'Enabled',
    广告 .getAdGroup().getName(),(ad.getAdGroup().isPaused()) ? 'Paused' : 'Enabled',
    广告 .getHeadline(),
    广告 .getDescription1(),
    广告 .getDescription2(),
    广告 .getDisplayUrl(),
    广告 .getDestinationUrl(),
    (ad.isPaused()) ? 'Paused' : 'Enabled',
    (ad.isMobilePreferred()) ? 'Mobile' : 'Desktop',
  ];
  if(INCLUDE_STATS) {
    var 统计资料 = 广告 .getStatsFor(DATE_RANGE);
    retVal = retVal.concat([
      统计资料.getImpressions(),
      统计资料.getClicks(),
      统计资料.getCtr(),
      统计资料.getCost(),
      统计资料.getAverageCpc(),
      统计资料.getConversions(),
      统计资料.getConversionRate(),
      统计资料.getAveragePageviews(),
      统计资料.getAveragePosition(),
      统计资料.getAverageTimeOnSite(),
      统计资料.getBounceRate()
      ]);
  }
  return '"' + retVal.join('","') + '"\n';
}
 
//This returns the column headings used for the report.
function getReportColumns() {
  var columnHeadings = [
    'AdId',
    'CampaignName','CampaignStatus',
    'AdGroupName','AdGroupStatus',
    'Headline',
    'Desc1',
    'Desc2',
    'DisplayUrl',
    'DestinationUrl',
    'Status',
    'Device'];
  if(INCLUDE_STATS) {
    columnHeadings = columnHeadings.concat([
      'Impressions',
      'Clicks',
      'Ctr',
      'Cost',
      'Cpc',
      'Conversions',
      'ConversionRate',
      'AveragePageviews',
      'AvgPosition',
      'AvgTimeOnSite',
      'BounceRate'
      ]);
  }
  return '"' + columnHeadings.join('","') + '"\n';
}   
 
//This function parses the 广告素材 file into an object for processing
function parseFileContent(fileContent) {
  var headers = [];
  var idHash = {};
  var data = Utilities.parseCsv(fileContent);
  for(var i in data) {
    var cells = data[i]
    if(cells.length == 1) { continue; } //skip any empty rows
    if(i == 0) { 
      headers = cells; 
    } else {
      var rowMap = {};
      for(var x in headers) {
        headers[x] = headers[x];
        cells[x] = cells[x];
        rowMap[headers[x]] = cells[x];
      }
      idHash[rowMap['AdId']] = rowMap;
    }
  }
  return idHash;
}
 
//This function gets the file from GDrive
function getFile(fileName,folderPath) {
  var folder = getFolder(folderPath);
  if(folder.getFilesByName(fileName).hasNext()) {
    return folder.getFilesByName(fileName).next();
  } else {
    return null;
  }
}
 
//This function 创造s a new file on GDrive
function 创造NewFile(fileName,folderPath,content) {
  if(!fileName) { throw 'createNewFile: Missing filename.'; }
  var folder = getFolder(folderPath);
  
  return folder.createFile(fileName, content);
}
 
//This function finds the folder for the file and 创造s folders if needed
function getFolder(folderPath) {
  var folder = DriveApp.getRootFolder();
  if(folderPath) {
    var pathArray = folderPath.split('/');
    for(var i in pathArray) {
      var folderName = pathArray[i];
      if(folder.getFoldersByName(folderName).hasNext()) {
        folder = folder.getFoldersByName(folderName).next();
      } else {
        folder = folder.createFolder(folderName);
      }
    }
  }
  return folder;
}

2013年7月30日,星期二

确定何时创建广告,广告组,关键字或广告系列

知道何时创建广告(或实体) 不可能使用脚本。根本不会在AdWords中跟踪该信息。其次,最好的办法是找出您的广告何时首次开始获得展示,并假设它是在创建的时候(如果创建了广告,但没人看到它,那它确实存在吗?)。

因此,为了帮助我跟踪何时 广告 实体已创建,我将以下脚本放在一起以将标签应用于我 广告 具有第一印象日期的实体。这样我就能知道 广告 我创建的实体,并确保不要对太小的内容采取任何措施。我也可以对所有 广告 只需选择正确的标签,即可在AdWords用户界面中相对容易地在一天中建立实体。

谢谢,
拉斯



/**************************************
* Track Entity Creation Date
* Version 1.4
* Changelog v1.4
*  - Removed apiVersion from 报告 呼叫
* Changelog v1.3
*  - Updated script to handle all entities
* Changelog v1.2
*  - Fixed an issue with comparing 日期
* ChangeLog v1.1
*  - Updated logic to work with larger accounts
* Created By: 拉斯 Savage
* http://www.FreeAdWordsScripts.com
**************************************/
//All my 标签 will start with this. For example: Created:2013-05-01
var LABEL_PREFIX = 'Created:';
var DAYS_IN_REPORT = 30;
var ENTITY = 'ad'; //or 广告群组 or 关键词 or 运动
 
function main() {
  //First we get the impression history of our 实体
  var ret_map = getImpressionHistory();
  //Then we apply our 标签
  applyLabels(ret_map);
}
 
//Function to apply 标签 to the 广告 in an account
function applyLabels(ret_map) {
  var iter;
  if(ENTITY === 'campaign') { iter = AdWordsApp.campaigns().get(); }
  if(ENTITY === 'adgroup') { iter = AdWordsApp.adGroups().get(); }
  if(ENTITY === 'ad') { iter = AdWordsApp.ads().get(); }
  if(ENTITY === 'keyword') { iter = AdWordsApp.keywords().get(); }
  
  while(iter.hasNext()) {
    var 实体 = iter.next();
    var id = 实体.getId();
    if(ret_map[id]) {
      var 标签_name = LABEL_PREFIX+Utilities.formatDate(ret_map[id], AdWordsApp.currentAccount().getTimeZone(), "yyyy-MM-dd");
      createLabelIfNeeded(label_name);
      entity.applyLabel(label_name);
    }
  }
}
 
//This is a helper function to 创造 the 标签 if it does not already exist
function 创造LabelIfNeeded(name) {
  if(!AdWordsApp.labels().withCondition("Name = '"+name+"'").get().hasNext()) {
    AdWordsApp.createLabel(name);
  }
}
 
//A helper function to find the date days ago
function getDateDaysAgo(days) {
  var the_past = new Date();
  the_past.setDate(the_past.getDate() - days);
  return Utilities.formatDate(the_past,AdWordsApp.currentAccount().getTimeZone(),"yyyyMMdd");
}
 
//A helper function to compare 日期.
//Copied from: http://goo.gl/uW48a
function diffDays(firstDate,secondDate) {
  var oneDay = 24*60*60*1000; // hours*minutes*seconds*milliseconds
  return Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay))); 
}
 
function getImpressionHistory() {
  var API_VERSION = { includeZeroImpressions : false };
  var first_date = new Date('10/23/2000');
  var max_days_ago = diffDays(first_date,new Date());
  var cols = ['Date','Id','Impressions'];
  var report = { 
    'campaign' : 'CAMPAIGN_PERFORMANCE_REPORT',
    'adgroup' : 'ADGROUP_PERFORMANCE_REPORT',
    'ad' : 'AD_PERFORMANCE_REPORT',
    'keyword' : 'KEYWORDS_PERFORMANCE_REPORT'}[ENTITY];
  var ret_map = {};
  var prev_days_ago = 0;
  for(var i = DAYS_IN_REPORT; i < max_days_ago; i+=DAYS_IN_REPORT) {
    var start_date = getDateDaysAgo(i);
    var end_date = getDateDaysAgo(prev_days_ago);
    var date_range = start_date+','+end_date;
    Logger.log('Getting data for ' + date_range);
    var query = ['select',cols.join(','),'from',report,'during',date_range].join(' ');
    var report_iter = AdWordsApp.report(query, API_VERSION).rows();
    if(!report_iter.hasNext()) { Logger.log('No more impressions found. Breaking.'); break; } // no more entries
    while(report_iter.hasNext()) { 
      var row = report_iter.next();
      if(ret_map[row['Id']]) {
        var [year,month,day] = (row['Date']).split('-');
        var from_row = new Date(year, parseFloat(month)-1, day);
        var from_map = ret_map[row['Id']];
         
        if(from_row < from_map) {
          ret_map[row['Id']] = from_row;
        }
      } else {
        var [year,month,day] = (row['Date']).split('-');
        ret_map[row['Id']] = new Date(year, parseFloat(month)-1, day);
      }
    }
    prev_days_ago = i;
  }
  return ret_map;
}

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年6月17日,星期一

查找关键字,广告组和广告中的异常

2013年7月23日更新:添加了向广告添加标签的功能。这可能对创意测试很有帮助。

在一个 最近来自SearchEngineLand的帖子,拉里·金(Larry Kim)希望PPC经理不要再偷懒。除了链接诱饵,他还有一些优点。我认为花费在倾倒客户电子表格上的大部分时间实际上是在试图回答“异常在哪里?”这个简单的问题。

异常是关键字或广告组,其效果似乎与同一个广告组或广告系列中的兄弟姐妹不同。也许您有一个包含15个关键字和一个或两个关键字的广告组,似乎获得了几乎所有的点击。或者,也许您只是拥有一个广告组,似乎正在占用预算的很大一部分,而您想对其进行更多控制。在这两种情况下,您都需要某种方法来快速确定要对哪些关键字或广告组进行操作。

因此,我创建了以下脚本来帮助我做到这一点。它内含一些统计信息,可以计算一组实体(广告组或关键字)的均值和标准差。然后,我将标签应用于似乎与均值相差两个标准偏差以上的任何实体,这表明该实体的性能要比其同级产品更好或更差。这样,我可以在自己的帐户中轻松地对这些实体采取措施。

该脚本还将每天向您发送一封电子邮件,其中包含它认为是异常的实体的摘要。您的目标是通过将这些问题转移到自己的广告系列和广告组中,或者甚至完全消除它们(可能是负面的)来解决这些问题。

目前,脚本将检查AdWordsApp.stats对象中可用的每个指标。可以轻松对其进行修改,以检查诸如每次转化费用或每次展示利润。您将在下面的代码中看到,您可以在其中删除也不感兴趣的统计信息。

需要警告的一点是,我并没有声称自己是统计学家,所以这可能不是一种看待事物的有效方法。希望它可以帮助您快速找到帐户中的问题并加以解决,以便您可以将更多时间花在懒惰上:)

另外,我欢迎您对此脚本提出意见和建议。对其他人有用吗?

谢谢,
拉斯

/**************************************
* Find the Anomalies
* Created By: 拉斯 Savage
* Version: 1.2
* Changelog v1.2
*  - Fixed divide by 0 错误
*  - Changed SIG_FIGS to DECIMAL_PLACES
* Changelog v1.1
*  - Added ability to tag 广告  anomalies as well
* FreeAdWordsScripts.com
**************************************/
var DATE_RANGE = 'LAST_30_DAYS';
var DECIMAL_PLACES = 3;
var STANDARD_DEVIATIONS = 2;
var TO = ['[email protected]_domain.com'];
 
function main() {
  // This will 广告 d 标签 to and send 电子邮件s about 广告群组, 关键字 and 广告. Remove any if you like.
  var levels_to_tag = ['adgroup','keyword','ad'];
  for(var x in levels_to_tag) {
    var report = getContentRows(levels_to_tag[x]);
    var 实体_map = buildEntityMap(levels_to_tag[x]);
    for(var parent_id in 实体_map) {
      var child_list = 实体_map[parent_id];
      var 统计资料_list = Object.keys(child_list[0].stats);
      for(var i in 统计资料_list) {
        var 意思 = getMean(child_list,stats_list[i]);
        var stand_dev = getStandardDev(child_list,mean,stats_list[i]);
        var 标签_name = 统计资料_list[i]+"_anomaly";
        report += 广告 dLabelToAnomalies(child_list,mean,stand_dev,stats_list[i],label_name,levels_to_tag[x]);
      }
    }
    sendResultsViaEmail(report,levels_to_tag[x]);
  }
}
  
//Takes a report and the level of 报告 and sends and 电子邮件
//with the report as an 在tachment.
function sendResultsViaEmail(report,level) {
  var rows = report.match(/\n/g).length - 1;
  if(rows == 0) { return; }
  var options = { 附件: [Utilities.newBlob(report, 'text/csv', level+"_anomalies_"+_getDateString()+'.csv')] };
  var 电子邮件_body = "There are " + rows + " " + level + "s that have abnormal performance. See 在tachment for details.";
  var subject = 'Abnormal ' + _initCap(level) + ' Entities Report - ' + _getDateString();
  for(var i in TO) {
    MailApp.sendEmail(TO[i], subject, 电子邮件_body, options);
  }
}
  
//Helper function to return a single row of the report formatted correctly
function toReportRow(entity,level,label_name) {
  var ret_val = [AdWordsApp.currentAccount().getCustomerId(),
                 entity.getCampaign().getName()];
  ret_val.push( (level == 'adgroup') ? 实体.getName() : 实体.getAdGroup().getName() );
  if(level == 'keyword') {
    ret_val = ret_val.concat([entity.getText(),entity.getMatchType()]); 
  } else if(level == 'ad') {
    ret_val = ret_val.concat([entity.getHeadline(),entity.getDescription1(),entity.getDescription2(),entity.getDisplayUrl()]); 
  }
  ret_val.push(label_name);
  return '"' + ret_val.join('","') + '"\n';
}
  
//Helper function to return the column headings for the report
function getContentRows(level) {
  var ret_val = ['AccountId','CampaignName','AdGroupName'];
  if(level == 'keyword') {
    ret_val = ret_val.concat(['KeywordText','MatchType']); 
  } else if(level == 'ad') {
    ret_val = ret_val.concat(['Headline','Description1','Description2','DisplayUrl']);
  }
  ret_val.push('LabelName');
  return '"' + ret_val.join('","') + '"\n';
}
  
//Function to 广告 d the 标签 to the entities based on the 标准偏差  and 意思.
//It returns a CSV formatted string for 报告
function 广告 dLabelToAnomalies(entites,mean,sd,stat_key,label_name,level) {
  createLabelIfNeeded(label_name);
  var report = '';
  for(var i in entites) {
    var 实体 = entites[i]['entity'];
    var deviation = Math.abs(entites[i]['stats'][stat_key] - 意思);
    if(sd != 0 && deviation/sd >= STANDARD_DEVIATIONS) {
      entity.applyLabel(label_name);
      report += toReportRow(entity,level,label_name);
    } else {
      entity.removeLabel(label_name);
    }
  }
  return report;
}
  
//This is a helper function to 创造 the 标签 if it does not already exist
function 创造LabelIfNeeded(name) {
  if(!AdWordsApp.labels().withCondition("Name = '"+name+"'").get().hasNext()) {
    AdWordsApp.createLabel(name);
  }
}
  
//This function returns the 标准偏差  for a set of entities
//The stat key determines which stat to calculate it for
function getStandardDev(entites,mean,stat_key) {
  var total = 0;
  for(var i in entites) {
    total += Math.pow(entites[i]['stats'][stat_key] - 意思,2);
  }
  if(Math.sqrt(entites.length-1) == 0) {
    return 0;
  }
  return round(Math.sqrt(total)/Math.sqrt(entites.length-1));
}
  
//Returns the 意思 (average) for the set of entities
//Again, stat key determines which stat to calculate this for
function getMean(entites,stat_key) {
  var total = 0;
  for(var i in entites) {
    total += entites[i]['stats'][stat_key];
  }
  if(entites.length == 0) {
    return 0;
  }
  return round(total/entites.length);
}
  
//This function returns a map of the entities that I am processing.
//The format for the map can be found on the first line.
//It is 意思t to work on AdGroups and Keywords
function buildEntityMap(entity_type) {
  var map = {}; // { parent_id : [ { 实体 : 实体, 统计资料 : 实体_stats } ], ... }
  var iter = getIterator(entity_type);
  while(iter.hasNext()) {
    var 实体 = iter.next();
    var 统计资料 = 实体.getStatsFor(DATE_RANGE);
    var 统计资料_map = getStatsMap(stats);
    var parent_id = getParentId(entity_type,entity);
    if(map[parent_id]) { 
      map[parent_id].push({entity : 实体, 统计资料 : 统计资料_map});
    } else {
      map[parent_id] = [{entity : 实体, 统计资料 : 统计资料_map}];
    }
  }
  return map;
}
  
//Given an 实体 type (adgroup or 关键词) this will return the parent id
function getParentId(entity_type,entity) {
  switch(entity_type) {
    case 'adgroup' :
      return 实体.getCampaign().getId();
    case 'keyword':
      return 实体.getAdGroup().getId();
    case 'ad':
      return 实体.getAdGroup().getId();
  }
}
  
//Given an 实体 type this will return the iterator for that.
function getIterator(entity_type) {
  switch(entity_type) {
    case 'adgroup' :
      return AdWordsApp.adGroups().forDateRange(DATE_RANGE).withCondition("Impressions > 0").get();
    case 'keyword' :
      return AdWordsApp.keywords().forDateRange(DATE_RANGE).withCondition("Impressions > 0").get();
    case 'ad' :
      return AdWordsApp.ads().forDateRange(DATE_RANGE).withCondition("Impressions > 0").get();
  }
}
  
//This returns a map of all the 统计资料 for a given 实体.
//You can 评论 out the things you don't really care about.
function getStatsMap(stats) {
  return { // You can 评论 these out as needed.
          avg_cpc : 统计资料.getAverageCpc(),
          avg_cpm : 统计资料.getAverageCpm(),
          avg_pv : 统计资料.getAveragePageviews(),
          avg_pos : 统计资料.getAveragePosition(),
          avg_tos : 统计资料.getAverageTimeOnSite(),
          bounce : 统计资料.getBounceRate(),
          clicks : 统计资料.getClicks(),
          cv : 统计资料.getConversionRate(),
          conv : 统计资料.getConversions(),
          cost : 统计资料.getCost(),
          ctr : 统计资料.getCtr(),
          imps : 统计资料.getImpressions()
         };
}
  
//Helper function to format todays date
function _getDateString() {
  return Utilities.formatDate((new Date()), AdWordsApp.currentAccount().getTimeZone(), "yyyy-MM-dd");
}
  
//Helper function to capitalize the first letter of a string.
function _initCap(str) {
  return str.replace(/(?:^|\s)\S/g, function(a) { return a.toUpperCase(); });
}

// 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;
}

2013年4月18日,星期四

在特定日期暂停或启用广告系列,关键字或广告

2013年12月13日更新:还添加了处理广告的功能。

我在论坛上看到过一些问题,询问在特定日期启用或暂停关键字。使用标签和脚本非常简单。以下脚本将在您的帐户中运行,并查找标记为“暂停于 ”或“启用 然后执行该操作。如果您只想使用日期,则可以将两个前缀值设置为空字符串(“”)。日期的格式为YYYY-MM-DD(2013-05-01)。

谢谢,
拉斯

/**************************************************
* Pause or Enable Campaigns, Keywords or 广告 on a Given Date
* Version 1.2
* Changelog v1.2 - Added ability to 暂停 Campaigns
* Changelog v1.1 - Added ability to run on 广告
* Created By: 拉斯 Savage
* FreeAdWordsScripts.com
**************************************************/
var ENTITY = 'Keyword'; //or Ad or Campaign
var PAUSE_PREFIX = "Pause on "; //look for 标签 "Pause on 2013-04-11"
var ENABLE_PREFIX = "Enable on "; //look for 标签 "Enable on 2013-04-11"

  
function main() {
  var todayStr = Utilities.formatDate(new Date(), AdWordsApp.currentAccount().getTimeZone(), "yyyy-MM-dd");
  var 暂停Str = PAUSE_PREFIX+todayStr;
  var enableStr = ENABLE_PREFIX+todayStr;
  Logger.log("Looking for 标签: " + [pauseStr,enableStr].join(' and '));
   
  var 标签Array = buildLabelArray(pauseStr,enableStr);
   
  if(labelsArray.length > 0) { 
    var 标签Str = "['" + 标签Array.join("','") + "']";
    var 实体Iter;
    if(ENTITY === 'Keyword') {
      实体Iter = AdWordsApp.keywords().withCondition("LabelNames CONTAINS_ANY "+labelsStr).get();
    } else if(ENTITY === 'Ad') {
      实体Iter = AdWordsApp.ads().withCondition("LabelNames CONTAINS_ANY "+labelsStr).get();
    } else if(ENTITY === 'Campaign') {
      实体Iter = AdWordsApp.campaigns().withCondition("LabelNames CONTAINS_ANY "+labelsStr).get();
    } else {
      throw 'Invaid ENTITY type. Should be Campaign, Keyword or Ad. ENTITY:'+ENTITY;
    }
     
    while(entityIter.hasNext()) {
      var 实体 = 实体Iter.next();
      pauseEntity(entity, 暂停Str);
      enableEntity(entity, enableStr);
    }
  }
}
 
//Helper function to build a list of 标签 in the account
function buildLabelArray(pauseStr,enableStr) {
  var 标签Array = [];
  try {
    var 标签Iter = AdWordsApp.labels().withCondition("Name IN ['"+pauseStr+"','"+enableStr+"']").get();
    while(labelIter.hasNext()) {
      标签Array.push(labelIter.next().getName());
    }
    return 标签Array;
  } catch(e) {
    Logger.log(e);
  }
  return [];
}
 
//Helper function to 暂停 entities
function 暂停Entity(entity, 暂停Str) {
  var 标签Iter = 实体.labels().withCondition("Name = '"+pauseStr+"'").get();
  if(labelIter.hasNext()) {
    实体.pause();
    实体.removeLabel(pauseStr);
  }
}
 
//Helper function to enable entities
function enableEntity(entity, enableStr) {
  var 标签Iter = 实体.labels().withCondition("Name = '"+enableStr+"'").get();
  if(labelIter.hasNext()) {
    实体.enable();
    实体.removeLabel(enableStr);
  }
}

2013年4月10日,星期三

报告帐户中的破损网址

注意:如果您正在寻找此脚本的版本以在MCC级别上运行,请签出 使用MCC级别脚本监视断开的链接.

更新时间:2013-05-20:基于读者的评论,该脚本现在仅检查活动的广告系列和广告组,并且仅检查每个网址一次。

更新时间:2013-04-28:基于读者的评论,我对该脚本进行了一些更新,包括将响应代码添加到电子邮件中并将结果格式化为附件。

它发生在我们最好的人身上。有时,我们会删除网站上的页面或更新链接,而忘记对我们的SEM帐户进行相应的更改。因此,今晚我整理了一个快速脚本来遍历您的所有广告和关键字,并创建一个包含以下内容的电子邮件报告: 找不到404 或一个 500服务器错误 响应码。您可以通过在脚本开头将它们添加到BAD_CODES数组中来轻松添加更多错误代码以进行检查。

谢谢,
拉斯

/****************************
* Find Broken Urls In Your Account
* Version 1.1
* ChangeLog v1.1
*  - Updated to only see Text 广告
* Created By: 拉斯 Savage
* FreeAdWordsScripts.com
****************************/
function main() {
  // You can 广告 d more if you want: http://goo.gl/VhIX
  var BAD_CODES = [404,500];
  var TO = ['[email protected]'/*,'[email protected]'*/];
  var SUBJECT = 'Broken Url Report - ' + _getDateString();
  var HTTP_OPTIONS = {
    muteHttpExceptions:true
  };
   
  //Let's look 在 广告 and 关键字 for 网址
  var iters = [
    //For Ad Level Urls
    AdWordsApp.ads()
      .withCondition("Status = 'ENABLED'")
      .withCondition("AdGroupStatus = 'ENABLED'")
      .withCondition("CampaignStatus = 'ENABLED'")
      .withCondition("Type = 'TEXT_AD'")
      .get(),
    //For Keyword Level Urls
    AdWordsApp.keywords()
      .withCondition("Status = 'ENABLED'")
      .withCondition("DestinationUrl != ''")
      .withCondition("AdGroupStatus = 'ENABLED'")
      .withCondition("CampaignStatus = 'ENABLED'")
      .get()
    ];
  
  var already_checked = {}; 
  var bad_entities = [];
  for(var x in iters) {
    var iter = iters[x];
    while(iter.hasNext()) {
      var 实体 = iter.next();
      if(entity.getDestinationUrl() == null) { continue; }
      var url = 实体.getDestinationUrl();
      if(url.indexOf('{') >= 0) {
        //Let's 去掉 the value track parameters
        url = url.replace(/\{[0-9a-zA-Z]+\}/g,'');
      }
      if(already_checked[url]) { continue; }
      var response_code;
      try {
        Logger.log("Testing url: "+url);
        response_code = UrlFetchApp.fetch(url, HTTP_OPTIONS).getResponseCode();
      } catch(e) {
        //Something is wrong here, we should know about it.
        bad_entities.push({e : 实体, code : -1});
      }
      if(BAD_CODES.indexOf(response_code) >= 0) {
        //This 实体 has an issue.  Save it for later. 
        bad_entities.push({e : 实体, code : response_code});
      }
      already_checked[url] = true;
    }
  }
  var column_names = ['Type','CampaignName','AdGroupName','Id','Headline/KeywordText','ResponseCode','DestUrl'];
  var 在tachment = column_names.join(",")+"\n";
  for(var i in bad_entities) {
    在tachment += _formatResults(bad_entities[i],",");
  }
  if(bad_entities.length > 0) {
    var options = { 附件: [Utilities.newBlob(attachment, 'text/csv', 'bad_urls_'+_getDateString()+'.csv')] };
    var 电子邮件_body = "There are " + bad_entities.length + " 网址 that are 破碎. See 在tachment for details.";
     
    for(var i in TO) {
      MailApp.sendEmail(TO[i], SUBJECT, 电子邮件_body, options);
    }
  }  
}
 
//Formats a row of results separated by SEP
function _formatResults(entity,SEP) {
  var e = 实体.e;
  if(typeof(e['getHeadline']) != "undefined") {
    //this is an 广告  实体
    return ["Ad",
            e.getCampaign().getName(),
            e.getAdGroup().getName(),
            e.getId(),
            e.getHeadline(),
            实体.code,
            e.getDestinationUrl()
           ].join(SEP)+"\n";
  } else {
    // and this is a 关键词
    return ["Keyword",
            e.getCampaign().getName(),
            e.getAdGroup().getName(),
            e.getId(),
            e.getText(),
            实体.code,
            e.getDestinationUrl()
           ].join(SEP)+"\n";
  }
}
 
//Helper function to format todays date
function _getDateString() {
  return Utilities.formatDate((new Date()), AdWordsApp.currentAccount().getTimeZone(), "yyyy-MM-dd");
}

2013年3月30日,星期六

根据您的棒球队的日程安排自动化广告

我知道现在每个人都将注意力集中在疯狂三月,但是棒球赛季的开幕日指日可待。我想知道是否可以根据您当地的MLB团队的时间表启用和禁用特定广告。

事实证明,美国职业棒球大联盟以易于解析的CSV格式提供了每个团队的完整时间表。您需要做的就是在Google中搜索“ 可下载的时间表”,然后找到以“ downloadable.jsp”结尾的页面。看起来像这样:


您需要的链接在上图中被圈出。您可以从网址中看到以下代码中的team_id值。而且,如果右键单击并下载该.csv文件,您还将能够看到用于home_field的值。在下面的示例中,我使用了家乡的小熊队和白袜队,但是您可以使用任何想要的球队。

脚本本身将运行并为您的团队寻找主场比赛。如果团队今天在比赛并且是主场比赛,它将启用所有在TEAM_INFO中配置的带有标签的广告。如果团队今天不参加主场比赛,它将暂停这些相同的广告。

在下面的示例中,我仅使用了csv文件中的一部分数据。也可能仅在实际游戏中启用广告,或者在所有游戏日中启用广告,而不仅仅是家用游戏。

我鼓励您尝试使用数据,看看可以做什么。如果发现有用的东西,请发表评论。

谢谢,
拉斯


//-----------------------------------
// Enable/Disable 广告 Based on the MLB Schedule
// Created By: 拉斯 Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
  var TEAM_INFO = [
    { team_id : 112, home_field : 'Wrigley Field', 标签 : 'cubs' }, // Cubs
    { team_id : 145, home_field : 'U.S. Cellular Field', 标签 : 'whitesox' } // White Sox
  ];
  //hopefully you've already 创造d and tagged some 广告 with these 标签
  //but just in case...
  创造LabelsIfNeeded(TEAM_INFO); 
  
  var SEASON = (new Date()).getFullYear();
  var is_home = false, is_game_day = false;
  for(var t in TEAM_INFO) {
    var team = TEAM_INFO[t];
    var url = "http://mlb.mlb.com/soa/ical/schedule.csv?team_id="+team.team_id+"&season="+SEASON;
    var html = UrlFetchApp.fetch(url).getContentText();
    var date_list = html.split("\r\n");
    for(var i in date_list) {
      if(i == 0) {continue;}
      var [start_date,start_time,start_time_et,
           subject,location,description,
           end_date,end_date_et,end_time,end_time_et] = date_list[i].split(",");
      
      var today = new Date();
      var game_day = new Date();
      game_day.setFullYear(SEASON,parseInt(start_date.split("/")[0])-1,parseInt(start_date.split("/")[1]));
      
      is_home = (location == team.home_field);
      is_game_day = (diffDays(game_day,today) == 0);
      
      if(is_home && is_game_day) {
        enableBaseballAds(team.label);
        break;
      }
    }
    if(!(is_home && is_game_day)) {
      disableBaseballAds(team.label); 
    }
  }
  
}

function enableBaseballAds(label) {
  Logger.log("Enabling all 广告 with the "+label+" 标签.");
  var 广告 = AdWordsApp.ads().withCondition("LabelNames CONTAINS_ALL ['"+label+"']").get();
  while(ads.hasNext()) {
    广告.next().enable(); 
  }
}

function disableBaseballAds(label) {
  Logger.log("Disabling all 广告 with the "+label+" 标签.");
  var 广告 = AdWordsApp.ads().withCondition("LabelNames CONTAINS_ALL ['"+label+"']").get();
  while(ads.hasNext()) {
    广告.next().pause(); 
  }
}

function 创造LabelsIfNeeded(team_info) {
  var 标签_iter = AdWordsApp.labels().get();
  var 标签_list = [];
  while(label_iter.hasNext()) {
    标签_list.push(label_iter.next().getName());
  }
  for(var i in team_info) {
    if(label_list.indexOf(team_info[i].label) == -1) {
      AdWordsApp.createLabel(team_info[i].label);
      标签_list.push(team_info[i].label);
    }
  }
}

//A helper function to compare 日期.
//Copied from: http://goo.gl/uW48a
function diffDays(firstDate,secondDate) {
  var oneDay = 24*60*60*1000; // hours*minutes*seconds*milliseconds
  return Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay))); 
}

2013年3月10日,星期日

根据机场延误管理广告

如今,互联网上有大量的API。这些中的任何一个都可以合并到您的AdWords脚本中,以自动化一些帐户管理。

以下脚本使用 FAA.gov提供的机场状态服务 在主要机场出现延误时启用和暂停广告。这对于机场附近可能从航班延误中受益的任何企业(例如餐厅,酒吧或酒店)很有用。您的广告可能会说:



您可以从顶部的列表中添加或删除机场代码。您需要做的只是用[airport_code] _delay标签(“ ORD_delay”,“ ATL_delay”)标记广告。

您还可以使用其他哪些动态数据来优化广告?电影时间?体育游戏?在下面的评论中让我知道,然后我会提出我的建议。

谢谢,
拉斯

/*********************************************
* Pause/Enable 广告 Based On Airport Delays
* Version 1.1
* ChangeLog v1.1 
*  - Added ability to completely 暂停 non-delay 广告
* Created By: 拉斯 Savage
* FreeAdWordsScripts.com
*********************************************/
// For this to work, you need to 广告 d a 标签 to all
// the 广告 for each 飞机场.  For example, PIT_normal
// or SFO_normal
var PAUSE_NORMAL_ADS_DURING_DELAY = false;
var DELAY_SUFFIX = '_delay'; //the suffix on the 标签 for delayed 广告
var NORMAL_SUFFIX = '_normal'; //the suffix on the 标签 for normal 广告

var AIR_CODES = ["ATL","ANC","AUS","BWI","BOS","CLT","MDW","ORD","CVG","CLE",
                 "CMH","DFW","DEN","DTW","FLL","RSW","BDL","HNL","IAH","HOU",
                 "IND","MCI","LAS","LAX","MEM","MIA","MSP","BNA","MSY","JFK",
                 "LGA","EWR","OAK","ONT","MCO","PHL","PHX","PIT","PDX","RDU",
                 "SMF","SLC","SAT","SAN","SFO","SJC","SNA","SEA","STL","TPA",
                 "IAD","DCA"];

function main() {
  var faaUrl = "http://services.faa.gov/airport/status/";
  var args = "?format=application/json";
  for(var i in AIR_CODES) {
    try{
      var resp = UrlFetchApp.fetch(faaUrl + AIR_CODES[i] + args);
      if( resp.getResponseCode() == 200 ) {
        var json = Utilities.jsonParse(resp.getContentText());
        if(json.delay == "false") {
          Logger.log("No 延误 在 "+json.IATA+". Pausing delay 广告 if any are running.");
          turnOffDelayAds(json.IATA);
          if(PAUSE_NORMAL_ADS_DURING_DELAY) {
            turnOnNonDelayAds(json.IATA);
          }
        } else {
          Logger.log("Delays in "+json.IATA+" Reason: "+json.status.reason);
          Logger.log("Turning on delay 广告 if there are any.");
          turnOnDelayAds(json.IATA);
          if(PAUSE_NORMAL_ADS_DURING_DELAY) {
            turnOffNonDelayAds(json.IATA);
          }
        }
      }
    }
    catch(e) {
      Logger.log("Error: " + e.message);
    }
  }
}

function turnOffDelayAds(airportCode) {
  var 标签Name = 飞机场Code + DELAY_SUFFIX;
  var 广告 Iter = AdWordsApp.ads()
    .withCondition("LabelNames CONTAINS_ANY ['"+labelName+"']")
    .withCondition("CampaignStatus = ENABLED")
    .withCondition("AdGroupStatus = ENABLED")
    .withCondition("Status = ENABLED")
    .get();
  while(adIter.hasNext()) {
    广告 Iter.next().pause();
  }
}

function turnOffNonDelayAds(airportCode) {
  var 标签Name = 飞机场Code + NORMAL_SUFFIX;
  var 广告 Iter = AdWordsApp.ads()
    .withCondition("LabelNames CONTAINS_ANY ['"+labelName+"']")
    .withCondition("CampaignStatus = ENABLED")
    .withCondition("AdGroupStatus = ENABLED")
    .withCondition("Status = ENABLED")
    .get();
  while(adIter.hasNext()) {
    广告 Iter.next().pause();
  }
}

function turnOnDelayAds(airportCode) {
  var 标签Name = 飞机场Code + DELAY_SUFFIX;
  var 广告 Iter = AdWordsApp.ads()
    .withCondition("LabelNames CONTAINS_ANY ['"+labelName+"']")
    .withCondition("CampaignStatus = ENABLED")
    .withCondition("AdGroupStatus = ENABLED")
    .withCondition("Status = PAUSED")
    .get();
  while(adIter.hasNext()) {
    广告 Iter.next().enable();
  }
}

function turnOnNonDelayAds(airportCode) {
  var 标签Name = 飞机场Code + NORMAL_SUFFIX;
  var 广告 Iter = AdWordsApp.ads()
    .withCondition("LabelNames CONTAINS_ANY ['"+labelName+"']")
    .withCondition("CampaignStatus = ENABLED")
    .withCondition("AdGroupStatus = ENABLED")
    .withCondition("Status = PAUSED")
    .get();
  while(adIter.hasNext()) {
    广告 Iter.next().enable();
  }
}

2013年3月4日,星期一

修复广告中的大写错误

营销人员在拥有从Feed中自动构建广告素材的系统时面临的问题之一是质量控制。最近,我遇到了一个问题,我制作了大约1000个新广告,城市名称全部为大写。 Google当然不那么喜欢,我不喜欢必须手动更新1,000个广告的想法,因此我整理了以下脚本。

该脚本会在您的帐户中运行所有被拒登的广告,并尝试在ALL CAPS中查找带有单词的广告。我不确定Google的上限是多少,但是在下面的脚本中,它将查找连续三个或三个以上大写字母的任何内容。然后替换它们,创建一个新广告,如果成功,则删除旧广告。

我在确定广告被拒登的原因时遇到了麻烦。 API中尚不提供此功能,但具有 被要求。另一个问题是,有时您创建的新广告会失败,这将导致您删除旧广告而不创建新广告。为了解决这一问题,我在制作新广告之前和之后对广告组中的广告进行了计数,以确保我的广告已创建。再说一次 发布功能请求 在adwords脚本论坛中。

谢谢,
拉斯

//-----------------------------------
// Fix 广告 with EXCESSIVE CAPITALIZATION
// Created By: 拉斯 Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
  var find_caps = /[A-Z]{3,}/g;
  var SEP = '[email protected]~~'; // this needs to be something you would never put in your 广告.
  var 广告 _iter = AdWordsApp.ads().withCondition("ApprovalStatus = 'DISAPPROVED'").get();
  
  while(ad_iter.hasNext()) {
    var 广告  = 广告 _iter.next();
    var old_ad_cnt = get_ad_count(ad.getAdGroup());
    var old_ad_str = [ad.getHeadline(),ad.getDescription1(),ad.getDescription2(),ad.getDisplayUrl()].join(SEP);
    var new_ad_str = old_ad_str;
    Logger.log("Before:"+old_ad_str);
    var m = "";
    while((m = find_caps.exec(new_ad_str)) != null) {
      new_ad_str = replace_all(new_ad_str,m[0],init_cap(m[0]),false);
    }
    Logger.log("After:"+new_ad_str);
    if(old_ad_str != new_ad_str) {
      var [new_headline,new_desc1,new_desc2,new_disp_url] = new_ad_str.split(SEP);
      广告 .getAdGroup().createTextAd(new_headline, new_desc1, new_desc2, new_disp_url, 广告 .getDestinationUrl());
      var new_ad_cnt = get_ad_count(ad.getAdGroup());
      if(new_ad_cnt == (old_ad_cnt+1)) {
        广告 .remove();
      }
    } else {
      Logger.log("Skipping because no changes were made."); 
    }
  }
  
  function init_cap(s) {
    return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
  }
  
  // This function was 广告 apted from: http://dumpsite.com/forum/index.php?topic=4.msg8#msg8 
  function replace_all(original,str1, str2, ignore) {
    return original.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2);
  }
  
  function get_ad_count(ad_group) {
    var 广告 _iter = 广告 _group.ads().get();
    var new_ad_cnt = 0;
    while(ad_iter.hasNext()) {
      广告 _iter.next();
      new_ad_cnt++;
    }
    return new_ad_cnt;
  }
}

2012年11月26日,星期一

新年广告更新

这是我先前有关以下内容之一的同伴 更新新年的关键字.  您可以轻松浏览所有广告,并使用以下脚本在新的一年中全部更新它们。 它还会暂停旧广告,以确保您与客户保持联系。 如果您的广告严重依赖过时的流量,则应安排在每年的1月1日投放。

谢谢,
拉斯

//-----------------------------------
// Update 广告 for 2012
// Created By: 拉斯 Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
  var OLD_YEAR = "2011";
  var NEW_YEAR = "2012";
  //You probably shouldn't 更新 目标网址 unless you know what you are doing.
  var FIELDS_CONTAINING_YEAR = ["Headline","Description1",
                                "Description2","DisplayUrl"
                                /*,"DestinationUrl"*/
                               ];
  
  for(i in FIELDS_CONTAINING_YEAR) {
    var field_iter = AdWordsApp.ads()
        .withCondition(FIELDS_CONTAINING_YEAR[i] + " CONTAINS " + OLD_YEAR)
        .withCondition("Status = ENABLED")
        .get();
    
    _iterateThroughAds(field_iter);
  }

  //---------------
  // Private Helper Functions
  //---------------  
  function _iterateThroughAds(ad_iter) {
    while (ad_iter.hasNext()) {
      var 广告  = 广告 _iter.next();
      var ag = 广告 .getAdGroup();
      _createNewAdFromOldAd(ag,ad);
    }
  }
  
  function _createNewAdFromOldAd(adgroup, old_ad) {
    //get the 更新d 广告  texts replacing all the old years with the 新年s
    var new_headline = old_ad.getHeadline().replace(OLD_YEAR,NEW_YEAR);
    var new_desc1 = old_ad.getDescription1().replace(OLD_YEAR,NEW_YEAR);
    var new_desc2 = old_ad.getDescription2().replace(OLD_YEAR,NEW_YEAR);
    var new_display_url = old_ad.getDisplayUrl().replace(OLD_YEAR,NEW_YEAR);
    var new_dest_url = old_ad.getDestinationUrl();/*.replace(OLD_YEAR,NEW_YEAR);*/
    
    //now 创造 the new 广告  and 暂停 the old one.
    广告群组.createTextAd(new_headline,new_desc1,new_desc2,new_display_url,new_dest_url);
    old_ad.pause();
  }
}

2012年11月22日,星期四

删除帐户中的所有拒登广告

同样,另一个简单的脚本仅关注帐户维护。随着时间的流逝,大型帐户可能会使用可能被拒登的广告来构建数千个广告组。有时,删除这些内容然后缓慢地构建和部署新的广告素材是很有意义的(稍后我们将提供脚本来构建新的广告素材)。希望这对您有用。

谢谢,
拉斯
//-----------------------------------
// Delete 广告 That Are Disapproved
// Created By: 拉斯 Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
  // Let's start by getting all of the 广告  that are 被拒登
  var 广告 _iter = AdWordsApp.ads()
  .withCondition("ApprovalStatus != APPROVED")
  .get();

  // Then we will go through each one
  while (ad_iter.hasNext()) {
    var 广告  = 广告 _iter.next();
    // now we 删除 the 广告 
    Logger.log("Deleteing 广告 : " + 广告 .getHeadline());
    广告 .remove();
  }
}