допомога маркетологу: пишемо автоматичне вивантаження даних з Adfox з візуалізацією

минулій статті був розглянутий приклад налаштування автоматичного вивантаження даних з Яндекс Метрики. Це полегшує регулярну вивантаження, але спосіб виходить напівавтоматичним: треба запускати скрипт, копіювати результати вивантаження до себе і далі займатися їх оформленням. Подивимося як можна зробити процес повністю автоматичним. Для прикладу будемо використовувати вивантаження даних їх рекламної системи Adfox.

Adfox має багато готових звітів, однак навіть прості ускладнення вимог до звітності викликають проблеми. Є опція налаштування регулярних звітів, однак у більшості випадків доводиться налаштовувати комбінації выгрузок самому.

У цій статті показано як зробити скрипт, який вивантажує CTR всіх банерів, які доступні аккаунту (зробити це вручну нереально часу). А також як відобразити це на графіку у вигляді простий HTML-сторінки. Тобто ми послідовно розглянемо всі кампанії і флайти, візьмемо покази та кліки по всіх банерів і намалюємо графік CTR. Як і в минулій статті працювати будемо на інстансах Amazon Web Services, щоб було універсально і головне безкоштовно. Вивантаження даних на PHP, графіки малюємо в Highcharts. У коді реалізований найпростіший спосіб вивантаження та обробки даних без яких-небудь поліпшень. В результаті отримаємо щодня оновлювану за вчорашній день сторінку виду
image


Починаємо з створення аккаунта на AWS (якщо ще немає). Ця процедура детально описана в документації docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-ug.pdf (до пункту Getting started). Далі ми пройдемо етап, описаний у цій же документації у розділі «Tutorial: Installing a LAMP Web Server on Amazon Linux»: встановимо потрібні нам для вивантаження і зберігання даних PHP і MySQL (надалі працювати з MySQL краще, ніж з текстовими файлами). Можна звичайно обійтися без цього, використовуючи вбудований Python. Запускаємо інстанси Amazon Linux (подробиці див. попередню статтю де ми вибирали інстанси Ubuntu Server). Тут нам знадобиться саме Linux, а не Ubuntu. Щоб запустити LAMP web server на Ubuntu дивіться документацію help.ubuntu.com/community/ApacheMySQLPHP. Отже, вибираємо інстанси Amazon Linux, перевіряємо Security Group і переконуємося що у нас є приватний ключ. Через пару хвилин отримуємо Public DNS нашого инстанса і подсоединяемся до нього через Putty (для Windows) або Terminal для MAC:


Ставимо LAMP web server. Виконуємо команду перевірки, що маємо останні оновлення:
$ sudo yum update -y

Ставимо PHP підходящої нам версії:
$ sudo yum install -y httpd24 php56 mysql55-server php56-mysqlnd

Запускаємо Apache web server:
$ sudo service httpd start

Хочемо, щоб Apache web server стартував при кожному запуску системи:
$ sudo chkconfig httpd on

Тестуємо, що все пройшло успішно: копіпаст в браузер Public DNS нашого инстанса і отримуємо наступну сторінку:


Зараз кореневої директорією /var/www/ «володіє» користувач root. Зробимо туди доступ користувачеві ec2-user:

Створюємо групу «www»:
$ sudo groupadd www

Додаємо користувача ec2-user в групу www:
$ sudo usermod -a -G www ec2-user

Щоб зміни вступили в силу закриваємо Putty або Terminal (команда exit) і подсоединяемся до инстансу ще раз. Перевіряємо, що користувач ec2-user прописаний в групі www:
$ groups
ec2-user wheel www

Змінюємо власника папки /var/www:
$ sudo chown -R root:www /var/www

Додаємо можливість користувачеві ec2-user та іншим користувачам з групи www права на зміну папки /var/www:
$ sudo chmod 2775 /var/www
$ find /var/www -type d -exec sudo chmod 2775 {} +
$ find /var/www -type f -exec sudo chmod 0664 {} +

Тестуємо, що тепер ми можемо створювати PHP-файли в директорії /var/www. Для цього створюємо файл phpinfo.php і записуємо в нього <?php phpinfo(); ?>:
$ echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php

Знову в адресному рядку браузера копіпаст Public DNS нашого инстанса і додаємо "/phpinfo.php". Ми повинні отримати наступну сторінку з конфігурацією PHP:


В цілях безпеки видаляємо створений нами файл phpinfo.php:
$ rm /var/www/html/phpinfo.php

Відмінно, ми готові до вивантаження даних з Adfox!

Вивантажуємо статистику Adfox
Документацію API Adfox можна знайти на сторінці help.adfox.ru (посилання на скачування в самому низу сторінки). В цілому документація складена не дуже наочно, тому в загальному випадку можна використовувати наступне правило: якщо вам потрібно отримати посилання для звіту в API, то копіюєте посилання з браузера і підставляєте в неї логін і пароль + '&isXML=1' для отримання даних у форматі XML. Якщо потрібні функції пошуку або налаштувань кампаній, то доведеться дивитися в документації API.

