🇺🇦 Ми працюємо: ПН-ПТ: 09:00-18:00 (Київ) Telegram Viber WhatsApp
Київ / Одеса (Україна):+38-098-887-05-49

Попит на різні товари та послуги залежить від багатьох умов. У деяких випадках певний вплив мають погодні умови. Наприклад, у дощову погоду відмічено підвищення попиту замовлення з доставок їжі (суші, піца тощо.).

Зміну ставок вручну необхідно робити регулярно, швидко і у великій кількості кампаній, що тягне за собою збільшення тимчасових і, відповідно, грошових витрат.

У зв'язку з цими спостереженнями, виникла потреба автоматизації зміни ставок у дні, коли йде дощ. Для цієї мети чудово підходить скрипт управління кампанією з урахуванням погоди.

Для використання скрипту потрібно зареєструватися у сервісі OpenWeatherMap та отримати ключ API.

Друге, що потрібно, — скопіювати шаблон електронної таблицідані якої будуть використовуватися скриптом. Вона містить 3 аркуші, які потрібно заповнити:

  • Campaigns — перелік кампаній, для яких будуть змінюватися ставки (назви повинні бути такими ж, як і в Google AdWords)
    image02

Стовпці Weather Location та Weather Condition зв'язуються з листами Geo Target Mapping та Weather Condition відповідно.

Стовпець Bid Modifier містить коефіцієнт зміни ставки за вибраних погодних умов. У цьому прикладі вибрано для дощової погоди збільшення ставки на 20%, а потім зменшення ставки на 20% до вихідного значення.

  • Weather Condition — лист з вибраними погодними умовами
    image00

У цьому прикладі визначено два типи стану погоди: Sunny (Сонячна) та Rainy (Дощова). Також обрана температура повітря у Фаренгейтах, кількість опадів за останні 3 години у мм та швидкість вітру у м/год.

  • Geo Target Mapping - лист з назвою розташування та кодом геотаргетингу
    image01

Детальний список розташування можна переглянути тут, а всі допустимі коди геотаргетингу тут.

Для одного розташування може бути визначено кілька кодів геотаргетингу. Для цього в таблиці просто створіть рядки з тим самим місцем розташування та відповідним кодом.

Важливо пам'ятати, що у кампанії, для якої налаштовується скрипт, повинен бути заданий геотаргетинг на вибране місцезнаходження, інакше він не виконуватиме жодних змін ставок.

Після того, як будуть виконані описані вище налаштування, додайте код скрипту, наведений нижче:

var OPEN_WEATHER_MAP_API_KEY = "OPEN_WEATHER_MAP_API_KEY";
var SPREADSHEET_URL = 'SPREADSHEET_URL';
var WEATHER_LOOKUP_CACHE = {};
function main() {
  var spreadsheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
  var campaignRuleData = getSheetData(spreadsheet, 1);
  var weatherConditionData = getSheetData(spreadsheet, 2);
  var geoMappingData = getSheetData(spreadsheet, 3);
  var campaignMapping = buildCampaignRulesMapping(campaignRuleData);
  var weatherConditionMapping =buildWeatherConditionMapping(weatherConditionData);
  var locationMapping = buildLocationMapping(geoMappingData);
  for (var campaignName in campaignMapping) {
    applyRulesForCampaign(campaignName, campaignMapping[campaignName], locationMapping, weatherConditionMapping);
  }
}
function getSheetData(spreadsheet, sheetIndex) {
  var sheet = spreadsheet.getSheets()[sheetIndex];
  var range = sheet.getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn());
