Отчет по поисковым запросам – управляющий аккаунт

This is a Manager Account script. For operating on a single account, use the Single Account version of the script.

"Отчет по поисковым запросам для Центра клиентов" – это расширенная версия аналогичного скрипта для отдельных аккаунтов. В качестве источника он использует данные отчета по эффективности поисковых запросов.

Скрипт извлекает из таблицы информацию о конфигурации порогов. В таблице есть строка с конфигурацией по умолчанию, а также есть строки с конфигурацией отдельных аккаунтов (по одному аккаунту в строке). Для каждого обрабатываемого аккаунта применяется отдельная конфигурация (если она есть в таблице) или конфигурация по умолчанию (в противном случае).

Принцип работы

Этот скрипт работает так же, как и скрипт для одного аккаунта. но позволяет внести в таблицу несколько аккаунтов.

Первый столбец в таблице – идентификатор аккаунта. It should be an advertiser account, not an MCC account. Таблица может содержать строку для конфигурации по умолчанию (с идентификатором аккаунта "По умолчанию"). В таком случае эта строка должна быть первой. За ней следуют строки с конфигурациями отдельных аккаунтов. Для каждого аккаунта отводится только одна строка. В противном случае будут учитываться данные только из первой строки.

Для каждого обрабатываемого аккаунта применяется отдельная конфигурация (если она есть в таблице) или конфигурация по умолчанию (в противном случае). Если же последняя не указана, аккаунт будет пропущен.

Итерация всех управляемых аккаунтов

Первоначально скрипт выполняется в контексте аккаунта Центра клиентов. Сначала, чтобы сохранить аккаунт Центра клиентов, вызывается метод

var mccAccount = AdWordsApp.currentAccount();
Затем вызывается итератор всех управляемых аккаунтов
var accountIterator = MccApp.accounts().get();

При каждой итерации скрипт вызывает

MccApp.select(account);
чтобы выполнять операции в контексте управляемого аккаунта. Закончив обработку всех аккаунтов, скрипт вызывает
MccApp.select(mccAcount);
чтобы вернуться в контекст аккаунта Центра клиентов.

Запрос отчета с помощью AWQL

Чтобы запросить отчет с помощью AWQL, используйте следующий код:

var report = AdWordsApp.report(
   "SELECT Query,Clicks,Cost,Ctr,ClickConversionRate,CostPerConvertedClick,ConvertedClicks,CampaignId,AdGroupId " +
   " FROM SEARCH_QUERY_PERFORMANCE_REPORT " +
   " WHERE " +
       " ConvertedClicks > 0" +
       " AND Impressions > " + IMPRESSIONS_THRESHOLD +
       " AND AverageCpc > " + AVERAGE_CPC_THRESHOLD +
   " DURING LAST_7_DAYS");
var rows = report.rows();

В этом коде серверы скриптов AdWords временно загружают в скрипт данные запрашиваемого отчета, пополняя их по мере обработки строк.

В приведенном выше коде AWQL из отчета по эффективности поисковых запросов (SEARCH_QUERY_PERFORMANCE_REPORT) запрашиваются поля с данными по эффективности за последнюю неделю.

Принятие решений на основе данных отчета

Далее скрипт последовательно просматривает строки отчета, принимая решение по их обработке:

while(rows.hasNext()) {
  var row = rows.next();
  if (parseFloat(row['Ctr']) < CTR_THRESHOLD) {
    addToMultiMap(negativeKeywords, row['AdGroupId'], row['Query']);
    allAdGroupIds[row['AdGroupId']] = true;
  } else if (parseFloat(row['CostPerConvertedClick']) < costPerConvThrsh) {
    addToMultiMap(positiveKeywords, row['AdGroupId'], row['Query']);
    allAdGroupIds[row['AdGroupId']] = true;
  }
}

Каждая строка отчета представляет собой объект JavaScript (ассоциативный массив), содержащий ключи имен запрашиваемых полей и строковое представление их значений. Скрипт преобразует значение каждого поля в числовой формат и сравнивает его с величиной CTR_THRESHOLD. Ключевые слова с показателем ниже заданного порога признаются неэффективными и включаются в создаваемый далее список минус-слов. Свойство AdGroupId записывается в отдельный объект для последующей массовой загрузки.

Ключевые слова с показателем CTR выше заданного порога и достаточной ценой за конверсию (CostPerConvertedClick) признаются эффективными.

Массовая загрузка групп объявлений

С помощью свойства AdGroupId можно реализовать массовую загрузку групп объявлений в одном запросе:

var adGroupIdList = [];
for (var adGroupId in allAdGroupIds) {
  adGroupIdList.push(adGroupId);
}

var adGroups = AdWordsApp.adGroups().withIds(adGroupIdList).get();

В целях повышения эффективности мы настоятельно рекомендуем применять такой подход при работе с отчетами.

Добавление ключевых слов в группы объявлений

Далее в загруженные группы объявлений добавляются нужные ключевые слова:

if (negativeKeywords[adGroup.getId()]) {
  for (var i = 0; i < negativeKeywords[adGroup.getId()].length; i++) {
    adGroup.createNegativeKeyword('[' + negativeKeywords[adGroup.getId()][i] + ']');
  }
}

Этот код проверяет и добавляет минус-слова с точным соответствием, которые позволяют исключить совпадающие с ними поисковые запросы.

Настройка

Исходный код

// Copyright 2015, Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @name MCC Search Query Report
 *
 * @overview The MCC Search Query Report script uses the Search Query Performance
 *     Report to find undesired search terms in accounts under an MCC account
 *     and add them as negative (or positive) exact keywords. See
 *     https://developers.google.com/adwords/scripts/docs/solutions/mccapp-search-query
 *     for more details.
 *
 * @author AdWords Scripts Team [adwords-scripts@googlegroups.com]
 *
 * @version 1.0.3
 *
 * @changelog
 * - version 1.0.3
 *   - Upgrade to API version v201609.
 * - version 1.0.2
 *   - Added validation for external spreadsheet setup.
 * - version 1.0.1
 *   - Improvements to time zone handling.
 * - version 1.0
 *   - Released initial version.
 */

var SPREADSHEET_URL = 'YOUR_SPREADSHEET_URL';

// Please fix the following variables if you need to reformat the spreadsheet
// column numbers of each config column. Column A in your spreadsheet has
// column number of 1, B has number of 2, etc.
var COLUMN = {
  accountId: 2,
  impressionsThreshold: 3,
  averageCpcThreshold: 4,
  ctrThreshold: 5,
  costPerConvThreshold: 6
};

// Start row/column numbers and total columns of actual config
// (without header and margin)
var CONFIG = {
  startRow: 6,
  startColumn: 2,
  totalColumns: 5
};

// One currency unit is one million micro amount.
var MICRO_AMOUNT_MULTIPLIER = 1000000;

/**
 * Configuration to be used for running reports.
 */
var REPORTING_OPTIONS = {
  // Comment out the following line to default to the latest reporting version.
  apiVersion: 'v201705'
};

function main() {
  // Read config data from the spreadsheet
  Logger.log('Using spreadsheet - %s.', SPREADSHEET_URL);
  var spreadsheet = validateAndGetSpreadsheet(SPREADSHEET_URL);

  // Make sure the spreadsheet is using the account's timezone.
  spreadsheet.setSpreadsheetTimeZone(AdWordsApp.currentAccount().getTimeZone());
  var sheet = spreadsheet.getSheets()[0];

  var endRow = sheet.getLastRow();
  var rows = endRow - CONFIG.startRow + 1;
  var config = [];
  if (rows > 0) {
    config = sheet.getRange(CONFIG.startRow, CONFIG.startColumn,
               rows, CONFIG.totalColumns).getValues();
  }
  else {
    Logger.log('Empty config, abort!');
    return;
  }

  var mccAccount = AdWordsApp.currentAccount();
  sheet.getRange(2, 6).setValue(mccAccount.getCustomerId());

  var accountIterator = MccApp.accounts().get();
  while (accountIterator.hasNext()) {
    var account = accountIterator.next();
    processAccount(account, config);
  }

  // Update "Last execution" timestamp
  var today = new Date();
  sheet.getRange(1, 3).setValue(today);
  MccApp.select(mccAccount);
}

