📬 Автоматическая отправка отчётов в Telegram с помощью R

На этой странице вы найдете пример готового решения для автоматической отправки отчётов в Telegram — с использованием языка R и библиотеки telegram.bot. Такой подход особенно полезен для маркетологов, аналитиков и директологов, которые хотят оперативно отслеживать важные изменения в рекламных кампаниях.

🔍 Что делает этот скрипт?

Скрипт:

  • подключается к Telegram-боту;
  • формирует краткий и наглядный отчет в Markdown-формате;
  • автоматически отправляет его в личные сообщения или рабочий чат;
  • выделяет проблемные аккаунты с критичными или предупреждающими метриками.

🧠 Зачем это нужно?

Этот инструмент избавляет от ручного копирования таблиц и переписки в мессенджерах. Вы можете:

  • получать ежедневные или еженедельные отчеты без вашего участия;
  • видеть только ключевые метрики и тревожные сигналы;
  • мгновенно реагировать на ухудшения в кампаниях, не дожидаясь конца месяца или отчёта от подрядчика.
# Загружаем необходимые библиотеки
library(RMariaDB) # Подключение к базе данных MariaDB (MySQL)
library(dplyr) # Для удобной работы с таблицами
library(timeperiodsR) # Для работы с временными периодами (не используется явно, но может пригодиться)
library(lubridate) # Для удобной работы с датами
library(stringr) # Для работы со строками
library(tidyr) # Для заполнения пропущенных значений

# Устанавливаем рабочую директорию
TokenPath <- "C:/Scripts_serv/R/script/bijobs/"
setwd(TokenPath)

# Загружаем переменные окружения из .env файла
readRenviron("C:/Scripts_serv/.env")
bd_login <- Sys.getenv("CONN_BJ")
bd_pass <- Sys.getenv("CONN_BJ_PASS")
bd_ip <- Sys.getenv("CONN_HOST")

# Функция для подключения к базе данных
connection_fn <- function(usr = NULL, pas = NULL){
dbConnect(drv = MariaDB(),
user = usr,
password = pas,
host = bd_ip,
dbname = usr) # Используем логин как имя базы
}

# Подключаемся к базе и загружаем данные
con <- connection_fn(usr = bd_login, pas = bd_pass)

