Яндекс.Метрика
Ноутбук, используемый в примере:
В данной статье рассматривается пример получения данных с сервиса Яндекс.Метрика для последующей загрузки в платформу Visiology. Пример не является шаблонным: в каждом случае задачи разнятся, и работать с данными придется по-другому.
Вот особенности данного кейса:
Количество получаемых данных небольшое - порядка 250 тысяч строк, поэтому все выгруженные и обработанные данные сохраняются в XLSX файл, а не в CSV или SQL базу данных.
По той же причине (небольшой объем данных) данные забираются сразу одним запросом. При большем объеме нужно учитывать ограничения, описанные в Яндекс.Метрика API и применять другие методы получения данных, например, используя пагинацию.
Код в приложенном ноутбуке находится в статусе рабочего черновика и служит лишь в качестве примера. Для продакшна код точно можно улучшить, например, сократить количество переменных или неоптимальных преобразований.
Здесь не рассматривается:
Данные будут забираться с Яндекс.Метрики вручную. Для регулярной автоматический выгрузки необходимо настроить планировщик Chronicle.
Для дальнейшей загрузки в платформу можно воспользоваться стандартными средствами в платформе: “создание загрузчика” и “планы загрузки”. Всё описано в разделе документации (ссылка для версии 2.17):
https://visiology-doc.atlassian.net/wiki/pages/createpage.action?spaceKey=v17&title=%D0%97%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B0%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85%20%D0%B8%20%D1%84%D0%BE%D1%80%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B%20%D0%B2%20%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9%20%D0%B1%D0%B0%D0%B7%D0%B5%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85%20ViQubeПодробности работы подключенных Python библиотек. Это необходимо изучать отдельно.
Сначала необходимо внимательно ознакомиться с API Метрики: https://yandex.ru/dev/metrika/.
Теперь можно приступать к работе в JupyterLab.
Создаем новый ноутбук.
Первым блоком подключаем все необходимые нам для работы Python библиотеки:
from tapi_yandex_metrika import YandexMetrikaLogsapi from datetime import datetime import petl as etl
Вторым блоком получаем вчерашнюю дату. Эту необходимо для получения данных за какой-то выбранный период. Далее в запросе мы будем запрашивать данные с 1 января 2018 года по вчерашний день.
В платформе будет использоваться гранулярность календаря - день. Поэтому вчерашний день выбран, чтобы избежать неполноты данных за сегодня.year = datetime.date(datetime.now()).strftime("%Y") month = datetime.date(datetime.now()).strftime("%m") day = str(int(datetime.date(datetime.now()).strftime("%d"))-1) date = year + '-' + month + '-' + day
Задаем свой токен и номер счетчика в Яндекс.Метрике. Что это такое и как получить лучше смотреть в первоисточнике:
ACCESS_TOKEN = "balblablablablayakrevedko" COUNTER_ID = "563547"
Обращаемся к API, используя токен и ID счетчика. Также указываем нужные нам настройки работы с API. В данном случае это wait_report=True, что позволит нам ожидать завершения генерации отчета на сервере Яндекс.Метрики до попытки его скачать. Если ее не поставить, то может возникнуть ситуация, когда мы пытаемся скачать отчет, который сервер Яндекса еще не успел сгенерировать.
api = YandexMetrikaLogsapi( access_token=ACCESS_TOKEN, default_url_params={'counterId': COUNTER_ID}, wait_report=True )
Задаем параметры для получения двух отчетов: визиты и просмотры страниц. Эти параметры ниже будут передаваться в Яндекс.Метрику для генерации отчетов. Тут, например, указывается начальная дата - 1 января 2018 и конечная дата - вчерашний день.
paramsVisit={ "fields": "ym:s:date,ym:s:clientID,ym:s:lastTrafficSource,ym:s:visitDuration," \ "ym:s:pageViews,ym:s:isNewUser,ym:s:visitID,ym:s:watchIDs," \ "ym:s:lastAdvEngine,ym:s:deviceCategory,ym:s:mobilePhone", "source": "visits", "date1": "2018-01-01", "date2": date } paramsWatch={ "fields": "ym:pv:watchID,ym:pv:URL,ym:pv:isPageView,ym:pv:UTMCampaign", "source": "hits", "date1": "2018-01-01", "date2": date }
В следующих трех блоках мы создаем необходимые нам два отчета на сервере Яндекс.Метрики и скачиваем их по айдишникам. Как раз на блоке скачивания и происходит ожидание, пока отчеты сгенерируются на сервере.
resultV = api.create().post(params=paramsVisit) resultW = api.create().post(params=paramsWatch) requestV_id = resultV().data["log_request"]["request_id"] requestW_id = resultW().data["log_request"]["request_id"] resultV = api.download(requestId=requestV_id).get() resultW = api.download(requestId=requestW_id).get()
Кладем полученные данные в переменные.
dataV = resultV().data dataW = resultW().data
Сейчас в переменных dataV и dataW данные лежат просто в виде строки. Так мы их далее использовать не сможем для формирования таблицы. Преобразуем их в список по разделителю новой строки \n.
dataV = dataV.split('\n') dataW = dataW.split('\n')
Создаем переменные, которые будут использоваться дальше в преобразовании данных. В нашем конкретном примере на выходе мы хотим получить одну большую таблицу по просмотрам страниц с добавленной информацией по визитам. То есть далее будем две таблицы сливать в одну. В иных ситуациях это слияние может быть ненужным, и в платформу будут загружаться две таблицы. Мы же на выходе хотим одну таблицу со всеми данными из двух полученных отчетов по просмотрам и визитам.
wvTable = [[]] visitTable = [[]] watchTable = [[]] visitArray = [] watchArray = []
В переменных *Table для хранения таблиц задаем заголовки таблиц. В комментариях указано сопоставление строчек таблиц для их последующего слияния. Для таблицы visitTable сопоставление смещается, так как мы далее будем удалять седьмой столбец “Список просмотров“ за ненадобностью.
wvTable[0] = ['VisitID', 'WatchID'] watchTable[0] = [ 'WatchID', #0 <- 0 'URL', #1 <- 1 'isPageView', #2 <- 2 'UTMCompain' #3 <- 3 ] visitTable[0] = [ 'Дата', #0 <- 0 'ClientID', #1 <- 1 'Источник', #2 <- 2 'Продолжительность визита', #3 <- 3 'Количество страниц', #4 <- 4 'Новый пользователь', #5 <- 5 'VisitID', #6 <- 6 'Рекламная система', #7 <- 8 'Тип устройства', #8 <- 9 'Тип мобильного устройства', #9 <- 10 ]
Удаляем седьмую колонку из таблицы visitTable, используя временный массив и наполняем таблицу данными по визитам.
for i in range(1, len(dataV)-1): visitArray = dataV[i].split('\t') visitTable.append(visitArray[:7] + visitArray[8:])
Создаем таблицу соответствия визитов и просмотров, где в каждой строке находится отдельный просмотр и этому просмотру сопоставлен id визита.
for i in range(1, len(dataV)-1): visitArray = dataV[i].split('\t') watchArray = visitArray[7][1:len(visitArray[7])-1].split(',') for watch in watchArray: wvTable.append([visitArray[6],watch])
Наполняем таблицу данными по просмотрам.
for i in range(1, len(dataW)-1): watchTable.append(dataW[i].split('\t'))
Сшиваем таблицу просмотров с таблицей соответствия визитов и просмотров с помощью LEFT JOIN. Теперь у нас есть одна таблица со всеми данными по просмотрам и еще данные по визитам, которым эти визиты соответствуют.
watchTable = etl.leftjoin(watchTable, wvTable, key='WatchID')
Выкидываем все строчки, у которых нет VisitID, а также у которых isPageView = 0 (это запросы поисковых роботов, они нам не нужны).
watchTable = etl.select(watchTable, lambda rec: rec.VisitID != None) watchTable = etl.select(watchTable, lambda rec: rec.isPageView != '0')
Объединяем таблицы по просмотрам и визитам.
watchTable = etl.leftjoin(watchTable, visitTable, key='VisitID')
Расшифровываем коды типов устройств.
watchTable = etl.convert(watchTable, 'Тип устройства', 'replace', '1', 'Десктоп') watchTable = etl.convert(watchTable, 'Тип устройства', 'replace', '2', 'Мобильные телефоны') watchTable = etl.convert(watchTable, 'Тип устройства', 'replace', '3', 'Планшеты') watchTable = etl.convert(watchTable, 'Тип устройства', 'replace', '4', 'TV')
В колонке “Рекламная система” содержится много разных типов систем. Нам же достаточно знать Яндекс это или Google, поэтому оставляем только символы до нижнего подчеркивания.
watchTable = etl.convert(watchTable, 'Рекламная система', lambda v: v.split('_')[0])
Правим тип данных на integer у двух колонок.
watchTable = etl.convert(watchTable, 'Продолжительность визита', int) watchTable = etl.convert(watchTable, 'Количество страниц', int)
Добавляем дополнительные колонки с данными для нашей конкретной бизнес-задачи. Это нужно для лучшей визуализации отчетов в платформе Visiology.
watchTable = etl.addfield(watchTable, 'Длительность просмотра', lambda row: 'меньше 15 сек' if row['Продолжительность визита'] < 15 else ('от 15 до 30 сек' if row['Продолжительность визита'] >= 15 and row['Продолжительность визита'] < 30 else ('от 30 до 60 сек' if row['Продолжительность визита'] >= 30 and row['Продолжительность визита'] < 60 else 'более минуты'))) watchTable = etl.addfield(watchTable, 'Глубина просмотра', lambda row: 'не более 1' if row['Количество страниц'] <= 1 else ('2-3' if row['Количество страниц'] >= 2 and row['Количество страниц'] <= 3 else 'больше 3')) watchTable = etl.addfield(watchTable, 'Качество трафика', lambda row: 'хорошее' if (row['Количество страниц'] > 1 and row['Продолжительность визита'] >= 15) else ('плохое' if (row['Количество страниц'] <= 1 and row['Продолжительность визита'] < 15) else 'среднее'))
Экспортируем в Excel.
etl.io.xlsx.toxlsx(watchTable, "oneTable.xlsx", sheet=None, write_header=True)
Не забываем убедиться в том, что ресурсов на сервере хватает на формирование большого XLSX файла.
23. Полученный файл можно брать и загружать в платформу через стандартный загрузчик. На этом работа в ViXtract завершена.