// Core logic for processing each account
function processAccount(account, config) {
  // Swith to current adwords account
  MccApp.select(account);
  var accountId = account.getCustomerId();

  var accountIdCol = COLUMN.accountId - CONFIG.startColumn;
  var impsThrshCol = COLUMN.impressionsThreshold - CONFIG.startColumn;
  var avgCpcThrshCol = COLUMN.averageCpcThreshold - CONFIG.startColumn;
  var ctrThrshCol = COLUMN.ctrThreshold - CONFIG.startColumn;
  var costPerConvThrshCol = COLUMN.costPerConvThreshold - CONFIG.startColumn;

  // Get config for this account, if not found use default entry,
  // if no default entry just skip
  var configIndex = -1;
  var hasDefault = (config[0][accountIdCol].toLowerCase() == 'default');
  var configStartRow = hasDefault ? 1 : 0;
  for (var i = configStartRow; i < config.length; i++) {
    if (config[i][accountIdCol] === accountId) {
      configIndex = i;
      break;
    }
  }

  if (configIndex == -1) {
    if (hasDefault) {
      Logger.log('Processing account %s with default config.', accountId);
      configIndex = 0;
    }
    else {
      Logger.log('Skipping account %s: no config found.', accountId);
      return;
    }
  }
  else {
    Logger.log('Processing account %s with account-specific config.',
               accountId);
  }

  var impsThrsh = config[configIndex][impsThrshCol];
  var avgCpcThrsh = config[configIndex][avgCpcThrshCol];
  var ctrThrsh = config[configIndex][ctrThrshCol];
  var costPerConvThrsh = config[configIndex][costPerConvThrshCol];

  var report = AdWordsApp.report(
      'SELECT Query, Clicks, Cost, Ctr, ConversionRate,' +
      ' CostPerConversion, Conversions, CampaignId, AdGroupId' +
      ' FROM SEARCH_QUERY_PERFORMANCE_REPORT' +
      ' WHERE ' +
          ' Conversions > 0' +
          ' AND Impressions > ' + impsThrsh +
          ' AND AverageCpc > ' + (avgCpcThrsh * MICRO_AMOUNT_MULTIPLIER) +
      ' DURING LAST_7_DAYS', REPORTING_OPTIONS);
  var rows = report.rows();

  var negativeKeywords = {};
  var positiveKeywords = {};
  var allAdGroupIds = {};
  // Iterate through search query and decide whether to add them as positive
  // or negative keywords (or ignore).
  while (rows.hasNext()) {
    var row = rows.next();
    if (parseFloat(row['Ctr']) < ctrThrsh) {
      addToMultiMap(negativeKeywords, row['AdGroupId'], row['Query']);
      allAdGroupIds[row['AdGroupId']] = true;
    } else if (parseFloat(row['CostPerConversion']) < costPerConvThrsh) {
      addToMultiMap(positiveKeywords, row['AdGroupId'], row['Query']);
      allAdGroupIds[row['AdGroupId']] = true;
    }
  }

  // Copy all the adGroupIds from the object into an array.
  var adGroupIdList = [];
  for (var adGroupId in allAdGroupIds) {
    adGroupIdList.push(adGroupId);
  }

  // Add the keywords as negative or positive to the applicable ad groups.
  var adGroups = AdWordsApp.adGroups().withIds(adGroupIdList).get();
  while (adGroups.hasNext()) {
    var adGroup = adGroups.next();
    var adGruopId = adGroup.getId();
    if (negativeKeywords[adGroupId]) {
      for (var i = 0; i < negativeKeywords[adGroupId].length; i++) {
        var curNegativeKeyword = '[' + negativeKeywords[adGroupId][i] + ']';
        adGroup.createNegativeKeyword(curNegativeKeyword);
        Logger.log('Update adGroup "%s": add negative keyword "%s".',
                   adGroupId, curNegativeKeyword);
      }
    }
    if (positiveKeywords[adGroupId]) {
      for (var i = 0; i < positiveKeywords[adGroupId].length; i++) {
        var curPositiveKeyword = '[' + positiveKeywords[adGroupId][i] + ']';
        var keywordOperation = adGroup.newKeywordBuilder()
            .withText(curPositiveKeyword)
            .build();
        Logger.log('Update adGroup "%s": add positive keyword "%s".',
                   adGroupId, curPositiveKeyword);
      }
    }
  }
}

// Helper function that stores queries with AdGroupId
function addToMultiMap(map, key, value) {
  if (!map[key]) {
    map[key] = [];
  }
  map[key].push(value);
}

/**
 * Validates the provided spreadsheet URL to make sure that it's set up
 * properly. Throws a descriptive error message if validation fails.
 *
 * @param {string} spreadsheeturl The URL of the spreadsheet to open.
 * @return {Spreadsheet} The spreadsheet object itself, fetched from the URL.
 * @throws {Error} If the spreadsheet URL hasn't been set
 */
function validateAndGetSpreadsheet(spreadsheeturl) {
  if (spreadsheeturl == 'YOUR_SPREADSHEET_URL') {
    throw new Error('Please specify a valid Spreadsheet URL. You can find' +
        ' a link to a template in the associated guide for this script.');
  }
  return SpreadsheetApp.openByUrl(spreadsheeturl);
}

Оставить отзыв о...

Текущей странице
Скрипты AdWords
Скрипты AdWords