+7 (8442) 50-01-34 mail@mellodesign.ru
Начните работать с нами
Оставьте заявку

Скрипт Ads для назначения ставок, если цена товара не указана в объявлении, и у вас огромный аккаунт

Данная статья продолжает блок статей об управлении ставками в модельных кампаниях Google Ads (когда объявление рекламирует конкретный товар) в зависимости от цен этих товаров. Предыдущая статья находится здесь.

07 марта 2019

Ни для кого не секрет, что по мере работы кампании ключевые слова накапливают статистику и мы принимаем решения об эффективности отдельных слов. Кто-то обновляет ставки руками, кто-то использует автоматизацию. Но что делать, когда вы только запускаетесь, и у вас нет данных по эффективности ключевых слов. Первое, что приходит в голову — назначить всем ключевикам единую ставку, а далее начать корректировать значения бидов. Однако стоит учитывать, если вы рекламируете товары с большим разбросом цены, например наушники за $5 и наушники за $150, то единая ставка тут не подойдет. Более дешевый товар может выиграть больше акционов, и вы на этом не заработаете. Для такой ситуации есть второй вариант назначения первых ставок — ставки в зависимости от цены товара. В этой статье рассмотрим еще один, уже сложный, вариант скрипта Ads, когда цена товара не указана в тексте объявления, но имеется на посадочной странице, и при этом у вас такой большой аккаунт, что скрипт из второй статьи вам не помог.

Логика работы мудреная, возможно в таком виде это вам и не пригодится, но интересные вещи почерпнете: Первый скрипт Ads проходит по всем вашим модельным кампаниям (надо добавить уникальный ярлык к объявлениям из таких РК), собирает все ссылки из объявлений и вставляет их в гугл таблицу. В этой гугл таблице срабатывает свой скрипт, который в соседних ячейках проставляет цены товаров по той же логике, что и во второй статье. Еще один скрипт Ads забирает из гугл таблицы данные по ценам и ссылкам, сохраняет их в списке, далее он же с помощью итератора и селектора ключевых слов получает активные слова из активных групп нужных кампаний. Для каждого ключевика получает его группу, из этой группы берет первое объявление. Из поля final url получаем ссылку на товар, для этой ссылки из массива находим цену. Далее назначаем ставку ключевому слову, исходя из коэффициента конверсии сайта и среднего дохода с товара; в примере цена товара просто делится на 80. Скрипт работает только с развернутыми текстовыми объявлениями, если хотите работать с другими типами, то почитайте в справке о селекторах для нужного формата объявлений.

Ниже инструкция с кодами скриптов и комментариями. Везде одобряйте авторизацию для скриптов.

1.Скопировать в аккаунт Ads этот скрипт и сохранить его отдельно:

function main() {var urls = [];

// выбираем все объявления
var adsIterator = AdWordsApp.ads()

.withCondition(«CampaignStatus = ENABLED»)

.withCondition(«AdGroupStatus = ENABLED»)

.withCondition(«Status = ENABLED»)
.withCondition(«LabelNames CONTAINS_ANY [‘Ярлык для отбора объявлений’]») //Тут указываем ярлык
.withCondition(«Type = ‘EXPANDED_TEXT_AD'»)
.get();

// Если хотите отбирать объявления по иным условиям, справка по селекторам объявлений в помощь:

//https://developers.google.com/google-ads/scripts/docs/reference/adsapp/adsapp_adselector?hl=ru#withCondition_1

while (adsIterator.hasNext()) {
try {

var ads = adsIterator.next();
var url = ads.urls().getFinalUrl();
urls.push(url);

} catch(e){/*Logger.log(‘-‘);*/}
}

//Logger.log(urls);

urls.sort(); // сортируем массив urls

for (var i = urls.length — 1; i > 0; i—) {
if (urls[i] == urls[i — 1]) urls.splice( i, 1);
}

//Logger.log(urls.length);

// объявляем таблицу с данными
var ss = SpreadsheetApp.openById(‘1EU6HIvhC7BtFaoWeXx1kQq_svBQnUj6uhIpuuXWfQCE’) // Указываем id таблицы
var sheet = ss.getSheets()[0]; // Работаем с первым листом таблицы
for (var i=1;i<=urls.length;i++) {
var range = sheet.getRange(«A»+i).setValue(urls[i-1]);
}
}

Этот скрипт собирает ссылки из всех объявлений и отправляет в гугл таблицу. Этому скрипту можно назначить расписание выполнения на 1 раз в день. В первый раз можно запустить руками для проверки. Тут не важно как запускать: в режиме просмотра или выполнения, в эдвордс изменений не будет, а в таблицу вставятся ссылки. В строчке с переменно ss надо указать id нужной таблицы. ID таблицы берется из ссылки на таблицу, например: https://docs.google.com/spreadsheets/d/1EU6HIvhCsssss7BtFaokQq_svBfQCE/edit#gid=0  — жирным выделили id.

2.В используемой таблице зайти в “Инструменты” -> “Редактор скриптов”.

Зайти в “Файл” — >”Создать” — >”Скрипт”

Вставить код

function clearSheet() {

// объявляем таблицу с данными, полученными из Ads
var ss = SpreadsheetApp.openById(‘1EU6HgtFaoWeXx1kQq_svgggWfQCE’) //id таблицы
var sheet = ss.getSheets()[0]; // Работаем с первым листом

// очищаем ее
sheet.clear();
}

В 4й строке указываем id таблицы. Сохраняем скрипт под каким-нибудь названием, для удобства можно назвать “clearTable”. Этот скрипт будет очищать таблицу с заданной периодичностью. Если обратить внимание на первую строку, то увидим название функции — clearSheet.
Чтобы настроить расписание этого скрипта, надо зайти в “Правка” -> “Триггеры текущего проекта” и добавить новый триггер для упомянутой выше функции.

Можно на раз в неделю или раз в день ночью. Если триггер будет на каждый день, то он должен срабатывать раньше, чем скрипт добавления ссылок в таблицу, который был описан в пункте 1.

3.По аналогии создаем в этой же таблице новый скрипт.

Вставляем код:function getPrices() {//функция получения цены
function getPrice(url) {

//парсим страницу
var response = UrlFetchApp.fetch(url);
var c = response.getContentText();
var text = c;

try {

var reg = ‘<meta itemprop=»price» content=»(.*)» />’;// Вот тут в кавычках указываем типовую часть кода посадочной страницы, где находится цена, да так, чтобы сама цена была на месте (.*)

// Например на странице фрагмент с ценой выглядит так: ‘<meta itemprop=»price» content=»4300″ />’

// Тогда в переменной reg это надо записать так: var reg = ‘<meta itemprop=»price» content=»(.*)» />’;

var res = text.match(reg);
//Logger.log(res[1]);
return res[1]

}
catch(e){Logger.log(‘-‘);}

} // Это была вспомогательная функция, которая получает цену для заданного url
// Далее уже будем для каждого url из ячеек столбца A вставлять цену в ячейки столбца B
// объявляем таблицу с данными
var ss = SpreadsheetApp.openById(‘1EU6HIvioWeXx1kQq_svBjXWfQCE’) // id таблицы
var sheet = ss.getSheets()[0]; // Работаем с первым листом
var lastRow = sheet.getLastRow();
Logger.log(lastRow);

var rangeAB = sheet.getRange(«A1:B»+lastRow).getValues();
var rangeB = sheet.getRange(«B1:B»+lastRow).getValues();
//Logger.log(rangeB.length);
//Logger.log(rangeAB.length);

var j = 1;
while (rangeB[j-1][0].toString()!=») {j++;}

// Logger.log(j);
var lastRowB = j;
//Logger.log(lastRow);
rangeAB = sheet.getRange(«A»+lastRowB+»:B»+lastRow).getValues();
//Logger.log(rangeAB.length);
rangeB = sheet.getRange(«B»+lastRowB+»:B»+lastRow).getValues();
//Logger.log(rangeB.length);

for (var i=lastRowB;i<=lastRow;i++){
var pr = rangeAB[i-lastRowB][1];
//Logger.log(pr);
//Logger.log(pr.length);
var url = rangeAB[i-lastRowB][0];
Logger.log(url);
//Logger.log(rangeB);
if (pr.length==0)
{
try{
var valuePr = getPrice(url);
sheet.getRange(«B»+i).setValue(valuePr);}
catch(e){Logger.log(‘-‘);}

}
}
}

В строке с переменной ss указываем id таблицы. Скрипт можно назвать произвольно, но для удобства можно и “getPrices”. Этот скрипт будет парсить сайт и находить цены под соответствующие ссылки. Обратим внимание, в начале скрипта указано название главной функции — getPrices . Для нее настраиваем триггер на каждые 15 минут.

Первый раз можно запустить руками.

За один проход этот скрипт может не успевать указать все цены, поэтому расписание такое частое. Проходов за 5 он успеет указать все цены.

4.Создаем еще один скрипт для таблицы.

function sorter() {

// объявляем таблицу с данными
var ss = SpreadsheetApp.openById(‘1EU6HgXx1kQq_svBQngfQCE’) // id таблицы
var sheet = ss.getSheets()[0];
var lastRow = sheet.getLastRow();
Logger.log(lastRow);

var rangeAB = sheet.getRange(«A1:B»+lastRow);
rangeAB.sort(2);

rangeAB = sheet.getRange(«A1:B»+lastRow).getValues();
var rangeB = sheet.getRange(«B1:B»+lastRow).getValues();
//Logger.log(rangeB);

var mas = [];
for (var i=0; i<rangeB.length;i++) {mas.push(rangeB[i][0]);}
//Logger.log(mas);
var j = 1 ;
var lastB = 1;
try {while (mas[j-1]>=0) {j++;}}
catch(e) {lastB=j;}
//Logger.log(j);
lastB=j;

rangeB = sheet.getRange(«B»+lastB+»:B»+lastRow);
rangeB.clear();

}

В строке с переменной ss указываем id таблицы. Этот срипт будет сортировать цены и ссылки так, чтобы неопределенные значения были внизу таблицы и для них повторно определялась цена. Скрипт можно назвать произвольно. Название функции — sorter.

Триггер можно поставить на каждый час.

 

5.Создаем в Ads новый скрипт.

function main() {function finder(arr,val){
for (var i=0;i<arr.length;i++)
{
var elem = arr[i];
if (elem[0].toString().toLowerCase()==val.toString().toLowerCase()) {
return parseFloat(elem[1])}
//else {return undefined}
}
}

// объявляем таблицу с данными
var ss = SpreadsheetApp.openById(‘1EU6HIvhgeXx1kQq_svBguXWfQCE’); // id таблицы
var sheet = ss.getSheets()[0];
var lastRow = sheet.getLastRow();
//Logger.log(lastRow);

var range = sheet.getRange(«A1:B»+lastRow).getValues(); // В этом range хранятся данные по всем сылкам и ценам
Logger.log(range);

range.sort(); // сортируем массив
for (var i = range.length — 1; i > 0; i—) {
if (range[i][0] == range[i — 1][0]) {range.splice( i, 1);}
}
//Logger.log(range);

// Получаем нужные ключевики

var kw1 = AdWordsApp.keywords()

.withCondition(‘CampaignName = «Указать имя кампании»‘)

.withCondition(«Status = ENABLED»)

.withCondition(«AdGroupStatus = ENABLED»)

.get();

// Если хотите отбирать ключевые слова по каким-то другим условиям, справка по селекторам в помощь:

//https://developers.google.com/google-ads/scripts/docs/reference/adsapp/adsapp_keywordselector?hl=ru#withCondition_1

 

// Проходимся по словам

while(kw1.hasNext()) {

 

var kw = kw1.next();

var kwText = kw.getText();

var group = kw.getAdGroup();

var groupName = group.getName();

var ads = group.ads().withCondition(«Type = ‘EXPANDED_TEXT_AD'»).withCondition(«Status = ENABLED»).get();

 

// Если хотите отбирать объявления по иным условиям, справка по селекторам объявлений в помощь:

//https://developers.google.com/google-ads/scripts/docs/reference/adsapp/adsapp_adselector?hl=ru#withCondition_1

 

var ad = ads.next();

var url = ad.urls().getFinalUrl();

 

var price = finder(range,url);

 

if (price != undefined) {
var bid = price/80;
if (bid>=10) {bid = 10;}
Logger.log(‘price — ‘ + price);
Logger.log(‘bid — ‘ + bid);

kw.setMaxCpc(bid);}

Logger.log(‘———‘);
price = undefined;
}
}

Этот скрипт берет данные из таблицы и назначает ставки в нужной кампании, исходя из цен на товары. Его выполнение можно поставить на 1 раз в день.

Итоговый график выполнения всех скриптов должен получиться примерно таким: ночью раз в неделю срабатывает скрипт очистки таблицы 1 раз в день; ночью один раз в сутки срабатывает скрипт ads, который собирает ссылки объявлений и отправляет их в таблицу; каждые 15-30 минут срабатывает скрипт получения цен в таблице; каждый час срабатывает скрипт сортировки в таблице; утром или днем (в зависимости от скорости заполнения всех цен в таблице) 1 раз в сутки срабатывает скрипт ads, выставляющий ставки.

При желании вы можете изменить последний скрипт так, чтобы он не назначал ставки, а изменял цены в текстах объявлений, — просто надо проходить селектором не по ключевым словам, а по объявлениям, брать искомый параметр объявления, например описание 2, вырезать из него цену, сверять цену с актуальной, полученной из таблицы. Если цены расходятся, то надо создавать дубль объявления, но с уже новой ценой, старый вариант удалять. А если у вас в аккаунте мало объявлений, то можно обойтись и без таблиц, сканируя посадочные страницы в поисках цен непосредственного из этого же скрпита, как это делалось во второй статье серии. Про такое обновление цен можно было бы написать статью, но каждый сайт и аккаунт ads уникален, поэтому общего решения все равно не выйдет, так что, приложив немного усилий, вы сделаете все сами. Удачи!