🇺🇦 Мы работаем: ПН-ПТ: 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» Екатерина Демянчук

 


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

Русский