Как автоматизировать работу PPC-специалиста?
Специалисты по контекстной рекламе или владельцы интернет-магазинов, которые ведут рекламный аккаунт своими руками, ежедневно сталкиваются с необходимостью автоматизации контекстной рекламы. В данной статье я расскажу, как с помощью небольших и быстрых настроек, можно освободить себя от скучной монотонной работы.
Главными помощниками в этом деле станут два скрипта Google Ads. Первый скрипт позволяет подставлять стоимость товара в объявление без последующей модерации. Второй — останавливает показ объявлений товаров, которых нет в наличии. Согласитесь, ведь это здорово!
С помощью скриптов мы не только экономим свое время, но еще и избавляемся от простоя рекламы, после внесенных руками изменений в объявления.
Для установки данных скриптов нам не понадобятся особые знания из области программирования. Достаточно всё делать шаг за шагом, как описано в этой статье.
Основные функции скриптов:
- парсинг цены товара на сайте и подстановка ее в объявление;
- парсинг любого другого текста на страничке сайта и подстановка его в объявление;
- парсинг наличия товара и отключение объявлений, когда товары отсутствуют в продаже.
Сайты, для которых подойдет данный пакет скриптов:
- на странице товара указана его цена
- на странице товара указано наличие товара
Что необходимо сделать?
1. Копируем скрипт подмены цены:
var URL_LEVEL = 'Ad'; // Ad or Keyword
var ONLY_ACTIVE = false; // set to false for all ads or keywords
var CAMPAIGN_LABEL = ''; // set this if you want to only check campaigns with this label
var STRIP_QUERY_STRING = true; // set this to false if the stuff that comes after the question mark is important
var WRAPPED_URLS = true; // set this to true if you use a 3rd party like Marin or Kenshoo for managing you account
// This is the specific text to search for
// on the page that indicates the item
// is out of stock.
var LABEL_NAMES = ['"Price_Change"'];
var OUT_OF_STOCK_TEXT = 'Осталось 0 товаров';
var PRICE_TEXT_BEGIN = '';
var PRICE_TEXT_END = '';
var keywords = {};
function setKeywordPrice(keyword, price) {
var keywordId = keyword.getId();
if (keywords[keywordId]) {} else {
Logger.log('Keyword: '+keyword+', Price: '+price);
keyword.setAdParam(1, price);
keywords[keywordId] = true;
}
}
function setAdPrice(ad, price) {
var keywords = ad.getAdGroup().keywords().get();
while(keywords.hasNext()) {
var keyword = keywords.next();
setKeywordPrice(keyword, price);
//Logger.log('Ad: '+ad+'; Price: '+price+'; Keyword: '+keyword);
}
}
function main() {
var alreadyCheckedUrls = {};
var prices = {};
var campIter = AdWordsApp.campaigns().get();
while (campIter.hasNext()) {
var camp = campIter.next();
var adIter = buildSelector(camp, 'Ad');
adIter = adIter.withCondition('LabelNames CONTAINS_ANY [' + LABEL_NAMES.join(',') + ']');
adIter = adIter.get();
//Logger.log(iter.totalNumEntities());
while(adIter.hasNext()) {
var entity = adIter.next();
var url = entity.urls().getFinalUrl();
if (url === null)
continue;
url = cleanUrl(url);
if (prices[url]) {
setAdPrice(entity, prices[url]);
//Logger.log('Url: '+url+'; Price: '+prices[url]+'; Entity: '+entity);
} else {
var htmlCode;
try {
htmlCode = UrlFetchApp.fetch(url).getContentText();
} catch(e) {
Logger.log('There was an issue checking:'+url+', Skipping.');
continue;
}
var priceStart = htmlCode.indexOf(PRICE_TEXT_BEGIN) + PRICE_TEXT_BEGIN.length;
if(priceStart >= 0) {
var priceEnd = htmlCode.indexOf(PRICE_TEXT_END, priceStart);
prices[url] = htmlCode.substr(priceStart, priceEnd - priceStart).replace(/\D/, '');
//setKeywordPrice(keyword, prices[url]);
setAdPrice(entity, prices[url]);
//Logger.log('Url: '+url+'; Price: '+prices[url]+'; Entity: '+entity);
}
}
//Logger.log('Url: '+url+' price is '+prices[url]);
if(alreadyCheckedUrls[url]) {
if(alreadyCheckedUrls[url] === 'out of stock') {
entity.pause();
//keyword.pause();
} else {
entity.enable();
//keyword.enable();
}
} else {
var htmlCode;
try {
htmlCode = UrlFetchApp.fetch(url).getContentText();
} catch(e) {
Logger.log('There was an issue checking:'+url+', Skipping.');
continue;
}
if(htmlCode.indexOf(OUT_OF_STOCK_TEXT) >= 0) {
alreadyCheckedUrls[url] = 'out of stock';
entity.pause();
} else {
alreadyCheckedUrls[url] = 'in stock';
entity.enable();
}
Logger.log('Url: '+url+' is '+alreadyCheckedUrls[url]+'; price: '+prices[url]);
}
}
}
}
function cleanUrl(url) {
if(WRAPPED_URLS) {
url = url.substr(url.lastIndexOf('http'));
if(decodeURIComponent(url) !== url) {
url = decodeURIComponent(url);
}
}
if(STRIP_QUERY_STRING) {
if(url.indexOf('?')>=0) {
url = url.split('?')[0];
}
}
if(url.indexOf('{') >= 0) {
//Let's remove the value track parameters
url = url.replace(/\{[0-9a-zA-Z]+\}/g,'');
}
return url;
}
function buildSelector(camp, url_level) {
var selector = (url_level === 'Ad') ? camp.ads() : camp.keywords();
return selector;
}
В объявление добавляется динамический параметр: {param1:230} — где 230 любое число, если используется 4х значное, то указать 4х значное.
Проверка добавления цены только через поиск, в аккаунте в объявлении цена меняться не будет.
2. Копируем скрипт проверки наличия товаров:
/************************************ * Item Out Of Stock Checker * Version 1.1 * ChangeLog v1.1 - Filtered out deleted Campaigns and AdGroups * Created By: Russ Savage * FreeAdWordsScripts.com ***********************************/ var URL_LEVEL = 'Ad'; // or Keyword var ONLY_ACTIVE = false; // set to false for all ads or keywords var CAMPAIGN_LABEL = 'CampaignLabel'; // set this if you want to only check campaigns with this label var STRIP_QUERY_STRING = true; // set this to false if the stuff that comes after the question mark is important var WRAPPED_URLS = true; // set this to true if you use a 3rd party like Marin or Kenshoo for managing you account // This is the specific text to search for // on the page that indicates the item // is out of stock. var OUT_OF_STOCK_TEXT = 'availability gray'; function main() { var alreadyCheckedUrls = {}; var iter = buildSelector().get(); while(iter.hasNext()) { var entity = iter.next(); if(entity.urls().getFinalUrl()){ var url = cleanUrl(entity.urls().getFinalUrl(), entity); if(alreadyCheckedUrls[url]) { if(alreadyCheckedUrls[url] === 'out of stock') { entity.pause(); } else { entity.enable(); } } else { var htmlCode; try { htmlCode = UrlFetchApp.fetch(url).getContentText(); } catch(e) { Logger.log('There was an issue checking:'+url+', Skipping.'); continue; } if(htmlCode.indexOf(OUT_OF_STOCK_TEXT) >= 0) { alreadyCheckedUrls[url] = 'out of stock'; entity.pause(); } else { alreadyCheckedUrls[url] = 'in stock'; entity.enable(); } } Logger.log('Url: '+url+' is '+alreadyCheckedUrls[url]); } } } function cleanUrl(url, entity) { if (url) { if(WRAPPED_URLS) { url = url.substr(url.lastIndexOf('http')); if(decodeURIComponent(url) !== url) { url = decodeURIComponent(url); } } if(STRIP_QUERY_STRING) { if(url.indexOf('?')>=0) { url = url.split('?')[0]; } } if(url.indexOf('{') >= 0) { //Let's remove the value track parameters url = url.replace(/\{[0-9a-zA-Z]+\}/g,''); } } else Logger.log('Что-то пошло не так, в урле нулл: '+url+' '+ entity.getCampaign.getName+ ' -> ' +entity.getAdGroup.getName); return url; } function buildSelector() { //var selector = (URL_LEVEL === 'Keyword') ? AdWordsApp.ads() : AdWordsApp.keywords(); var selector = (URL_LEVEL === 'Keyword') ? AdWordsApp.keywords() : AdWordsApp.ads(); selector = selector.withCondition('CampaignStatus != DELETED').withCondition('AdGroupStatus != DELETED'); if(ONLY_ACTIVE) { selector = selector.withCondition('CampaignStatus = ENABLED').withCondition('Status = ENABLED'); if(URL_LEVEL !== 'Keyword') { selector = selector.withCondition('AdGroupStatus = ENABLED'); } } if(CAMPAIGN_LABEL) { var label = AdWordsApp.labels().withCondition("Name = '"+CAMPAIGN_LABEL+"'").get().next(); var campIter = label.campaigns().get(); var campaignNames = []; while(campIter.hasNext()) { campaignNames.push(campIter.next().getName()); } selector = selector.withCondition("CampaignName IN ['"+campaignNames.join("','")+"']"); } return selector; }
3. Помечаем ярлыками все объявления, в которых будем использовать подмену цены, чтобы наш скрипт смог их определить.
Название ярлыка можно увидеть на следующем скриншоте. Его можно заменить на свое.
4. Меняем заголовки или описания в объявлениях, которые мы пометили ранее ярлыком, путем добавления динамической вставки в текст {param1:230}. Это будет наша переменная, которая будет записываться в массив данных Google Ads, а далее — подставляться из массива в текст.
После двоеточия стоит цена 230 — это условная цена по умолчанию, чтобы понимать количество символов, которое она займет. После успешной установки скрипта и его запуска, эти данные автоматически заменятся на актуальную цену с сайта.
Важно! В объявлениях этого не видно, так как цена будет подтягиваться из массива данных внутри Google Ads и увидеть ее можно будет только в рекламной выдаче.
5. Добавляем ранее скачанный скрипт в библиотеку Google Ads. Просто создаете новый скрипт и полностью вставляете скопированный код в поле.
6. Определяем код, который включает в себя цену на сайте. Для этого нам необходимо открыть страничку товара на сайте, с которой мы будем парсить цену. Найти на странице цену и щелкнуть по ней правой кнопкой мыши, где выбрать «Просмотреть код элемента».
7. Находим этот код и указываем для скрипта обе его части, между которыми и находится наша цена. В нашем случае код выглядит так:
<span data-el_name=»default_price»>3215 </span>.
Определяем начало кода — <span data—el_name=»default_price«> И конец — </span>.
Важно! Внутри кода могут находиться не только цифры, а и текст вроде «всего», «от», «грн», «usd» и др. Различные символы и пробелы, которые находятся до и после цены, учитываются при ее определении. Поэтому обязательно указывайте их в скрипте, чтобы ничего лишнего, кроме цены товара, не вытянулось в наш параметр. После того, как мы определили Начало и Конец цены, добавляем эти части кода в скрипт.
8. Нажимаем сохранить скрипт. Затем нажимем кнопку «Просмотр» в правой нижней части экрана.
Если все сделано верно, то на вкладке «Журнал» можно будет наблюдать записи по полученным ценам для различных объявлений и ключевых слов.
После того, как все предыдущие операции были сделаны и отработали без ошибок, нажимаем кнопку «Сохранить».
Результаты работы подмены цены можно увидеть, если ввести целевой запрос товара в поиске. С помощью таких объявлений, перед кликом на рекламу мы даем представление о цене потенциальному клиенту. Таким образом мы получаем более горячие переходы по рекламе и исключаем в клики пользователей, для которых данные товары слишком дорогие.
Последним этапом в настройке скрипта будет создание расписания, в зависимости от частоты изменения цен на сайте.
Для это переходим в список скриптов аккаунта, для которого мы устанавливали наш скрипт, находим его из списка (если до этого у нас уже есть в аккаунте установленные ранее скрипты) и нажимаем на появившуюся кнопку редактирования в столбце «Частота». В появившемся окошке выбираем частоту и время срабатывания для нашего скрипта.
Далее настроим скрипт, который будет отключать объявления, естли товара нет в наличии на сайте.
Установка практически идентичная предудущему скрипту. Первым делом, помечаем ярлыком кампании, в которых мы рекламируем наши товары и будем проверять их наличие:
В нашем случае ярлык будет с названием «Test_In_Stock». По желанию название этого ярлыка можно изменить. В этом случае не забудьте поменять его и в самом скрипте.
Далее переходим на страничку с нашим товаром, которого нет в наличии. Находим на странице код элемента, который отвечает за наличие товара. В нашем случае товары, которые отсутствуют были без пометки «Нет в наличии». Вместо него на странице был кусок кода, который отвечал за количество оставшегося товара «Осталось 0 товаров». Этот код, в итоге, мы использовали для определения таких продуктов.
После определения текста, который отвечает за наличие товара на складе, мы добавляем новый скрипт в аккаунт и вставляем ранее определенный текст в него.
После этого, даем название своему скрипту и запускаем его предпросмотр:
Если все сделано верно, то на вкладке «Журнал» можно будет наблюдать записи по проверенным объявлениям:
После успешной установки, нажимаем на кнопку «Сохранить».
Не забудьте установить расписание запуска скрипта, в зависимости от частоты изменения наличия товаров на сайте. Установка расписания частоты аналогична скрипту динамической подмены цены в объявлении.
Выводы. С помощью таких простых и быстрых настроек в аккаунте, мы экономим себе тонну времени. Данные скрипты работают на многих наших проектах интернет-магазинов и выполняют самую большую часть рутинной работы, в то время как мы занимаемся более полезными задачами.
Эффективность кампаний, которые используют данные скрипты, намного выше. И, естественно, мы экономим большое количество денежных средств клиента не рекламируя товары, которых нет в наличии.
Надеемся, что данные скрипты и для вас будут очень полезны.
У нас с мужем свой интернет магазин небольшой, так что все ведем сами, по крайней мере стараемся, ваш скрипт стал для нас практически спасением. Спасибо за хорошо отработанный скрипт, проверили, действительно избавил нас от многих сложностей, т.к. до этого все делалось в ручную, уходило громадная куча времени, иногда даже просто не меняли цену, хотя была возможность, чтоб не возиться.