В загальному випадку запити до API Adfox супроводжуються логіном (як ви заходите в систему) і хэшом SHA-256 від вашого пароля. Згенерувати хеш до пароля можна на будь-якому сайті за пошуковим запитом «sha-256 online». Наприклад, тут: www.xorbin.com/tools/sha256-hash-calculator

Якщо ваш пароль «12345», то для звернень до API в якості пароля треба використовувати значення «5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5»:


Наш алгоритм буде складатися з двох кроків:

Крок 1. Отримуємо список всіх доступних нам кампаній
Візьмемо список доступних кампаній. Якщо кампаній багато, то можна обмежитися тими, що були заведені, наприклад, з 1 серпня:
login.adfox.ru/API.php?object=account&action=list&actionObject=superCampaign&dateAddedFrom=2015-08-01&loginAccount=логин&loginPassword=пароль-sha-256&isXML=1

У браузері отримаємо наступний XML-файл:


Крок 2. Для кожної кампанії маємо її назва (тег ) і ID (). Тепер для кожного ID отримуємо звіт по банерах (наприклад, для кампанії з ID=55555):
login.adfox.ru/commonReportsOutputForm.php?period=&startDate=начальная-дата&endDate=конечная-дата&criteria=superCampaignBanner&isNewSearch=on&objectName=superCampaign&objectID=55555&ignoreStartDate=off&loginAccount=логин&loginPassword=пароль-sha-256&isXML=1


Зробимо скрипт, який буде щодня робити цю процедуру і записувати дані в файл. Простіше всього буде зайти в папку /var/www/html, створити там папку adfox і створити в ній файл daily.php з таким кодом:

Код вивантаження даних Adfox
<?php

// Задаємо діапазон дат, за які вивантажуємо дані: startDate і a list
// Формат дат для запитів до Adfox дд.мм.рр
date_default_timezone_set("Europe/Moscow");
//$startDate = '04.09.15';
//$a list = '04.09.15';

// Для щоденних выгрузок вказуємо в якості дати вивантаження вчорашній день
$startDate = date('d.m.y', strtotime('-1 day'));
$a list = $startDate;

// Функція getCampaigns показує доступні даного логіном кампанії
// Повертає масив $campIDs з ID назвою кампаній
// В тілі запиту змінної dateAddedFrom можна вказати дату створення кампанії, щоб не вивантажувати все підряд
function getCampaigns(){
$ch = curl_init();
$options = array(
CURLOPT_URL => 'https://login.adfox.ru/API.php?object=account&action=list&actionObject=superCampaign&dateAddedFrom=2015-08-01&loginAccount=логин&loginPassword=пароль-sha-256&isXML=1',
CURLOPT_HEADER => "Content-Type:application/xml",
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_SSL_VERIFYPEER => FALSE,
CURLOPT_RETURNTRANSFER => TRUE
);

curl_setopt_array($ch, $options);
$data = curl_exec($ch);

curl_close($ch);

// Можна записати відповідь Adfox у файл, щоб переконатися в його вірності
// file_put_contents('request.txt', $data, FILE_APPEND);

// Перетворимо відповідь Adfox з XML в масив vals
$parser=xml_parser_create('UTF-8');
xml_parse_into_struct($parser, $data, $vals, $index);

$campIDs = array();
$j = 0;

// Проходимо масив vals, вибираючи з усіх параметрів ID і назва кампаній і записуючи їх в масив campIDs
for ($i = 0; $i < count($vals); ++$i) {

if ($vals[$i]["tag"]=="ID") {
$ID = $vals[$i]["value"];
}

if ($vals[$i]["tag"]=="NAME") {
$name = $vals[$i]["value"];

$campIDs[$j]['id'] = $ID;
$campIDs[$j]['name'] = $name;

$j += 1;
}
}

return $campIDs;
}