return range.getValues();
}
function buildCampaignRulesMapping(campaignRulesData) {
  var campaignMapping = {};
  for (var i = 0; i < campaignRulesData.length; i++) {
    if (campaignRulesData[i][4].toLowerCase() == 'yes') {
      var campaignName = campaignRulesData[i][0];
      var campaignRules = campaignMapping[campaignName] || [];
      campaignRules.push({
          'name': campaignName,
          'location': campaignRulesData[i][1],
          'condition': campaignRulesData[i][2],
          'bidModifier': campaignRulesData[i][3]
      });
      campaignMapping[campaignName] = campaignRules;
    }
  }
  return campaignMapping;
}
function buildWeatherConditionMapping(weatherConditionData) {
  var weatherConditionMapping = {};
  for (var i = 0; i < weatherConditionData.length; i++) {
    var weatherConditionName = weatherConditionData[i][0];
    weatherConditionMapping[weatherConditionName] = {
      'condition': weatherConditionName,
      'temperature': weatherConditionData[i][1],
      'precipitation': weatherConditionData[i][2],
      'wind': weatherConditionData[i][3]
    };
  }
  return weatherConditionMapping;
}
function buildLocationMapping(geoTargetData) {
  var locationMapping = {};
  for (var i = 0; i < geoTargetData.length; i++) {
    var locationName = geoTargetData[i][0];
    var locationDetails = locationMapping[locationName] || {
      'geoCodes': []      
    };
    locationDetails.geoCodes.push(geoTargetData[i][1]);
    locationMapping[locationName] = locationDetails;
  }
  return locationMapping;
}
function applyRulesForCampaign(campaignName, campaignRules, locationMapping, weatherConditionMapping) {
  for (var i = 0; i < campaignRules.length; i++) {
    var bidModifier = 1;
    var campaignRule = campaignRules[i];
    var locationDetails = locationMapping[campaignRule.location];
    var weather = getWeather(campaignRule.location);
    var weatherConditionName = campaignRule.condition;
    var weatherConditionRules = weatherConditionMapping[weatherConditionName];
    if (evaluateWeatherRules(weatherConditionRules, weather)) {
      bidModifier = campaignRule.bidModifier;
      adjustBids(campaignName, locationDetails.geoCodes, bidModifier);
    }
  }
  return;
}
function toFahrenheit(kelvin) {
  return (kelvin - 273.15) * 1.8 + 32;
}
function evaluateWeatherRules(weatherRules, weather) {
  var precipitation = 0;
  if (weather.rain && weather.rain['3h']) {
    precipitation = weather.rain['3h'];
  }
  var temperature = toFahrenheit(weather.main.temp);
  var windspeed = weather.wind.speed;
  return evaluateMatchRules(weatherRules.temperature, temperature) &&
      evaluateMatchRules(weatherRules.precipitation, precipitation) &&
      evaluateMatchRules(weatherRules.wind, windspeed);
}
function evaluateMatchRules(condition, value) {
  if (condition == '') {
    return true;
  }
  var rules = [matchesBelow, matchesAbove, matchesRange];
  for (var i = 0; i < rules.length; i++) {
    if (rules[i](condition, value)) {
      return true;
    }
  }
  return false;
}
function matchesBelow(condition, value) {
  conditionParts = condition.split(' ');
  if (conditionParts.length != 2) {
    return false;
  }
  if (conditionParts[0] != 'below') {
    return false;
  }
  if (value < conditionParts[1]) {
    return true;
  }
  return false;
}
function matchesAbove(condition, value) {
  conditionParts = condition.split(' ');
  if (conditionParts.length != 2) {
    return false;
  }
  if (conditionParts[0] != 'above') {
    return false;
  }
  if (value > conditionParts[1]) {
    return true;
  }
  return false;
}
function matchesRange(condition, value) {
  conditionParts = condition.replace('\w+', ' ').split(' ');
  if (conditionParts.length != 3) {
    return false;
  }
  if (conditionParts[1] != 'to') {
    return false;
  }
  if (conditionParts[0] <= value && value <= conditionParts[2]) {
    return true;
  }
  return false;
}
function getWeather(location) {
  if (location in WEATHER_LOOKUP_CACHE) {
    return WEATHER_LOOKUP_CACHE[location];
  }
  var url = Utilities.formatString('http://api.openweathermap.org/data/2.5/weather?APPID=%s&q=%s', encodeURIComponent(OPEN_WEATHER_MAP_API_KEY), encodeURIComponent(location));
  var response = UrlFetchApp.fetch(url);
  if (response.getResponseCode() != 200) {
    throw Utilities.formatString('Error returned by API: %s, Location searched: %s.', response.getContentText(), location);
  }
  var result = JSON.parse(response.getContentText());
  if (result.cod != 200) {
    throw Utilities.formatString('Error returned by API: %s,  Location searched: %s.', response.getContentText(), location);
  }
  WEATHER_LOOKUP_CACHE[location] = result;
  return result;
}
function adjustBids(campaignName, geocodes, bidModifier) {
  var campaignIterator = AdWordsApp.campaigns().withCondition( Utilities.formatString('CampaignName = "%s"', campaignName)).get();
  while (campaignIterator.hasNext()) {
    var campaign = campaignIterator.next();
    var locations = campaign.targeting().targetedLocations().get();
    while (locations.hasNext()) {
      var location = locations.next();
      var currentBidModifier = location.getBidModifier().toFixed(2);
      if (geocodes.indexOf(location.getId()) != -1 &&
          currentBidModifier != bidModifier) {
        location.setBidModifier(bidModifier);
      }
    }
  }
}

 


У коді замініть значення змінних OPEN_WEATHER_MAP_API_KEY та SPREADSHEET_URL на отриманий ключ API сервісу погоди та посилання на таблицю Bid by Weather відповідно. Після цього встановіть частоту виконання сценарію. На цьому все.

Таким чином, якщо Ваш бізнес певною мірою залежить від погодних умов, Ви сміливо можете використовувати цей скрипт та експериментувати з налаштуваннями. Якщо виникнуть якісь питання, ми з радістю дамо відповідь на них у коментарях.

 

Автор: web-програміст агентства стратегічного інтернет-маркетингу «StarMarketing» Катерина Дем'янчук

 


Про автора - Вадим Стеблінський

Українська