На этой странице приведены рекомендации по разработке скриптов Google Рекламы.
Селекторы
Фильтрация с помощью селекторов
По возможности используйте фильтры, чтобы запрашивать только нужные объекты. Применение подходящих фильтров дает следующие преимущества:
- Код значительно проще.
- Скрипт будет работать быстрее.
Сравните следующие фрагменты кода:
| Метод кодирования | Фрагмент кода |
|---|---|
| Как отфильтровать файлы с помощью селекторов (рекомендуется) |
var keywords = AdsApp.keywords()
.withCondition('Clicks > 10')
.forDateRange('LAST_MONTH')
.get();
while (keywords.hasNext()) {
var keyword = keywords.next();
// Do work here.
}
|
| Фильтрация в коде (не рекомендуется) |
var keywords = AdsApp.keywords().get();
while (keywords.hasNext()) {
var keyword = keywords.next();
var stats = keyword.getStatsFor(
'LAST_MONTH');
if (stats.getClicks() > 10) {
// Do work here.
}
}
|
Второй подход не рекомендуется, поскольку он пытается получить список всех ключевых слов в вашем аккаунте только для того, чтобы применить к нему фильтр.
Как обойтись без обхода иерархии в рамках кампании
Если вам нужно получить объекты определенного уровня, используйте метод сбора на этом уровне, а не просматривайте всю иерархию кампании. Это не только проще, но и эффективнее: системе не придется считывать все кампании и группы объявлений.
Сравните следующие фрагменты кода, которые извлекают все объявления в вашем аккаунте:
| Метод кодирования | Фрагмент кода |
|---|---|
| Используйте подходящий метод сбора данных (рекомендуется) |
var ads = AdsApp.ads(); |
| Переход по иерархии (не рекомендуется) |
var campaigns = AdsApp.campaigns().get();
while (campaigns.hasNext()) {
var adGroups = campaigns.next().
adGroups().get();
while (adGroups.hasNext()) {
var ads = adGroups.next().ads().get();
// Do your work here.
}
}
|
Второй подход не рекомендуется, поскольку он пытается получить целые иерархии объектов (кампании, группы объявлений), когда требуются только объявления.
Используйте специальные методы доступа к родительским элементам
Иногда вам может потребоваться получить родительский объект извлеченного объекта. В этом случае следует использовать предоставленный метод доступа, а не извлекать целые иерархии.
Сравните следующие фрагменты кода, которые извлекают группы объявлений, содержащие текстовые объявления с более чем 50 кликами за последний месяц:
| Метод кодирования | Фрагмент кода |
|---|---|
| Используйте подходящий метод доступа к родительскому элементу (рекомендуется) |
var ads = AdsApp.ads()
.withCondition('Clicks > 50')
.forDateRange('LAST_MONTH')
.get();
while (ads.hasNext()) {
var ad = ads.next();
var adGroup = ad.getAdGroup();
var campaign = ad.getCampaign();
// Store (campaign, adGroup) to an array.
}
|
| Переход по иерархии (не рекомендуется) |
var campaigns = AdsApp.campaigns().get();
while (campaigns.hasNext()) {
var adGroups = campaigns.next()
.adGroups()
.get();
while (adGroups.hasNext()) {
var ads = adGroups.ads()
.withCondition('Clicks > 50')
.forDateRange('LAST_MONTH')
.get();
if (ads.totalNumEntities() > 0) {
// Store (campaign, adGroup) to an array.
}
}
}
|
Второй подход не рекомендуется, поскольку он извлекает все иерархии кампаний и групп объявлений в вашем аккаунте, когда вам нужен только поднабор кампаний и групп объявлений, связанных с вашим набором объявлений. Первый подход ограничивается получением только коллекции релевантных объявлений и использует соответствующий метод для доступа к родительским объектам.
Использовать специальные родительские фильтры
Чтобы получить доступ к объектам в определенной кампании или группе объявлений, используйте специальный фильтр в селекторе, а не извлекайте и не просматривайте иерархию.
Сравните следующие фрагменты кода, которые извлекают список текстовых объявлений в указанной кампании и группе объявлений, получивших более 50 кликов за последний месяц.
| Метод кодирования | Фрагмент кода |
|---|---|
| Используйте подходящие фильтры родительского уровня (рекомендуется) |
var ads = AdsApp.ads()
.withCondition('CampaignName = "Campaign 1"')
.withCondition('AdGroupName = "AdGroup 1"')
.withCondition('Clicks > 50')
.forDateRange('LAST_MONTH')
.get();
while (ads.hasNext()) {
var ad = ads.next();
var adGroup = ad.getAdGroup();
var campaign = ad.getCampaign();
// Store (campaign, adGroup, ad) to
// an array.
}
|
| Переход по иерархии (не рекомендуется) |
var campaigns = AdsApp.campaigns()
.withCondition('Name = "Campaign 1"')
.get();
while (campaigns.hasNext()) {
var adGroups = campaigns.next()
.adGroups()
.withCondition('Name = "AdGroup 1"')
.get();
while (adGroups.hasNext()) {
var ads = adGroups.ads()
.withCondition('Clicks > 50')
.forDateRange('LAST_MONTH')
.get();
while (ads.hasNext()) {
var ad = ads.next();
// Store (campaign, adGroup, ad) to
// an array.
}
}
}
|
Второй подход не рекомендуется, поскольку он перебирает иерархию кампаний и групп объявлений в вашем аккаунте, когда вам нужен только выбранный набор объявлений и их родительские кампании и группы объявлений. Первый подход ограничивает итерацию списком объявлений, применяя к селектору определенный фильтр для родительских объектов.
По возможности используйте для фильтрации идентификаторы
При фильтрации объектов предпочтительно использовать их идентификаторы, а не другие поля.
Рассмотрим следующие фрагменты кода, которые выбирают кампанию.
| Метод кодирования | Фрагмент кода |
|---|---|
| Фильтрация по идентификатору (рекомендуется) |
var campaign = AdsApp.campaigns()
.withIds([12345])
.get()
.next();
|
| Фильтрация по названию (менее оптимальный вариант) |
var campaign = AdsApp.campaigns()
.withCondition('Name="foo"')
.get()
.next();
|
Второй подход менее оптимален, поскольку фильтрация выполняется по полю, не содержащему идентификатор.
По возможности фильтруйте по родительским идентификаторам.
При выборе объекта по возможности используйте фильтр по родительским идентификаторам. Это позволит ускорить выполнение запросов, ограничив список объектов, извлекаемых серверами при фильтрации результатов.
Рассмотрим следующий фрагмент кода, который извлекает AdGroup по идентификатору. Предположим, что идентификатор родительской кампании известен.
| Метод кодирования | Фрагмент кода |
|---|---|
| Фильтрация по идентификаторам кампаний и групп объявлений (рекомендуется) |
var adGroup = AdsApp.adGroups()
.withIds([12345])
.withCondition('CampaignId="54678"')
.get()
.next();
|
| Фильтрация только по идентификатору группы объявлений (менее оптимальный вариант) |
var adGroup = AdsApp.adGroups()
.withIds([12345])
.get()
.next();
|
Хотя оба фрагмента кода дают одинаковые результаты, дополнительная фильтрация во фрагменте 1 с использованием идентификатора родительского объекта (CampaignId="54678") делает код более эффективным, ограничивая список объектов, которые сервер должен перебирать при фильтрации результатов.
Используйте ярлыки, если условий фильтрации слишком много
Если условий фильтрации слишком много, рекомендуется создать ярлык для обрабатываемых объектов и использовать его для фильтрации.
Рассмотрим следующий фрагмент кода, который извлекает список кампаний по их названию.
| Метод кодирования | Фрагмент кода |
|---|---|
| Использование ярлыка (рекомендуется) |
var label = AdsApp.labels()
.withCondition('Name = "My Label"')
.get()
.next();
var campaigns = label.campaigns.get();
while (campaigns.hasNext()) {
var campaign = campaigns.next();
// Do more work
}
|
| Как создавать сложные селекторы (не рекомендуется) |
var campaignNames = ['foo', 'bar', 'baz'];
for (var i = 0; i < campaignNames.length; i++) {
campaignNames[i] = '"' + campaignNames[i] + '"';
}
var campaigns = AdsApp.campaigns
.withCondition('CampaignName in [' + campaignNames.join(',') + ']')
.get();
while (campaigns.hasNext()) {
var campaign = campaigns.next();
// Do more work.
}
|
Хотя оба фрагмента кода обеспечивают примерно одинаковую производительность, второй подход приводит к созданию более сложного кода по мере увеличения количества условий в селекторе. Кроме того, применить ярлык к новому объекту проще, чем изменить скрипт, чтобы включить этот объект.
Ограничьте количество условий в операторе IN
При работе со скриптами часто требуется создать отчет по списку объектов. Обычно разработчики делают это, создавая очень длинный запрос GAQL, который фильтрует идентификаторы объектов с помощью предложения IN. Этот подход хорошо работает, когда количество объектов ограничено. Однако по мере увеличения длины запроса производительность скрипта снижается по двум причинам:
- Чем длиннее запрос, тем больше времени требуется на его обработку.
- Каждый идентификатор, добавленный в предложение IN, представляет собой дополнительное условие, которое необходимо оценить, и поэтому требует больше времени.
В таких случаях лучше применить к объектам ярлык, а затем отфильтровать их по LabelId.
| Метод кодирования | Фрагмент кода |
|---|---|
| Как применить ярлык и отфильтровать по labelID (рекомендуется) |
// The label applied to the entity is "Report Entities"
var label = AdsApp.labels()
.withCondition('LabelName contains "Report Entities"')
.get()
.next();
var report = AdsApp.report('SELECT AdGroupId, Id, Clicks, ' +
'Impressions, Cost FROM KEYWORDS_PERFORMANCE_REPORT ' +
'WHERE LabelId = "' + label.getId() + '"');
|
| Создание длинного запроса с помощью оператора IN (не рекомендуется) |
var report = AdsApp.report('SELECT AdGroupId, Id, Clicks, ' +
'Impressions, Cost FROM KEYWORDS_PERFORMANCE_REPORT WHERE ' +
'AdGroupId IN (123, 456) and Id in (123,345, 456…)');
|
Изменения в аккаунте
Массовые изменения
Когда вы вносите изменения в объект Google Рекламы, скрипты Google Рекламы не выполняют их немедленно. Вместо этого он пытается объединить несколько изменений в пакеты, чтобы можно было выдать один запрос, который вносит несколько изменений. Это ускорит работу скриптов и снизит нагрузку на серверы Google Рекламы. Однако некоторые шаблоны кода заставляют скрипты Google Рекламы часто очищать пакет операций, что приводит к замедлению работы скрипта.
Рассмотрим следующий скрипт, который обновляет ставки для списка ключевых слов.
| Метод кодирования | Фрагмент кода |
|---|---|
| Отслеживайте обновленные элементы (рекомендуется) |
var keywords = AdsApp.keywords()
.withCondition('Clicks > 50')
.withCondition('CampaignName = "Campaign 1"')
.withCondition('AdGroupName = "AdGroup 1"')
.forDateRange('LAST_MONTH')
.get();
var list = [];
while (keywords.hasNext()) {
var keyword = keywords.next();
keyword.bidding().setCpc(1.5);
list.push(keyword);
}
for (var i = 0; i < list.length; i++) {
var keyword = list[i];
Logger.log('%s, %s', keyword.getText(),
keyword.bidding().getCpc());
}
|
| Извлечение обновленных элементов в цикле (не рекомендуется) |
var keywords = AdsApp.keywords()
.withCondition('Clicks > 50')
.withCondition('CampaignName = "Campaign 1"')
.withCondition('AdGroupName = "AdGroup 1"')
.forDateRange('LAST_MONTH')
.get();
while (keywords.hasNext()) {
var keyword = keywords.next();
keyword.bidding().setCpc(1.5);
Logger.log('%s, %s', keyword.getText(),
keyword.bidding().getCpc());
}
|
Второй подход не рекомендуется, поскольку вызов keyword.bidding().getCpc() заставляет скрипты Google Рекламы очищать операцию setCpc() и выполнять только одну операцию за раз. Первый подход похож на второй, но у него есть дополнительное преимущество – поддержка пакетной обработки, поскольку вызов getCpc() выполняется в цикле, отдельном от цикла, в котором вызывается setCpc().
По возможности используйте конструкторы
Скрипты Google Рекламы поддерживают два способа создания объектов: конструкторы и методы создания. Конструкторы более гибкие, чем методы создания, поскольку они предоставляют доступ к объекту, созданному в результате вызова API.
Рассмотрим следующие фрагменты кода:
| Метод кодирования | Фрагмент кода |
|---|---|
| Использование конструкторов (рекомендуется) |
var operation = adGroup.newKeywordBuilder()
.withText('shoes')
.build();
var keyword = operation.getResult();
|
| Использование методов создания (не рекомендуется) |
adGroup.createKeyword('shoes');
var keyword = adGroup.keywords()
.withCondition('KeywordText="shoes"')
.get()
.next();
|
Второй подход не рекомендуется, поскольку для получения ключевого слова требуется дополнительная операция выбора. Кроме того, методы создания также устарели.
Однако помните, что при неправильном использовании конструкторов скрипты Google Рекламы не смогут выполнять пакетную обработку операций.
Рассмотрим фрагменты кода, которые создают список ключевых слов и выводят идентификаторы новых ключевых слов.
| Метод кодирования | Фрагмент кода |
|---|---|
| Отслеживайте обновленные элементы (рекомендуется) |
var keywords = ['foo', 'bar', 'baz'];
var list = [];
for (var i = 0; i < keywords.length; i++) {
var operation = adGroup.newKeywordBuilder()
.withText(keywords[i])
.build();
list.push(operation);
}
for (var i = 0; i < list.length; i++) {
var operation = list[i];
var result = operation.getResult();
Logger.log('%s %s', result.getId(),
result.getText());
}
|
| Извлечение обновленных элементов в цикле (не рекомендуется) |
var keywords = ['foo', 'bar', 'baz'];
for (var i = 0; i < keywords.length; i++) {
var operation = adGroup.newKeywordBuilder()
.withText(keywords[i])
.build();
var result = operation.getResult();
Logger.log('%s %s', result.getId(),
result.getText());
}
|
Второй подход не рекомендуется, поскольку в нем метод operation.getResult() вызывается в том же цикле, в котором создается операция. В результате скрипты Google Рекламы вынуждены выполнять по одной операции за раз. Первый подход, хотя и похож на второй, позволяет выполнять пакетную обработку, поскольку мы вызываем operation.getResult() в цикле, отличном от того, в котором он был создан.
Используйте массовую загрузку для крупных обновлений
Разработчики часто создают отчеты и обновляют свойства объектов (например, ставки на уровне ключевого слова) на основе текущих показателей эффективности. Если вам нужно обновить большое количество объектов, массовая загрузка обычно обеспечивает лучшую производительность. Например, рассмотрим скрипты, которые увеличивают максимальную цену за клик для ключевых слов, у которых TopImpressionPercentage > 0.4 за последний месяц.
| Метод кодирования | Фрагмент кода |
|---|---|
| Массовая загрузка (рекомендуется) |
var report = AdsApp.report(
'SELECT AdGroupId, Id, CpcBid FROM KEYWORDS_PERFORMANCE_REPORT ' +
'WHERE TopImpressionPercentage > 0.4 DURING LAST_MONTH');
var upload = AdsApp.bulkUploads().newCsvUpload([
report.getColumnHeader('AdGroupId').getBulkUploadColumnName(),
report.getColumnHeader('Id').getBulkUploadColumnName(),
report.getColumnHeader('CpcBid').getBulkUploadColumnName()]);
upload.forCampaignManagement();
var reportRows = report.rows();
while (reportRows.hasNext()) {
var row = reportRows.next();
row['CpcBid'] = row['CpcBid'] + 0.02;
upload.append(row.formatForUpload());
}
upload.apply();
|
| Выбор и обновление ключевых слов по идентификатору (менее оптимальный вариант) |
var reportRows = AdsApp.report('SELECT AdGroupId, Id, CpcBid FROM ' +
'KEYWORDS_PERFORMANCE_REPORT WHERE TopImpressionPercentage > 0.4 ' +
' DURING LAST_MONTH')
.rows();
var map = {
};
while (reportRows.hasNext()) {
var row = reportRows.next();
var adGroupId = row['AdGroupId'];
var id = row['Id'];
if (map[adGroupId] == null) {
map[adGroupId] = [];
}
map[adGroupId].push([adGroupId, id]);
}
for (var key in map) {
var keywords = AdsApp.keywords()
.withCondition('AdGroupId="' + key + '"')
.withIds(map[key])
.get();
while (keywords.hasNext()) {
var keyword = keywords.next();
keyword.bidding().setCpc(keyword.bidding().getCpc() + 0.02);
}
}
|
Хотя второй подход дает довольно хорошую производительность, первый подход предпочтительнее в этом случае, поскольку
В скриптах Google Рекламы есть ограничение на количество объектов, которые можно получить или обновить за один запуск. Операции выбора и обновления во втором подходе учитываются в этом ограничении.
При массовой загрузке лимиты выше как по количеству объектов, которые можно обновить, так и по общему времени выполнения.
Группируйте массовые загрузки по кампаниям
При создании массовых загрузок старайтесь группировать операции по родительской кампании. Это повышает эффективность и снижает вероятность конфликтующих изменений и ошибок параллелизма.
Предположим, что параллельно выполняются две задачи массовой загрузки. Одно приостанавливает показ объявлений в группе, а другое корректирует ставки для ключевых слов. Даже если операции не связаны, они могут применяться к объектам в одной группе объявлений (или в двух разных группах объявлений в одной кампании). В этом случае система заблокирует родительский объект (общую группу объявлений или кампанию), что приведет к взаимной блокировке задач массовой загрузки.
Скрипты Google Рекламы могут оптимизировать выполнение в рамках одной задачи массовой загрузки, поэтому проще всего запускать только одну задачу массовой загрузки для каждого аккаунта за раз. Если вы решите запустить несколько массовых загрузок для одного аккаунта, убедитесь, что они работают с взаимоисключающими списками кампаний (и их дочерних объектов). Это позволит обеспечить оптимальную производительность.
Отчеты
Как использовать отчеты для получения статистики
Если вам нужно получить большое количество объектов и их статистику, лучше использовать отчеты, а не стандартные методы AdsApp. Использовать отчеты предпочтительнее по следующим причинам:
- Отчеты обеспечивают более высокую производительность при обработке больших запросов.
- Отчеты не будут учитываться в квотах на получение данных.
Сравните следующие фрагменты кода, которые извлекают данные о кликах, показах, стоимости и тексте всех ключевых слов, получивших более 50 кликов за последний месяц:
| Метод кодирования | Фрагмент кода |
|---|---|
| Использование отчетов (рекомендуется) |
report = AdsApp.search(
'SELECT ' +
' ad_group_criterion.keyword.text, ' +
' metrics.clicks, ' +
' metrics.cost_micros, ' +
' metrics.impressions ' +
'FROM ' +
' keyword_view ' +
'WHERE ' +
' segments.date DURING LAST_MONTH ' +
' AND metrics.clicks > 50');
while (report.hasNext()) {
var row = report.next();
Logger.log('Keyword: %s Impressions: %s ' +
'Clicks: %s Cost: %s',
row.adGroupCriterion.keyword.text,
row.metrics.impressions,
row.metrics.clicks,
row.metrics.cost);
}
|
| Использование итераторов AdsApp (не рекомендуется) |
var keywords = AdsApp.keywords()
.withCondition('metrics.clicks > 50')
.forDateRange('LAST_MONTH')
.get();
while (keywords.hasNext()) {
var keyword = keywords.next();
var stats = keyword.getStatsFor('LAST_MONTH');
Logger.log('Keyword: %s Impressions: %s ' +
'Clicks: %s Cost: %s',
keyword.getText(),
stats.getImpressions(),
stats.getClicks(),
stats.getCost());
}
|
Второй подход не рекомендуется, поскольку он предполагает итерацию по ключевым словам и получение статистики по одному объекту за раз. В этом случае отчеты создаются быстрее, поскольку все данные извлекаются за один вызов и передаются по мере необходимости. Кроме того, ключевые слова, полученные вторым способом, учитываются в квоте скрипта на количество объектов, полученных с помощью вызова get().
Используйте поиск вместо отчета
Метод report был создан для старой инфраструктуры и будет выводить результаты в плоском формате, даже если вы используете GAQL. Это означает, что результаты запроса должны быть преобразованы в соответствии со старым стилем, который поддерживается не для всех полей и увеличивает нагрузку на каждый вызов.
Рекомендуем использовать метод search, чтобы воспользоваться всеми возможностями отчетов в новом Google Ads API.
Используйте GAQL вместо AWQL
Хотя AWQL по-прежнему работает для запросов отчетов и вызовов withCondition, использовать его не рекомендуется. Чтобы полностью контролировать запросы, используйте GAQL.
Не выбирайте больше строк, чем вам нужно
Скорость выполнения отчетов (и селекторов) зависит от общего количества строк, которые будут возвращены отчетом, независимо от того, выполняете ли вы итерацию по ним. Это означает, что вы всегда должны использовать определенные фильтры, чтобы максимально минимизировать набор результатов в соответствии с вашим вариантом использования.
Например, вы хотите найти группы объявлений со ставками, которые не входят в определенный диапазон. В этом случае быстрее будет выполнить два отдельных запроса: один для ставок ниже нижнего порога, а другой – для ставок выше верхнего порога. Это быстрее, чем получить все группы объявлений и игнорировать те, которые вас не интересуют.
| Метод кодирования | Фрагмент кода |
|---|---|
| Используйте два запроса (рекомендуется) |
var adGroups = []
var report = AdsApp.search(
'SELECT ad_group.name, ad_group.cpc_bid_micros' +
' FROM ad_group WHERE ad_group.cpc_bid_micros < 1000000');
while (report.hasNext()) {
var row = report.next();
adGroups.push(row.adGroup);
}
var report = AdsApp.search(
'SELECT ad_group.name, ad_group.cpc_bid_micros' +
' FROM ad_group WHERE ad_group.cpc_bid_micros > 2000000');
while (report.hasNext()) {
var row = report.next();
adGroups.push(row.adGroup);
}
|
| Фильтрация общего запроса (не рекомендуется) |
var adGroups = []
var report = AdsApp.search(
'SELECT ad_group.name, ad_group.cpc_bid_micros' +
' FROM ad_group');
while (report.hasNext()) {
var row = report.next();
var cpcBidMicros = row.adGroup.cpcBidMicros;
if (cpcBidMicros < 1000000 || cpcBidMicros > 2000000) {
adGroups.push(row.adGroup);
}
}
|
Скрипты для управляющих аккаунтов (Центра клиентов)
Используйте executeInParallel вместо последовательного выполнения
При написании скриптов для управляющих аккаунтов по возможности используйте executeInParallel() вместо последовательного выполнения. executeInParallel() дает скрипту больше времени на обработку (до одного часа) и до 30 минут на каждый обработанный аккаунт (вместо 30 минут в сумме для последовательного выполнения). Подробную информацию можно найти на странице с ограничениями.
Таблицы
Используйте пакетные операции при обновлении таблиц
При обновлении таблиц старайтесь использовать методы массовых операций (например, getRange()), а не методы, которые обновляют по одной ячейке за раз.
Рассмотрим следующий фрагмент кода, который генерирует фрактальный узор в таблице.
| Метод кодирования | Фрагмент кода |
|---|---|
| Обновление диапазона ячеек за один вызов (рекомендуется) |
var colors = new Array(100);
for (var y = 0; y < 100; y++) {
xcoord = xmin;
colors[y] = new Array(100);
for (var x = 0; x < 100; x++) {
colors[y][x] = getColor_(xcoord, ycoord);
xcoord += xincrement;
}
ycoord -= yincrement;
}
sheet.getRange(1, 1, 100, 100).setBackgroundColors(colors);
|
| Обновление по одной ячейке (не рекомендуется) |
var cell = sheet.getRange('a1');
for (var y = 0; y < 100; y++) {
xcoord = xmin;
for (var x = 0; x < 100; x++) {
var c = getColor_(xcoord, ycoord);
cell.offset(y, x).setBackgroundColor(c);
xcoord += xincrement;
}
ycoord -= yincrement;
SpreadsheetApp.flush();
}
|
Хотя Google Таблицы пытаются оптимизировать второй фрагмент кода, кешируя значения, он все равно работает медленнее первого из-за количества вызовов API.