Две недели назад овнер Profit Agency, CEO GXT и ведущая собственных авторских подкастов «Будет хуже» — Маша Дорвей, поделилась с комьюнити крутым лайфхаком, позволяющим подсмотреть рекламу конкурентов в Telegram Ads. Учитывая, что каких-либо публичных спай-сервисов для Телеги до этого не существовало — предложенная идея существенно упрощает жизнь.
Но есть одно «но»
Однако используемый в лайфхаке Маши сервис tgstat.ru изначально не задумывался как спай, а потому при его использовании очень много времени уходит на «работу ручками». Мы связались с представителями tgstat.ru и расспросили их о про сбор интересующей нас информации по API. К сожалению, ответ нас не удовлетворил.
Поэтому мы решили «изобрести велосипед» и автоматизировать сбор инфы о креативах конкурентов самостоятельно. Сразу предупреждаем: «колеса у велосипеда кривые», но мы и не программисты. Главное — «ехать можно». Скрипт автоматизирует действия «ручками», а значит — экономит время. А что еще нужно-то?
Для лучшего понимания процесса, ниже мы в деталях расписали алгоритм скрипта. Тем, кто «может в код», по большому счету это ни к чему — там ничего сложного. Можете прокрутить до раздела «исходный код». Но если же вы такой же «не программист», как и мы — советуем ознакомиться, чтобы понимать принцип работы.
Принцип работы скрипта
Каких-либо специальных методов API для вывода инфы о креативах у tgstat.ru нет. Во всяком случае в публичном доступе (даже для самых крутых тарифов). Однако сама информация на их сайте выводится. Минимальный диапазон времени — час. Проще говоря, tgstat.ru позволяет видеть ежечасный ответ о закупах рекламы.
Более того, их движок генерирует отдельную страницу для каждого такого отчета. Найти url таких страниц можно, изучив исходный код сайта. В общем, если не вдаваться в подробности — для каждого изучаемого канала у нас будет ссылка, в конце которой цифры. Эти цифры — время и дата.
Дальше все просто:
- Мы берем общий url.
- Подставляем в него исследуемый канал.
- Подставляем «стартовое» время.
- Подставляем «конечное» время.
- Засовываем все это в цикл, изменяющий «цифры ссылки» (время и дату) с шагом 1 час.
- Записываем собранную инфу на каждом шаге.
- Ждем завершения цикла.
- Фильтруем совпадения.
- Выводим собранную инфу.
Если вы совсем далеки от темы, но очень хотите автоматизировать спаинг, — покажите это ТЗ любому фрилансеру-программисту. Это простейший скрипт, с которым справится даже школьник, если он обладает базовыми знаниями программирования. Спросите тех, кто в теме, — они не дадут соврать. Впрочем, перейдем к коду.
Исходный код
Так как наши читатели обладают разными уровнями знаний и разными финансовыми возможностями, — мы решили написать наиболее универсальный вариант, не требующий затрат на аренду сервера. Увы, большинство бесплатных хостингов не подойдут для этой задачи, так как у них лимитировано процессорное время.
Поэтому сделаем сервер на своем ПК! Да-да, ребят, — Denwer :) Почему он? Потому что те, кто в теме, все равно сделают по-своему, им главное — понять алгоритм. А тем, кто не в теме, разобраться с Denwer будет значительно проще, чем с любым другим сервером.
Расписывать процесс установки не будем — он не сложнее, чем инсталляция компьютерной игры. Просто не меняйте стандартные настройки — для нашей задачи этого хватит за глаза. Когда денвер будет установлен, делаем следующее:
- Переходим в C:\WebServers\home\localhost\www\
- Создаем папку с любым название на английском (желательно без символов). Например — tgstats.
- Открываем директорию C:\WebServers\home\localhost\www\tgstats (либо ваше название папки вместо tgstats).
- Создаем в ней файл index.php (убедитесь, что у вас отображаются расширения файлов).
- Открываем его блокнотом.
- Вводим в него следующий код:
<?php
$channel = $_POST['channel'];
$date_start = $_POST['date_start'];
$date_end = $_POST['date_end'];
$timezone = $_POST['timezone'];
$logdate1 = strtotime($date_start);
$logdate2 = strtotime($date_end);
$logdate1=date("d.m.y", $logdate1);
$logdate2=date("d.m.y", $logdate2);
$filename=$channel."-".$logdate1."-".$logdate2.".txt";
$filename = str_replace(' ', '', $filename);
if (!file_exists("logs")) {
mkdir("logs");
}
if (file_exists("logs/-01.01.70-01.01.70.txt")) {
unlink("logs/01.01.70-01.01.70.txt");
}
if (!file_exists("test.bat")) {
$fp = fopen("test.bat", "w");
fwrite($fp, '"C:\Program Files\Google\Chrome\Application\chrome.exe" "http://127.0.0.1/tgstats/index.php"');
fclose($fp);}
if($_POST["clear"]=="clear") {
$fp = fopen("status.txt", "w");
fwrite($fp, "2");
fclose($fp);}
echo iconv("utf-8", "windows-1251", '
<form action="index.php" method="post">
<p><input type="submit" value="Сбросить кэш"></p>
</form>')
;
if (file_exists("status.txt")) {
if($_POST['logclear']=="go") {
$fp = fopen("status.txt", "w");
fwrite($fp, "3");
fclose($fp);
$file3 = fopen("logs/$filename","w");
fwrite($file3,"");
fclose($file3);
}
$status = file("status.txt");
$status = str_replace(' ', '', $status);
if ($status[0] != 3) {
$file = fopen("cache.txt","w");
fwrite($file,"$channel\n$date_start\n$date_end\n$timezone");
fclose($file);
$date_new = $date_start;
$date_new = strtotime($date_new);
$timezonestamp = $timezone*3600;
$date_new = $date_new+$timezonestamp;
$file2 = fopen("test.txt","w");
fwrite($file2,"$date_new");
fclose($file2);
$arr = file("cache.txt");
$channel = $arr[0];
$date_start = $arr[1];
$date_end = $arr[2];
$timezone = $arr[3];
$start="Задать";
$start_text="Задать параметры";
echo iconv("utf-8", "windows-1251", '
<form action="index.php" method="post">
<p><red><b>*Обратите внимание! Для корректной работы скрипта необходимо придерживаться установленного формата ввода данных.</b></red></p>
<p>Название канала:<input name="channel" placeholder="trafficcardinal" value="'.$channel.'"/></p>
<p>Начальная дата:<input name="date_start" placeholder="2023-02-20 00:00:00" value="'.$date_start.'"/></p>
<p>Конечная дата:<input name="date_end" placeholder="2023-02-23 23:00:00" value="'.$date_end.'"/></p>
<p>Часовой пояс:<input name="timezone" placeholder="+3" value="'.$timezone.'"/></p>
');
if ($logdate1 != "01.01.70" and $logdate2 != "01.01.70"){
if (file_exists("logs/$filename")) {
echo iconv("utf-8", "windows-1251", 'Анализ по такому запросу уже производился: ');
echo '<br>';
echo '<a href="index.php?someValue='.$filename.'">'.$filename.'</a>';
echo '<br>';
}
$start="Начать сканирование";
$start_text="Начать";
echo iconv("utf-8", "windows-1251", '
<p><b>Подтвердить (*обязательно для начала сканирования):</b> <input type="checkbox" name="logclear" value="go">
');
} echo iconv("utf-8", "windows-1251", '
<p>'.$start_text.': <input type="submit" value="'.$start.'"></p>
</form>');
echo iconv("utf-8", "windows-1251", '
<form action="index.php" method="post">
<p><b>Показать историю сканирования:</b> <input type="checkbox" name="show" value="show">
<p><input type="submit" value="Показать"></p>
</form>
');
if($_POST["show"]=="show") {
$logs = scandir('logs/');
echo iconv("utf-8", "windows-1251", '<b>История сканирования:</b>');
echo '<br>';
foreach ($logs as $log) {
echo '<a href="index.php?someValue='.$log.'">'.$log.'</a>';
echo '<br>';
}
}
$someValue = $_GET['someValue'];
if (isset($someValue)) {
$filename=$someValue;
$arr = file("logs/$filename");
$arr = preg_replace('/\s+/', ' ', $arr);
$arr = preg_replace('/Пост[[:digit:]][[:digit:]] /', '', $arr);
$arr = preg_replace('/Пост[[:digit:]] /', '', $arr);
$arr = str_replace('------------------------------------', '', $arr);
while (in_array(' ',$arr)) {
$arr = str_replace(' ', ' ', $arr);
}
$count = count($arr);
$arr2=array_unique($arr,SORT_REGULAR);
$count2 = count($arr2);
$creo_log=substr($filename,0,-4);
array_unshift($arr2,"Креативы $creo_log\r\n");
$arr3=array_unique($arr2,SORT_REGULAR);
$count3 = count($arr3);
print "\r\n";
for ($i=0; $i<=$count3;){
echo nl2br(urldecode(iconv("utf-8", "windows-1251", $arr3[$i])));
echo "<br>";
print "\r\n";
$i=$i+1;
}
$fp = fopen("status.txt", "w");
fwrite($fp, "2");
fclose($fp);
}
}
elseif ($status[0] == 3) {
$arrz = file("cache.txt");
$arrz = preg_replace('/\s+/', '', $arrz);
$channel = $arrz[0];
$channel = str_replace(' ', '', $channel);
$date_start = $arrz[1];
$date_start = str_replace(' ', '', $date_start);
$date_end = $arrz[2];
$date_end = str_replace(' ', '', $date_end);
$timezone = $arrz[3];
$timezone = str_replace(' ', '', $timezone);
$microtime = microtime(true);
$date_start = strtotime($date_start);
$date_end = strtotime($date_end);
$date_new = htmlentities(file_get_contents("test.txt"));
$logdate1=date("d.m.y", $date_start);
$logdate2=date("d.m.y", $date_end);
$filename=$channel."-".$logdate1."-".$logdate2.".txt";
$filename = str_replace(' ', '', $filename);
if ($date_new<=$date_end){
$fp = fopen("logs/$filename", "a");
$datestamp2=date("d.m.y", $date_new);
fwrite($fp, " \r\n [".$datestamp2."] \r\n ");
fclose($fp);
$pattern = '/\s*<div class="font-14 mt-1 text-dark">\s*<\/div>\s*/im';
$date1 = htmlentities(file_get_contents("test.txt"));
$date1 = $date1+(-1*$timezone);
$date2 = $date1+82800;
sleep(1);
$i=0;
for ($date = $date1; $date<=$date2;){
$fp = fopen("logs/$filename", "a");
fwrite($fp,"Пост".$i);
fclose($fp);
$datestamp=date("ymdHs", $date);
$data = file_get_contents("http://tgstatsat.ru/channel/".$channel."/stat/sp-messages-details?timecode=".$datestamp);
preg_match_all('#<div class="font-14 mt-1 text-dark">(.+?)</div>#is', $data, $arr);
$count = count($arr[0]);
$j=0;
for ($j = 0; $j <= $count; $j++) {
$arr[0][$j]=strip_tags($arr[0][$j]);
$arr[0][$j] = str_replace(' ', "", $arr[0][$j]);
$fp = fopen("logs/$filename", "a");
fwrite($fp, $arr[0][$j]);
fclose($fp);
}
$fp = fopen("logs/$filename", "a");
fwrite($fp, "\r\n ------------------------------------ \r\n");
fclose($fp);
$date=$date+3600;
$i=$i+1;
}
$date_new=$date_new+86400;
$fp2 = fopen("test.txt", "w");
fwrite($fp2, $date_new);
fclose($fp2);
}
sleep(5);
if ($date_new<$date_end){
exec('cmd /c C:\WebServers\home\localhost\www\tgstats\test.bat');
echo '<script>window.close()</script>';
}
else {
$arr = file("logs/$filename");
$arr = preg_replace('/\s+/', ' ', $arr);
$arr = preg_replace('/Пост[[:digit:]][[:digit:]] /', '', $arr);
$arr = preg_replace('/Пост[[:digit:]] /', '', $arr);
$arr = str_replace('------------------------------------', '', $arr);
while (in_array(' ',$arr)) {
$arr = str_replace(' ', ' ', $arr);
}
$count = count($arr);
$arr2=array_unique($arr,SORT_REGULAR);
print "\r\n";
$count2 = count($arr2);
print "\r\n";
$creo_log=substr($filename,0,-4);
array_unshift($arr2,"Креативы $creo_log\r\n");
$arr3=array_unique($arr2,SORT_REGULAR);
$count3 = count($arr3);
print "\r\n";
for ($i=0; $i<=$count3;){
echo nl2br(urldecode(iconv("utf-8", "windows-1251", $arr3[$i])));
echo "<br>";
print "\r\n";
$i=$i+1;
}
$fp = fopen("status.txt", "w");
fwrite($fp, "2");
fclose($fp);
}
}
}
else{
$fp = fopen("status.txt", "w");
fwrite($fp, "2");
fclose($fp);
;
}
?>
- Сохраняем файл.
- Запускаем Denwer с ярлыка на рабочем столе.
- Открываем браузер.
- Вводим в адресную строку http://127.0.0.1/tgstats/ (либо ваше название папки вместо tgstats).
- Жмем «Сбросить кеш».
- Указываем интересующий нас канал.
- Указываем «стартовую» дату исследования.
- Указываем «конечное» время исследования.
- Указываем часовой пояс.
- Запускаем скрипт.
- Изучаем чужие креативы :)
Как это работает — наглядная инструкция
Почему «колеса кривые» и чем это чревато
Будет правильно заранее расписать возможные проблемы для тех, кто не особо понимает, что только что сделал. Итак:
Во-первых, раз у TGStat нет API под эту задачу, значит, они не хотят, чтобы пользователи могли так делать. Не хотят — это не обязательно «против», это может быть и «вообще не думали об этом». Но, может, и «против». В последнем случае, если фича станет использоваться массово — ее могут прикрыть и придется искать другой способ автоматизации. Так что критически важные процессы на этом лайфхаке не завязывайте.
Во-вторых, мы не тестили работоспособность скрипта под реально высокой нагрузкой. Но в этом и нет нужды — при высокой нагрузке (если вы будете мониторить несколько десятков или сотен каналов одновременно) сервер TGStat гарантированно «отключит вас» от себя. Соответственно, использование VPN — неизбежно.
Ну и в-третьих, очевидно, что скрипту не хватает «ситуативной функциональности». Скорее всего, кто-то захочет вывести инфу в других диапазонах, кому-то будет достаточно ежедневного отчета, а не ежечасного, а кому-то может банально хотеться «красоты». В общем, предложенное нами решение — это база. А уж «навесы» на все случаи жизни — сами :)
Немного полезной инфы
При работе со скриптом учитывайте следующие нюансы:
1 день — это ~30 сек. работы скрипта. Соответственно, стата за год будет собираться около трех часов (это излечимо).
Для удобства лимит обработки сервера был увеличен с 30 до 300 сек.
Скрипт не зависит от лимитов обработки сервера и/или браузера.
TGStat обязательно вас забанит — используйте VPN при работе.
В скрипте заложена возможность использования нового ip-адреса на каждый анализируемый день.
Используемая папка — tgstats. Если решите поместить скрипт в другую — замените ее в коде.
Используемый браузер — Google Chrome. Если решите поместить скрипт в другой — замените его в коде.
Используемые кодировки для вывода данных — "utf-8", "windows-1251". Если видите «кракозябры», — измените кодировки.
Даты в истории сканирования привязаны к первому использованию креатива. Однако если он использовался до указанного вами диапазона времени, — скрипт этого не узнает.
В скрипте не используются функции, т. к. он создавался с расчетом на «ковыряние» в нем далеких от программирования пользователей. Но никто не запрещает вам «загнать быдлокод» в функции для удобства.
Редактировать исходный код удобнее в notepad++ либо соответствующей среде разработки на php.
Ссылка на исходный код
Подводя итоги
Надеемся, наш скрипт поможет вам автоматизировать монотонное «тыканье» мышкой и вы сможете анализировать креативы конкурентов без пустой траты времени. Будем рады фидбэку по реализации от тех, кто «в теме», и пожеланиям по функциональности от тех, кто «не в теме». Тратьте свое время с умом, друзья!