// Функція getBanners для заданої кампанії за її ID запитує звіт по банерам
// Звіт записується в масив campReport у вигляді ID кампанії + назва флайту - назва банера - покази - кліки
function getBanners($id, $startDate, $a list) {
$ch = curl_init();
$options = array(
CURLOPT_URL => 'https://login.adfox.ru/commonReportsOutputForm.php?period=&startDate='.$startDate.'&endDate='.$endDate.'&criteria=superCampaignBanner&isNewSearch=on&objectName=superCampaign&objectID='.$id.'&ignoreStartDate=off&loginAccount=логин&loginPassword=пароль-sha-256&isXML=1',
CURLOPT_HEADER => "Content-Type:application/xml",
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_SSL_VERIFYPEER => FALSE,
CURLOPT_RETURNTRANSFER => TRUE
);

curl_setopt_array($ch, $options);
$data = curl_exec($ch);

curl_close($ch);

//Можна записати відповідь Adfox у файл, щоб переконатися в його вірності
//file_put_contents('request.txt', $data, FILE_APPEND);

$parser=xml_parser_create('UTF-8');
xml_parse_into_struct($parser, $data, $vals, $index);

$campReport = array();
$j = 0;

for ($i = 0; $i < count($vals); ++$i) {
if ($vals[$i]["tag"]=="CRITERIA") {
$bannername = $vals[$i]["value"];
}

if ($vals[$i]["tag"]=="FLIGHTNAME") {
$flightname = $vals[$i]["value"];
}

if ($vals[$i]["tag"]=="IMPRESSIONS") {
$impressions = $vals[$i]["value"];
}

if ($vals[$i]["tag"]=="CLICKS") {
$clicks = $vals[$i]["value"];

$campReport[$j]['campaign'] = $id;
$campReport[$j]['flightname'] = $flightname;
$campReport[$j]['bannername'] = $bannername;
$campReport[$j]['impressions'] = $impressions;
$campReport[$j]['clicks'] = $clicks;

$j += 1;
}
}

return $campReport;
}

// Отримуємо список доступних кампаній
$campIDs = getCampaigns();

// Для кожної кампанії запитуємо звіт по банерам
for ($i = 0; $i < count($campIDs); ++$i) {
$campReport = getBanners($campIDs[$i]['id'], $startDate, $a list);

// Для кожного банера записуємо в файл data.txt результат запиту з показами і кліками
// Повний шлях до файлу data.txt потрібно вказувати для коректної роботи автоматичного вивантаження Cron
for ($j = 0; $j < count($campReport); ++$j) {
file_put_contents('/var/www/html/adfox/data.txt', $startDate."\t".$campReport[$j]['campaign']."\t".$campReport[$j]['flightname']."\t".$campReport[$j]['bannername']."\t".$campReport[$j]['impressions']."\t".$campReport[$j]['clicks']."\n", FILE_APPEND);

// Пишемо в консолі сходинку про створення запису (опціонально)
echo 'Record created - '.$startDate.' - '.$campReport[$j]['bannername']."\n";
}
}



Проганяємо код за кілька днів (наприклад, за 1-4 вересня), підставляючи в startDate і a list дати від 01.09.15 до 04.09.15. В результаті у файлі data.txt повинна накопичитися статистика по кожному банеру за кожен день з 1 по 4 вересня.

Залишилося відобразити наші дані на графіку і поставити скрипт на автоматичне оновлення. Для малювання графіків використовуємо www.highcharts.com/demo/line-basic. Можна завантажити бібліотеку на інстанси або звертатися до бібліотек на сайті Highcharts. У прикладі використовується другий варіант. Код всіх прикладів можна подивитися на www.highcharts.com/demo/line-basic, клікнувши під графіком кнопку «EDIT IN JSFIDDLE».

Для коректної роботи бібліотеки нам знадобиться jQuery. Завантажуємо його з сайту або відразу в консолі в папку /var/www/html/adfox:
$ wget code.jquery.com/jquery-1.11.3.js

Додаємо код графіка в файл report.html:
Код HTML-сторінки з візуалізацією
<html>
<head>

<script src="jquery-1.11.3.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>

</head>

<body>

<script>

// масив списку банерів, які були вивантажені в файл data.txt
var banners = [];

// масиви дат, показів і кліків, які завантажимо з файлу data.txt
// значення CTR (відношення кліків до показів) розрахуємо
var dates1 = [];
var shows1 = [];
var clicks1 = [];
var ctr1 = [];

var dates2 = [];
var shows2 = [];
var clicks2 = [];
var ctr2 = [];

var dates3 = [];
var shows3 = [];
var clicks3 = [];
var ctr3 = [];

