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

2013年7月11日,星期四

在Google电子表格中的广告组一级设置AdParams

我有几个人问我如何更新以前的脚本 在关键字级别设置AdParams 以便可以在广告组一级进行设置。这是该脚本的更新,仅此即可。

要使用它,您需要 创建一个新的Google电子表格 并分别在A,B和C列(带有列标题)中分别加载广告组名称,参数1值和参数2值。然后将该URL复制到脚本中,您应该一切顺利。

谢谢,
拉斯

/************************************************
* Update Ad Params by Ad Groups
* Version 1.1
* ChangeLog v1.1
*  - Added the ability to enable param1 or 2 individually
*  - Looks for Keywords on all sheets
*  - Runs much faster
* Created By:  拉斯  Savage
* FreeAdWordsScripts.com
************************************************/
var SPREADSHEET_URL = "PUT YOUR SPREADSHEET URL HERE";
var SET_PARAM1 = true;
var SET_PARAM2 = false;
var DATA_RANGE = 'A:D'; // A - CampaignName, B - AdGroupName, 
                        // C - Param1, D - Param2

function main() {
  var 电子表格 = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
  var allSheets = 电子表格.getSheets();
  var allData = [];
  for(var i in allSheets) {
    var sheet = allSheets[i];
    var data = sheet.getRange(DATA_RANGE).getValues();
    data.shift(); //get rid of headers
    allData = allData.concat(data);
  }
  
  var allDataHash = {};
  for(var i in allData) {
    var row = allData[i];
    if(row[0] === '') { continue; }
    var rowKey = [row[0],row[1]].join('~~!~~');
    allDataHash[rowKey] = { param1 : row[2], param2: row[3] };
  }
  
  var kwIter = AdWordsApp.keywords()
    .withCondition('CampaignStatus = ENABLED')
    .withCondition('AdGroupStatus = ENABLED')
    .withCondition('Status = ENABLED')
    .get();
  
  while(kwIter.hasNext()) { 
    var kw = kwIter.next();
    var campName = kw.getCampaign().getName();
    var  广告 GroupName = kw.getAdGroup().getName();
    var rowKey = [campName,adGroupName].join('~~!~~');
    if(allDataHash[rowKey]) {
      if(SET_PARAM1) { kw.setAdParam(1, allDataHash[rowKey].param1); }
      if(SET_PARAM2) { kw.setAdParam(2, allDataHash[rowKey].param2); }
    }
  }
}

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

2012年11月26日,星期一

新年广告更新

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

谢谢,
拉斯

//-----------------------------------
// Update Ads 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月21日,星期三

暂停没有有效关键字的广告组

这是一个快速脚本,可以暂停所有没有有效关键字的广告组。不确定这是否超级有用,但是对于大型帐户,它可能有助于确定您可以删除的广告组。

谢谢,
拉斯

/*********************************************
* 暂停没有有效关键字的广告组
* Version 1.1
* Changelog v1.1
*   - Updated for speed and  广告 ded 评论s 
* Created By:  拉斯  Savage
* FreeAdWordsScripts.com
**********************************************/
function main() {
  // Let's start by getting all of the active AdGroups
  var agIter = AdWordsApp.adGroups()
    .withCondition('CampaignStatus = ENABLED')
    .withCondition('Status = ENABLED')
    .get();
 
  // It is faster to store them and process them all  在  once later
  var toPause = [];
  // Then we will go through each one
  while(agIter.hasNext()) {
    var ag = agIter.next();
    //get all the 关键字 that are enabled
    var kwIter = ag.keywords()
      .withCondition("Status = ENABLED")
      .get();
    
    //If .hasNext() is true, there is  在  least 1 kw in the AdGroup
    var hasKw = kwIter.hasNext(); 
    if(!hasKw) {
      toPause.push(ag);
    }
  }
  
  // Now we process them all  在  once to take  广告 vantage of batch processing
  for(var i in toPause) {
    toPause[i].pause();
  }
}