# Загружаем все данные начиная с 2025 года (можно поменять)
database <- dbGetQuery(con, "
SELECT * FROM vf_direct
WHERE Date >= '2025-01-01'
")
dbDisconnect(con)

# Приводим колонку с датами к формату Date
database <- database %>% mutate(Date = as.Date(Date))

# Определяем с какого месяца начинаем анализ (последние 4 месяца)
date_cutoff <- floor_date(Sys.Date() %m-% months(4), "month")

# Агрегируем данные по IdYandex, Директологу и месяцу
monthly_data <- database %>%
filter(Date >= date_cutoff) %>%
mutate(
year = year(Date),
month = month(Date)
) %>%
group_by(IdYandex, Директолог, year, month) %>%
summarise(
total_cost = sum(Cost, na.rm = TRUE),
total_conversions = sum(Konversii, na.rm = TRUE),
.groups = "drop"
)

# Определяем последний доступный месяц
latest_month <- monthly_data %>%
arrange(desc(year), desc(month)) %>%
slice(1) %>%
select(year, month)

# Текущий месяц — данные для прогноза
current_month <- monthly_data %>%
inner_join(latest_month, by = c("year", "month")) %>%
mutate(
total_cost = as.numeric(total_cost),
total_conversions = as.numeric(total_conversions),
cpa_current = ifelse(total_conversions > 0, total_cost / total_conversions, 0)
) %>%
select(IdYandex, Директолог,
budget_current = total_cost,
conversions_current = total_conversions,
cpa_current)

# Рассчитываем средние значения за предыдущие 3 месяца
last_3_months <- monthly_data %>%
anti_join(latest_month, by = c("year", "month")) %>%
group_by(IdYandex) %>%
summarise(
budget_avg_3m = mean(total_cost, na.rm = TRUE),
conversions_avg_3m = mean(total_conversions, na.rm = TRUE),
cpa_avg_3m = ifelse(sum(total_conversions) > 0, sum(total_cost) / sum(total_conversions), 0),
.groups = "drop"
)

# Объединяем фактические и средние данные
final_data <- current_month %>%
filter(!is.na(Директолог)) %>%
left_join(last_3_months, by = "IdYandex") %>%
mutate(across(everything(), ~replace_na(.x, 0))) # Заменяем NA на 0

# Рассчитываем прогнозы и отклонения

# Определяем текущую дату и сколько дней уже прошло в месяце
yesterday <- Sys.Date() - 1
days_passed <- day(yesterday)
total_days <- days_in_month(yesterday)

# Добавляем прогнозы и отклонения от среднего
final_data_t <- final_data %>%
mutate(
budget_forecast = (budget_current / days_passed) * total_days,
conversions_forecast = (conversions_current / days_passed) * total_days,

budget_deviation = ((budget_forecast / budget_avg_3m) - 1) * 100,
conversions_deviation = ((conversions_forecast / conversions_avg_3m) - 1) * 100,
cpa_deviation = (cpa_current / cpa_avg_3m - 1) * 100
) %>%
select(IdYandex, Директолог,
budget_current, budget_forecast, budget_deviation,
conversions_current, conversions_forecast, conversions_deviation,
cpa_current, cpa_deviation)

# Анализируем проблемные аккаунты
problematic_accounts <- final_data_t %>%
mutate(
alert_level = case_when(
budget_deviation < -40 | budget_deviation > 40 ~ "CRITICAL",
conversions_deviation < -50 ~ "CRITICAL",
cpa_deviation > 50 ~ "CRITICAL",
budget_deviation < -30 | budget_deviation > 30 ~ "WARNING",
conversions_deviation < -30 ~ "WARNING",
cpa_deviation > 30 ~ "WARNING",
TRUE ~ "NORMAL"
),
# Формируем описание проблемы на основе отклонений
reason = str_trim(str_c(
ifelse(budget_deviation < -40, "Резкое сокращение бюджета, ", ""),
ifelse(budget_deviation > 40, "Сильный рост бюджета, ", ""),
ifelse(conversions_deviation < -50, "Резкое падение конверсий, ", ""),
ifelse(cpa_deviation > 50, "Существенное увеличение CPA, ", ""),
ifelse(budget_deviation < -30 & budget_deviation >= -40, "Заметное сокращение бюджета, ", ""),
ifelse(budget_deviation > 30 & budget_deviation <= 40, "Заметный рост бюджета, ", ""),
ifelse(conversions_deviation < -30 & conversions_deviation >= -50, "Падение конверсий, ", ""),
ifelse(cpa_deviation > 30 & cpa_deviation <= 50, "Рост CPA, ", "")
)) %>%
str_remove(", $") %>%
na_if("") %>%
replace_na("Нет проблем")
)

# Теперь у тебя есть:
# 1. `final_data_t` — таблица с метриками по всем аккаунтам
# 2. `problematic_accounts` — таблица с "вниманием" и уровнями отклонений

🛠 Что потребуется дальше?

Перед использованием убедитесь, что у вас:

  1. Есть Telegram-бот, созданный через @BotFather;
  2. Установлен пакет telegram.bot в R;
  3. Есть chat_id — ID пользователя или группы, куда бот будет отправлять сообщения;
  4. Подготовлена таблица с ключевыми метриками (например, problematic_accounts).

Код для отправки сообщений

# Убедитесь, что установлен пакет telegram.bot
library(telegram.bot)

# Инициализация Telegram-бота
bot <- Bot(token = "ВАШ_ТОКЕН_БОТА") # Замените на токен вашего бота

chat_id <- ВАШ_CHAT_ID
# Замените ВАШ_CHAT_ID на ID получателя (можно узнать через getUpdates() или через @getmyid_bot)

# Генерация markdown-сообщения на основе итоговой таблицы final_data_t
# Оставляем только проблемные аккаунты (CRITICAL и WARNING)
report_data <- problematic_accounts %>%
filter(alert_level %in% c("CRITICAL", "WARNING")) %>%
arrange(desc(alert_level)) # CRITICAL выше в списке

# Генерируем текст для Telegram
markdown_text <- if (nrow(report_data) == 0) {
"*📊 Отчет по кампаниям*\n\nПроблемных аккаунтов не обнаружено. Всё работает стабильно ✅"
} else {
paste0(
"*📊 Отчет по кампаниям*\n\n",
paste0(
apply(report_data, 1, function(row) {
sprintf(
"*🆔 Аккаунт:* `%s`\n*👨‍💼 Директолог:* _%s_\n*🚨 Уровень тревоги:* *%s*\n*📝 Причина:* _%s_\n",
row["IdYandex"],
row["Директолог"],
row["alert_level"],
row["reason"]
)
}),
collapse = "\n"
)
)
}

# Отправка сообщения в Telegram
bot$sendMessage(chat_id,
text = markdown_text,
parse_mode = "Markdown")

✍️ Как адаптировать под себя?

Можете дополнить форматирование, добавить эмодзи или ссылки — Telegram Markdown это позволяет.

Укажите свой токен Telegram-бота;

Подставьте нужный chat_id;

Настройте поля alert_level, reason, IdYandex, Директолог под свою структуру данных;


Если хотите получить больше знаний о том как работать с языком R, специально для вас мы подготовили пошаговую статью для изучения основ программирования на языке R >>. Удачи! 🚀


Ну и конечно, подписывайтесь на наш канал в телеграм >>