// читаємо файл data.txt порядково
$.get("data.txt", function(data){
var lines = data.split("\n");
for (var i = 0, len = lines.length; i < len; i++) {
// перевіряємо на консолі, що файл прочитаний коректно
//console.log(lines[i]);

// поділяємо кожен рядок файлу на масив з 6 елементів відповідних стовпців в data.txt
elements = lines[i].split("\t");

// назва банера це третій за рахунком стовпець, відповідно бере третій елемент масиву elements
// (на всякий випадок - нумерація елементів масиву починається з 0, а не 1)
banners.push(elements[2]);
}
// перевіряємо, що назви банерів вважалися коректно
//console.log(banners);

// візьмемо унікальні назви банерів і запишемо в масив bannerNames перші 3 назви
Array.prototype.unique = function()
{
var tmp = {}, out = [];
for(var i = 0, n = this.length; i < n; ++i)
{
if(!tmp[this[i]]) { tmp[this[i]] = true; out.push(this[i]); }
}
return out;
}

bannersNames = banners.unique().slice(0, 3);

// перевіряємо, що отримали 3 коректних назви банерів
//console.log(bannersNames);

// проходимо ще раз файл data.txt і вибираємо дати, покази та кліки для банерів з масиву bannerNames
for (var i = 0, len = lines.length; i < len; i++) {

elements = lines[i].split("\t");

// якщо рядок у файлі data.txt відноситься до першого банеру, то додаємо в масив дат, показів і кліків значення цього рядка
if (elements[2] == bannersNames[0]) {
dates1.push(elements[0]);
shows1.push(parseInt(elements[4]));
clicks1.push(parseInt(elements[5]));

// toFixed(3) - округлюємо значення CTR до третього знака після коми
if (parseInt(elements[4]) > 0) {
ctr1.push(Number(parseFloat(elements[5] / elements[4] * 100).toFixed(3)));
} else {
ctr1.push(0);
}
}

// те ж саме для другого банера
if (elements[2] == bannersNames[1]) {
dates2.push(elements[0]);
shows2.push(parseInt(elements[4]));
clicks2.push(parseInt(elements[5]));
if (parseInt(elements[4]) > 0) {
ctr2.push(Number(parseFloat(elements[5] / elements[4] * 100).toFixed(3)));
} else {
ctr2.push(0);
}
}

// те ж саме для третього банера
if (elements[2] == bannersNames[2]) {
dates3.push(elements[0]);
shows3.push(parseInt(elements[4]));
clicks3.push(parseInt(elements[5]));
if (parseInt(elements[4]) > 0) {
ctr3.push(Number(parseFloat(elements[5] / elements[4] * 100).toFixed(3)));
} else {
ctr3.push(0);
}
}
}

// перевіряємо, що всі масиви CTR (які будуть на графіку) мають числовий формат
// наприклад: [0.22, 0.25, 0.30, 0.24]
//console.log(ctr1);
//console.log(ctr2);
//console.log(ctr3);

// відображаємо значення CTR на графіку
$(function (){
// назва блоку container повинно збігатися з вашим <div id="container"... внизу сторінки
$('#container').highcharts({
// заголовок графіка
title: {
text: 'Campaign banners CTR',
x: -20 //center
},

// підпис під заголовком
subtitle: {
text: 'Source: ADFOX',
x: -20
},

// в якості осі абсции беремо значення масиву дат dates1
xAxis: {
categories: dates1
},

// параметри осі ординат
yAxis: {
title: {
text: 'CTR %'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},

// параметри підказки при наведенні на графік
tooltip: {
valueSuffix: '%'
},

// параметри легенди
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},

// задаємо значення, які хочемо відобразити на графіку: назва банера і значення CTR з відповідного масиву
series: [{
name: bannersNames[0],
data: ctr1
}, {
name: bannersNames[1],
data: ctr2
}, {
name: bannersNames[2],
data: ctr3
}],
credits: {
enabled: false
}
});
});
});
</script>

<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>

</body>
</html>



Відкриваємо сторінку report.html у браузері, не забуваючи, що файл лежить в папці adfox:


Залишилося поставити наш скрипт на щоденне оновлення (наприклад, в 8:00 за системного часу инстанса, яке можна перевірити командою date в консолі). Для цього в консолі виконуємо:
$ crontab -e

За замовчуванням відкриється редактор vim. Для редагування файлу натисніть 'i' (режим редагування) і додайте наступний рядок (вставте в редактор з допомогою Shift+Ins):
00 08 * * * /usr/bin/php /var/www/html/adfox/daily.php > /var/www/html/adfox/out

Потім тиснемо esc (вихід з режиму редагування) і набираємо ':wq' — зберегти і вийти. В консолі повинна відображатися рядок:
crontab: installing new crontab

Для перевірки установки розкладу:
$ crontab -l
00 08 * * * /usr/bin/php /var/www/html/adfox/daily.php > /var/www/html/adfox/out

У файлі out можна відстежувати результати роботи Cron завдань. Наприклад, якщо виникнуть помилки в ході виконання скрипта.

Детальніше про Cron на AWS: docs.aws.amazon.com/opsworks/latest/userguide/workingcookbook-extend-cron.html

Все готово. Разом у нас є скрипт, який щодня вранці оновлює дані по показах і кліках всіх доступних нам банерів за вчорашній день. А також HTML-сторінка, на якій в будь-який час можна подивитися динаміку CTR банерів за останні кілька днів. На AWS є багато можливостей по налаштуванню безпечного доступу до даних. Також при вдосконаленні цього підходу можна записувати дані в базу MySQL, з якою набагато простіше працювати, ніж з текстовими файлами. Сподіваюся цей підхід допоможе вам заощадити час при регулярній роботі з Adfox.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.