Русский
Русский
English
Статистика
Реклама

Телеграм

Вы часть руководства? Отключите прием вызовов в телеграм! Баг-хантер? Уважайте других людей

13.04.2021 22:15:19 | Автор: admin

Всем привет. Сегодня речь пойдет не совсем о разработке. Я даже не знаю с чего начать. Это просто крик души.

Вы когда-нибудь пользовались звонками в телеграм? Это в целом удобно, особенно если не знаешь номера телефона. Но три месяца назад началась очень неприятная история, которая в конечном счете вымотала всю нашу поддержку, да и меня тоже.

Хто я?

Я - технический директор зарубежной компании. Прошел весь путь с момента идеи продукта и до текущего момента. По сути, мы - стартап, но вышли на самоокупаемость. Я часто отвечаю в поддержке для ускорения процесса если, конечно же, у меня есть свободное время. Итак, история началась 3 месяца назад. Наша команда в основном работает удаленно, но желающие могут посещать офис в Москве. Так вот, в конце января наш офис (а за одно и столицу) решил посетить один из сотрудников. Было принято решение встретить его с аэропорта. Должен сказать, я не отвечаю на телефонные звонки когда за рулем. И вот я еду в аэропорт, как мне начинает звонить раннее неизвестный мне человек в телеге. Я конечно же сбрасываю, но так просто я не отделался. Звонки начали повторяться постоянно. Сбросил - через 5 секунд тебе уже снова звонят. Ну что-ж. Выход очевиден: беззвучный режим и глаза на дорогу.

Как только я доехал до аэропорта и открыл чат - увидел что этот человек, который так сильно названивал, нашел несколько багов в нашем приложении и просит вознаграждение. После чего я перенаправляю его на других сотрудников, забираю коллегу и еду обратно. Дальше пришло несколько сообщений которые я снова не прочитал потому что был за рулем и снова очередь звонков, которые были сброшены.

Вернувшись в офис, я решил уделить время охотнику за багами. После небольшой переписки, багхантер понимает что вознаграждение не я плачу и что все-таки я бесполезен для него. Ситуация стихает на некоторое время. Но неделю назад все началось с бОльшей силой. Я как обычно сижу на работе, провожу митап со своей командой, как мне начинают звонить. Естественно все по старой схеме: я занят > сброс > звонок. Цикл замкнулся.

while (true) {  const rand = randomFloat();  if (rand > 0.9) {    writeMessage("Hi");    continue;  }    callTelegramm();}

После митапа я пишу "What happened?" ииии... Дальше ничего. Сообщение не прочитано, человек так сильно пытался до меня дозвониться и пропал. Через 3 дня он объявляется и сообщает что нашел аж 10(!) багов. Я думаю "как же так, 10 багов, я о них ничего не знаю". Логично что я сразу же занялся его вопросом и решил лично проверить все.

-_- ([%$#%^&$#] заголовок украден хакерами анонимусами)

После проверки "багов" оказалось что часть из них - возможность вытащить "личные данные пользователей". Звучит страшно, но на деле там оказалось что можно получить nickname пользователя, чей ник ты и так должен знать и (внимание) ID пользователя. Wow. Чтобы было немного понятнее: вы можете найти в телеграм пользователя по его нику. Чтобы его найти - вы и так должны знать ник. Это точно личные данные пользователей уязвимые для атаки? Вот такой же "баг" у нас нашли.

Другой "баг" - возможность доступа к открытым разделам приложения без оплаты. Мы сняли требование оплаты для того чтобы пользователь мог зайти в настройки и изменить емаил или пароль. Или же сменить тарифный план на бесплатный. Так вот как оказалось - это критическая уязвимость.

Еще могу рассказать как взломать абсолютно любой сервис. Как же? Все просто: открываете дев-тулзы на сайте и меняете текст в хтмл на свой личный. Для удобства представим что вы в сообществе вк добавляете модератора. Так вот вы находите в девтулзах слово "модератор" и пишете "владелец". А потом нажимаете кнопку, которая и выдает права. Проверять не стоит, ведь вы и так уверены что сообщество теперь принадлежит другому пользователю. Правда если все же проверить права - он окажется модератором, но это не важно. Звучит как ерунда? Я с вами согласен.

В конечном счете оказалось из 10 багов, за которые, кстати, тот самый нереальный охотник просил $2000, действительно багами считать можно только 2. И то они заключались в том, что мы не ограничиваем максимальное количество вводимых символов в инпут пароля при логине и регистрации. Казалось бы: можно попробовать забить сервер. Но при превышении максимального веса запроса - сервер сам отбросит его, да и к тому же у нас передается очень много данных между клиентом и сервером. Бывает возвращается ответ с 10к+ строк текста.

Пора поговорить о bug bounty

Решение было принято. За это платить $2000 не будем, оно того не стоит. Было предложено $400 за эти 2 момента. Но эта сумма не устроила охотника за багами. Он снисходительно снизил цену до $1500. 1500? Что? За максимальное ограничение символов? Его аргументом стало то, что это можно использовать для DDOS-атаки. Но DDOS-атака не проводится на поля для ввода. Она не так подбирается. Ищется место, в котором сервер медленнее всего обрабатывает запрос - очевидно там тяжелая работа с базой или какая-то дополнительная обработка, а может и в оперативу выгружает большое количество данных. И именно в этом место начинается атака чтобы положить сервер. В результате я предложил решение: проведешь успешную атаку с этим "багом" и мы поговорим об оплате за него.

Тут баг-хантер решил что пора понижать планку еще: до $1000. На самом деле $400 за эти "баги" и так сильно завышенная цена. После моего отказа - начались звонки - я отписал что в данный момент работаю и не могу ответить, но звонки продолжились. На следующий день все повторилось - я перенаправил его на других сотрудников, но с ними сей человек разговаривать не стал и продолжил долбиться ко мне в личку. В конце рабочего дня он отписал, что согласен на $600, после чего мы с ним еще раз поговорили и сошлись на 500, но без дальнейшего продолжения сотрудничества. После чего я связался с CEO компании и оказалось, что за день до этого ему уже перевели $500 (в тот момент, когда его это не устраивало). Я снова списался с охотником на баги и оказалось что он хочет еще $500. То есть в общей сложности $1000. И снова начались звонки... Я запретил ему в настройках звонить мне - он зарегал второй аккаунт, затем третий. После - начал звонить и писать в чат поддержки с требованием перевести ему еще со словами "иначе с вами никто не будет работать". Дальше - больше. Дело пошло к угрозам, жалобным и злобным эмоджи.

Потом пошел флуд в личку. И в конечном счете я не выдержал и отправил его в бан.

Может быть у кого-то были подобные проблемы? Как вы их решаете? Формально у нас не было компании на hackerOne. Этот человек сам нашел нас и сам же скинул баги и запросил цену. Мы готовы платить, но всему есть предел. Буду рад обсудить это в комментариях.

Мораль сей басни такова

  1. Не названивайте в телеграм постоянно. Если человек сбросил - он занят и обязательно ответит позже

  2. Не ломите цену. Ну ей богу. Ограничение по количеству символов в инпуте не стоит 2000 у.е. Оно и 500 не стоит если честно. Такими темпами можно будет оценивать отсутствие валидации полей на клиенте в тысячу долларов. А главным аргументом станет "Ну и что, что запрос не выполняется. Он же на сервер улетает. Запрос лишний - можно дудосить"

  3. Проверяйте баги прежде чем отписывать о них. Изменить в девтулзах текст - это не баг если он ни к чему не привел

Всех же, кто является частью руководства компании, призываю ограничить прием вызовов в телеграм не только в личном, но и в аккаунте поддержки - нашу команду просто вымотали за 3 дня. 3 дня безостановочных звонков. А главное - поддержка не может себе позволить заблокировать пользователя или сама отключить прием вызовов. Я восхищаюсь их терпению. Я бы просто не выдержал.

Подробнее..

Botsman новая платформа для разработки Telegram-ботов

30.12.2020 12:20:04 | Автор: admin

Сегодня, в предпоследний день уходящего года, хочу рассказать о созданном мной сервисе, помогающем быстро проектировать, отлаживать и следить за работоспособностью ботов в мессенджере Телеграм. Надеюсь, он окажется удобным инструментом. Под катом довольно подробный рассказ о том, как этот сервис зародился, какие технологии я для него выбрал и обзор того, что он сейчас умеет.

Для тех же, кому уже захотелось ознакомиться с Botsman (но не очень хочется много читать) вот ссылка, милости прошу: https://bots.mn/. Главное, о чём стоит помнить платформа только-только запустилась, и (пока что) не стоит переносить на неё что-то серьёзное и масштабное.

Предыстория: путь к созданию Ботсмана

Пять лет назад в Telegram появилась возможность создавать ботов автоматизированные аккаунты, которыми можно управлять с помощью своих скриптов. Меня это сразу заинтересовало: я люблю делать маленькие, но полезные утилитки.

Правда, в отличие от десктопных приложений, браузерных расширений и простых веб-сервисов, с ботами есть некоторая сложность в их разработке: в отличие от традиционных веб-сервисов, их труднее отлаживать. Даже если настроить логирование, бывает трудно понять, что именно происходит с ботом и всё ли работает так, как нужно.

Поэтому почти сразу пришла в голову идея сделать такую платформу, которая возьмёт весь мониторинг на себя: будет логировать и входящие обновления, и то, как бот на них реагирует (и какие возникают при этом ошибки). Заодно можно и графики удобные строить.

Но, к сожалению, дальше придумывания красивого названия Botsman и покупки короткого домена bots.mn дело поначалу не зашло. Проект оказался непривычно большим для того, чтобы осилить его в одиночку, и за пять лет я то брался за него, то снова откладывал на потом.

И только к концу злополучного 2020-го я нашёл в себе силы довести его до рабочего состояния, которое можно показать широкой публике. Специально поставил цель зарелизиться до Нового года: чтобы добавить этому году плюс одно хорошее событие :)

Итак, что же сейчас предлагает данная платформа?

Проксирование запросов

Во-первых, мой сервис умеет работать как прокси: вы подключаете бота к Botsman, он ловит все приходящие от Telegram события, логирует, и передаёт вашему серверу. Это удобно, если у вас уже написан и где-то крутится бот: ваш код может даже не подозревать про эту прослойку.

Выбор способа обработки запросов ботомВыбор способа обработки запросов ботом

У этой фичи есть очевидный недостаток: небольшое увеличение времени отклика (поскольку в цепочке Telegram ваш сервер появляется дополнительное звено).

Но этой осенью Telegram сделал крутую вещь: они выложили в открытый доступ код сервера-посредника Bot API. По своей сути это такое приложение, которое внутри общается с Телеграмом как клиент по их протоколу MTProto, а снаружи у него торчит уже простое и понятное Bot API. И когда вы обращаетесь к публичному Bot API по HTTPS запрос на самом деле идёт к инстансу такого сервера, а теперь стало можно поднять его самому. И конечно же, внутри Ботсмана я так и сделал (и это новшество оказалось ещё одним мотиватором закончить проект).

Таким образом, вашего бота можно настроить так, что цепочка не станет длиннее: вместо
Telegram сервер Bot API ваш сервер будет
Telegram Botsman ваш сервер.

Правда, тут уже потребуются правки в коде вашего бота: исходящие запросы придётся делать не на api.telegram.org, а на api.bots.mn/telegram. Зато Botsman сможет логировать и их тоже!

Собственно, поговорим о логировании:

Живая лента обновлений

После настройки бота в Botsman, можно сразу открыть страницу Events, отправить что-то в Телеграме своему боту, и увидеть, как это сообщение появилось на экране в реальном времени. Если у вас настроен прокси вы увидите и результат перенаправления запроса вашему серверу. Если ваш сервер шлёт запросы через проксирующий эндпоинт api.bots.mn/telegram они тоже туда попадут.

Так в интерфейсе Botsman выглядит лог всех происходящих с ботом событийТак в интерфейсе Botsman выглядит лог всех происходящих с ботом событий

С технической стороны, конечно, тут всё просто: я использую веб-сокеты чтобы проталкивать все обновления на клиент, если у вас открыта соответствующая вкладка (если открытых страниц нет, лишней нагрузки это создавать не должно). Возможно, если бы я начинал этот проект сейчас, я бы попробовал использовать Server-sent events вместо веб-сокетов, но вряд ли есть какой-то повод переходить на них.

Кроме бесконечного лога, куда все события сыпятся вперемешку, Botsman ещё умеет показывать интерфейс, похожий на обычный список диалогов в самом мессенджере то, как их видит ваш бот. При желании можно даже никак не обрабатывать запросы, а просто вручную открывать диалоги и отвечать от имени бота (этакий режим техподдержки возможно, впоследствии я добавлю поддержку управления ботами с нескольких аккаунтов с разными ролями, если это действительно будет актуально).

Слежение за показателями бота

Ну и конечно же, статистика и графики, куда без них. Честно говоря, аналитик из меня так себе, поэтому сейчас Botsman показывает только довольно базовые метрики общее число апдейтов, число чатов, число пользователей, дневную и месячную аудиторию (DAU и MAU). Графики по числу апдейтов на каждый день/час, и по среднему времени обработки запросов. Было бы, конечно, интересно смотреть на всякую демографию, но в Telegram в этом плане мало информации о пользователях.

Графики в разделе Stats. Как видно, через одного из моих ботов уже прошло почти 20 млн апдейтов.Графики в разделе Stats. Как видно, через одного из моих ботов уже прошло почти 20 млн апдейтов.

Для подсчёта статистики я с самого начала выбрал старый добрый Redis, а вот на клиентской стороне решил рисовать графики с помощью библиотеки, которую до этого сам же написал на конкурс того же Телеграма. Не пропадать же добру :)

Скриптинг

Но вернёмся к тому, как вообще оживить вашего бота. Просто проксировать запросы к другому серверу скучно (да и от дополнительного звена всё-таки лучше избавиться). Мне хотелось дать возможность прямо внутри сервиса описать логику работы бота. Знаю, что существует множество конструкторов ботов для этого (хотя я и старался всё делать без оглядки на них), но мне хотелось возможности писать полноценный код прямо в браузере.

При этом мне не очень хотелось прибегать к компилируемым в нативный код языкам: это производительно, но тогда пришлось бы строить сложную систему, оборачивая код каждого бота в контейнер и держать их все непрерывно запущенными.

Поэтому я выбрал JavaScript: моя изначальная идея была взять встроенную в Node песочницу, немного доработать (как это сделано в библиотеках Sandcastle или vm2), чтобы сделать её безопаснее, и выполнять код ботов в ней.

Но в процессе очередного подхода к допиливанию проекта пришло осознание, что даже с доработками такой подход неидеален: код в таком случае выполнялся бы все равно в одном общем потоке и при росте нагрузке неизбежно привёл бы к тормозам. Да и риск проблем с изолированностью исполняемого кода всё-таки сохраняется.

В итоге я обратил внимание на библиотеку isolated-vm: она тоже реализует песочницу в JS, но делает это другим, более безопасным (и, что важно, многопоточным) образом. По сути это обёртка над присутствующим в V8 механизмом изолятов независимых контекстов, которые ничего не знают друг про друга. Эта же библиотека, кстати, используется в игре Screeps, где игрокам тоже нужно писать своих ботов.

Что особенно хорошо для ботов: состояние одного такого изолята можно держать в памяти как кусок данных (не расходуя процессорное время), и только когда боту понадобится обработать прилетевший апдейт от Телеграма оживлять это состояние, вызывая в нём функцию-обработчик. И конечно можно ограничить как потребляемую память, так и процессорное время (с этим, помнится, в нодовской песочнице были некоторые сложности).

Скриптинг: внутреннее API, обработчики событий

Дальше одним из камней преткновения было дать удобное внутреннее API для написания ботов. Конечно, можно было сказать вашему коду будет доступна переменная update и метод callMethod, а дальше делайте, что хотите. Но раз уж я проектирую всю песочницу, нужно идти до конца.

В частности, мне хотелось реализовать механизм состояний: часто боты рассчитаны на пошаговый диалог, и это надо учесть, как-то запоминать контекст, даже если пользователь бросил диалог и вернулся к нему на следующий день. В итоге я решил, что для каждого чата, пользователя или сообщения я позволю хранить объект с произвольными полями. А у чатов (как личных, так и групповых) в придачу есть понятие пути, route оно позволяет раскидать обработчики событий по тому, на каком шаге находится пользователь.

Само добавление обработчиков делается довольно просто:

on(ctx => {  ctx.log('Some update received: ', update);});

Это самый универсальный обработчик: он вызывается при любом событии (напомню, кроме события пришло сообщение Telegram присылает и ряд других оповещений).

Перед функцией-коллбэком можно указать один конкретный тип события: тогда обработчик будет вызываться исключительно для него.

on('message', ctx => {  ctx.message.reply('Hi!');});

А что будет, если объявить два обработчика и они оба подходят для текущего апдейта? Botsman вызовет только первый из них но можно передать управление следующему, если вернуть false (ну или промис, резолвящийся в false разумеется, всё делалось с расчётом на асинхронный код).

Ещё есть удобные способы обработывать только текстовые сообщения с помощью on.text (их можно заодно ещё и фильтровать по регэкспу), только команды с помощью on.command, инлайн-запросы on.inline, и коллбэк-запросы (нажатия на кнопки под отправленными сообщениями) on.callback. О них можно почитать в документации.

В примерах выше видно, что обработчику передаётся единственный параметр экземпляр класса EventContext, и через него делаются все вызовы. Это позволяет Ботсману связывать, например, вызовы API или возникающие ошибки с конкретным апдейтом, который к ним привёл.

Ну а как разграничить обработчики для разных состояний (путей) чата? Для этого предназначена глобальная функция state:

state('step1', (on, state) => {  // Этот обработчик вызовется для любого сообщения,  // если наш чат в состоянии 'step1' - и переведёт его  // в состояние 'step2'  on.text(ctx => {    ctx.route.to('step2');   });});state('step2', (on, state) => {  // А этот обработчик вызывается, если наш чат в  // состоянии 'step2' и возвращает его в 'step1'  on.text(ctx => {    ctx.route.to('step1');   });});

Обратите внимание: функция state немедленно вызывает переданный ей коллбэк с двумя аргументами, которые заменяют собой глобальные функции on и state. Добавленный с помощью локальной функции on обработчик будет вызываться только в указанном состоянии, а с помощью локальной функции state можно создавать вложенные состояния (хотя их можно создать и вручную, просто записывая путь, разделённый слэшами: 'step1/substep1/branchA'). Пока что, впрочем, иерархическая структура состояний особых преимуществ по сравнению с линейной не имеет (но может помочь их логически упорядочить).

Скриптинг: форматируем сообщения с помощью tagged template literals

Отдельно поделюсь одной, казалось бы, незначительной, но весьма радующей лично меня деталью. Если вы уже пробовали использовать Telegram API, то возможно сталкивались со сложностями при отправке текста с форматированием особенно когда в него нужно подставить пользовательские данные. Telegram умеет принимать и HTML, и Markdown, но и в том, и в другом случае подставляемые данные нужно обрабатывать, эскейпить управляющие символы, что не очень удобно.

К счастью, не так давно при отправке сообщения (и в других методах, где можно отправлять форматированный текст) появилась возможность просто указать отдельно, какие участки в нём нужно отформатировать. Добавляем к этому tagged templates из ES6 и получаем вот что:

await ctx.call('sendMessage', {  chat_id: 12345,  ...fmt`Hello ${fmt.bold(foo)}! You can combine ${fmt.italic(bar).bold()} styles together.Links are supported ${fmt.text_link(linkLabel, linkUrl)}.`,});

Выглядит немного непривычно, зато а) не нужно ничего эскейпить, б) невозможно сломать вёрстку, потеряв какой-нибудь HTML-тэг или символ разметки Markdown. Если у вас валидный JS будет и валидная вёрстка. Под капотом запись fmt`something` возвращает объект с двумя полями text и entities поэтому его нужно распаковывать с помощью ... (spread syntax). Ну или его можно передать напрямую в короткие методы типа ctx.message.reply(fmt`something`) или ctx.chat.say(fmt`something`).

Мне кажется, что у tagged template literals вообще не очень много уместных применений в реальном мире, но тут у меня получилось найти одно из них :)

Скриптинг: код по расписанию и запросы к внешним API

Должен сделать важную оговорку: так как код выполняется в изолированных контекстах, у скриптов нет ни доступа к API самой Node, ни возможности импортировать внешние модули. Однако я реализовал метод fetch (по аналогии с одноимённым браузерным API) он позволяет делать не слишком тяжёлые запросы к внешним серверам. Кроме того, доступна глобальная функция cron с помощью неё можно запланировать регулярное выполнение повторяющихся действий:

cron('0 0 * * FRI', ctx => {  ctx.log('This function should execute each Friday at midnight');});

Первый параметр тут либо привычный формат crontab, либо интервал в секундах (правда, и то, и другое с разрешением не чаще раза в пять минут). Я думаю, что возможности выполнять код по расписанию и делать запросы к внешним API позволят реализовать множество практических задач. И не исключено, что в будущем список возможностей (например, импорт каких-то проверенных модулей) будет расширяться.

Скриптинг: веб-интерфейс

Писать код прямо в браузере не самое комфортное занятие, но я стремлюсь сделать его хотя бы сравнимым с разработкой в IDE. Сейчас в качестве редактора я использую CodeMirror (в первую очередь из-за его относительно небольшого веса), в дальнейшем, вероятно, добавлю возможность переключиться на Monaco он ощутимо тяжелее, зато должен быть шустрее и функциональнее (именно он используется внутри VS Code).

Так сейчас выглядит редактор кода в BotsmanТак сейчас выглядит редактор кода в Botsman

Пока что в Botsman нет разбивки кода на отдельные файлы в этом тоже может быть неудобство, если вы собираетесь писать сложного бота. Зато код сохраняется автоматически, и есть возможность хранить все его предыдущие версии это ещё не Git, но всё же.

И ещё одна небольшая, но довольно ценная возможность: проверка кода перед деплоем с помощью тестов. При этом Botsman по нажатию одной кнопки сразу покажет подробный лог выполнения (см. скриншот выше): время инициализации, обработки запроса, отладочный вывод и возникшие ошибки (код с синтаксическими ошибками задеплоить не выйдет в принципе).

Песочница для запросов к Telegram

Ну и последняя небольшая, но довольно полезная фича Botsman, о которой хотелось бы рассказать панель для формирования запросов к Telegram. Нередко социальные сети предоставляют собственный инструмент для этого, но у Телеграма его, к сожалению, нет. Поэтому я сделал страницу, где можно выбрать нужный метод API, заполнить его параметры и наглядно увидеть результат вызова. Заодно можно сразу скопировать эквивалентный код, делающий этот запрос.

Панель вызова методов Telegram APIПанель вызова методов Telegram API

Будущие планы

Как было сказано ранее, Botsman находится в самом начале своего пути. Возможно, его даже настигнет Хабраэффект (надеюсь, что нет!). Возможно, ему станет тяжко, если созданные на нём боты наберут популярность не исключено, что тогда придётся вводить платные возможности. Поскольку занимаюсь им я сейчас в одиночку, сложно сказать, что с ним будет.

В очень примерных планах сейчас такие фичи:

  • Визуальный конструктор в дополнение к скриптингу

  • Глобальное key-value хранилище + создание собственных хранилищ

  • Поддержка других платформ, кроме Telegram

  • Доступный снаружи эндпоинт для вызова кода бота

  • Управление ботом с нескольких аккаунтов

  • Навигация по коду, разбивка на модули, поддержка сторонних модулей

  • Более гибкое тестирование кода, автоматические тесты

  • Больше статистики и графиков

  • Оповещения (если с ботом что-то не так)

  • Улучшение вида чатов

  • Улучшение работы с файлами (скачивание, загрузка), в том числе в песочнице

В любом случае, надеюсь, что из этого сервиса выйдет что-то хорошее! Буду рад услышать ваши мысли, пожелания и соображения в комментариях.

Подробнее..

Оплата в телеграм боте Платежи 2.0 Сбербанк Telegraf Node.js

02.05.2021 10:10:12 | Автор: admin

Платежи 2.0 В мессенджере Telegram появилась возможность принимать платежи в любом чате, включая группы и каналы. Подключить свой магазин к платформе можно самостоятельно, без согласования с Telegram.



И в этом туториале мы создадим простого бота с Node.js на фреймворке Telegraf.js, который сможет принимать деньги с клиента и отправлять их на ваш счет через Сбербанк.


Платежи 2.0


Платежи 2.0


Платёжные боты существуют в Telegram с 2017 года. С их помощью можно безопасно оплачивать товары и услуги вроде доставки пиццы, не покидая приложения.


С сегодняшнего дня продавцы могут принимать платежи кредитными картами с помощью 8-ми встроенных платёжных систем в любом чате, включая группы и каналы.


На данный момент поддерживаются платежи из более чем 200 стран через следующие платежные системы:


Платежи 2.0


Telegram не обрабатывает платежи от пользователей и вместо этого полагается на разных поставщиков платежей по всему миру. Именно провайдеры платежей обрабатывают и хранят всю конфиденциальную информацию, например данные кредитной карты. Ни Telegram, ни разработчики ботов не имеют к нему доступа.


Для оплаты можно использовать любое приложение в том числе Telegram для компьютеров. Покупатель также может оставить чаевые, чтобы поддержать любимого автора, кафе или магазин.


Создаём бота в Telegram


Бот в Telegram создается при помощи другого бота под названием @BotFather. Отправляем ему команду /newbot, выбираем имя, которое будет отображаться в списке контактов, и адрес. Например, Оплата в Telegram боте с адресом sber_pay_test_bot.


newbot


Если адрес не занят, а имя введено правильно, BotFather пришлет в ответ сообщение с токеном ключом для доступа к созданному боту.


ВНИМАНИЕ! Его нужно сохранить и никому не показывать.


Создаем проект Node.js


Далее создадим новый проект. Создаем папку.


Вводим в консоле:


mkdir sber_pay_test_bot && cd sber_pay_test_bot

Затем:


npm init 

Программа задаёт вам разные вопросы и создает package.json, который определяет настройки проекта, зависимости, скрипты, название и прочее. Для примера можно везде нажать enter


и добавим файл index.js в котором будет разрабатываться наш бот.


touch index.js    

Telegraf.js


Cтавим telegraf.js это один из популярных фреймворков для создания телеграм бота.


npm install telegraf@3.38 

Ставим библиотеку dotenv это модуль, который загружает переменные среды из файла .env в process.env., а также заодно поставим nodemon инструмент, который помогает разрабатывать приложения на основе node.js путем автоматического перезапуска приложения node при обнаружении изменений файлов в каталоге.


npm install dotenv nodemon

Добавляем скрипт запуска в package.json


"scripts": {    "start": "nodemon index"}

Из документации telegraf.js, копируем в наш проект первоначальную настройку бота.


const { Telegraf } = require('telegraf')require('dotenv').config()const bot = new Telegraf(process.env.BOT_TOKEN) //сюда помещается токен, который дал botFatherbot.start((ctx) => ctx.reply('Welcome')) //ответ бота на команду /startbot.help((ctx) => ctx.reply('Send me a sticker')) //ответ бота на команду /helpbot.on('sticker', (ctx) => ctx.reply('')) //bot.on это обработчик введенного юзером сообщения, в данном случае он отслеживает стикер, можно использовать обработчик текста или голосового сообщенияbot.hears('hi', (ctx) => ctx.reply('Hey there')) // bot.hears это обработчик конкретного текста, данном случае это - "hi"bot.launch() // запуск бота

Создаем файл .env куда в переменную BOT_TOKEN кладем токен, который ранее нам выдал @BotFather


BOT_TOKEN='сюда'

Запускаем бот командой


npm run start

Проверяем работу бота


check bot


Получаем PROVIDER_TOKEN от @SberbankPaymentBot


Для получения PROVIDER_TOKEN вам необходимо получить merchantLogin в Сбербанке. Для этого необходимо подключить услугу интерент-эквайринг в Сбербанке.


После того как вы его получили переходим в @BotFather и вызываем команду /mybots, где выбираем вашего бота.


Далее Payments


Payments


Где выбираем Сбербанк


Payments


Выбираем Connect Сбербанк Live


Payments


После этого вас перекинет на @SberbankPaymentBot, где нужно ввести ваш merchantLogin, который необходимо вводить без всяких префиксов -api или -operator. Например так: P71XXXXXXX21. Из-за того что я этого не знал, у меня ушло на переписку с техподдержкой Сбербанка неделя времени.


SberbankPaymentBot


После @BotFather выдаст вам токен, который нужно вставить в переменную PROVIDER_TOKEN файла .env


PROVIDER_TOKEN='41018XXXX:LIVE:XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

SberbankPaymentBot


Подключаем оплату в приложении


Пишем в index.js следующий код:


const { Telegraf } = require('telegraf')require('dotenv').config()const bot = new Telegraf(process.env.BOT_TOKEN) //сюда помещается токен, который дал botFatherconst getInvoice = (id) => {  const invoice = {    chat_id: id, // Уникальный идентификатор целевого чата или имя пользователя целевого канала    provider_token: process.env.PROVIDER_TOKEN, // токен выданный через бот @SberbankPaymentBot     start_parameter: 'get_access', //Уникальный параметр глубинных ссылок. Если оставить поле пустым, переадресованные копии отправленного сообщения будут иметь кнопку Оплатить, позволяющую нескольким пользователям производить оплату непосредственно из пересылаемого сообщения, используя один и тот же счет. Если не пусто, перенаправленные копии отправленного сообщения будут иметь кнопку URL с глубокой ссылкой на бота (вместо кнопки оплаты) со значением, используемым в качестве начального параметра.    title: 'InvoiceTitle', // Название продукта, 1-32 символа    description: 'InvoiceDescription', // Описание продукта, 1-255 знаков    currency: 'RUB', // Трехбуквенный код валюты ISO 4217    prices: [{ label: 'Invoice Title', amount: 100 * 100 }], // Разбивка цен, сериализованный список компонентов в формате JSON 100 копеек * 100 = 100 рублей    payload: { // Полезные данные счета-фактуры, определенные ботом, 1128 байт. Это не будет отображаться пользователю, используйте его для своих внутренних процессов.      unique_id: `${id}_${Number(new Date())}`,      provider_token: process.env.PROVIDER_TOKEN     }  }  return invoice}bot.use(Telegraf.log())bot.hears('pay', (ctx) => { . // это обработчик конкретного текста, данном случае это - "pay"  return ctx.replyWithInvoice(getInvoice(ctx.from.id)) //  метод replyWithInvoice для выставления счета  })bot.on('pre_checkout_query', (ctx) => ctx.answerPreCheckoutQuery(true)) // ответ на предварительный запрос по оплатеbot.on('successful_payment', async (ctx, next) => { // ответ в случае положительной оплаты  await ctx.reply('SuccessfulPayment')})bot.launch()

Метод Telegraf replyWithInvoice это метод telegram.sendInvoice.


Используйте этот метод для отправки счетов. В случае успеха отправленное сообщение возвращается.


Запускаем бот командой yarn start и проверяем проходит ли оплата.


Проверить как работает оплата можно в наших телеграм ботах JavaScript Bot это бот с тестовыми вопросами по нашим курсам JavaScript, React Native, TypeScript, а также проверить платежи можно боте по изучению английских слов по эмодзи Englishmoji


Проблемы или вопросы?


Задавайте их в телеграм сообществе Боты на Telegraf


Подписывайтесь на наши новости и социальные сети.


JavaScript Camp

Подробнее..

Продвижение бота на 214 тысяч процентов

26.12.2020 16:10:02 | Автор: admin

Примерно с начала декабря провожу эксперимент по продвижению (если угодно - хайпу) в Твиттере своего бота. Результаты мне нравятся. Возможно кому будет интересно как почти при нулевом бюджете сделать эффективную рекламную кампанию в сети. Скриншоты, статистика, части кода и рассказы ниже.

Теория

По моему мнению реклама в сети скоро будет активно осваивать короткие звуковые споты. Всё чаще люди начинают слушать интернет, а не только его смотреть. Интернет-радио,Spotify,iTunesи множество других служб для "прослушки" сети очень быстро внедряются в массовое употреблением. Даже Твиттер вывел на рынок звуковые твитты.Росту значения звука способствует и рост числа индивидуальных устройств для прослушивания - наушники стали обыденным явлением и значит звуковая реклама можетбыть индивидуализированна и подана отдельному человеку в зависимости от его предпочтений как и традиционная контекстная реклама.

Практика

О своём боте для звукодзи я уже писал в статье на Хабр

В начале декабря я добавил к нему функцию озвучки гифок и картинок. То есть нужно послать боту изображение в виде файла, а потом голосовое сообщение. Бот вернёт короткий спот видео, который можно уже вставить куда угодно. Мы проводили эксперименты с размещением готовых видео роликов в Твиттере чтобы оценить реакцию пользователей и их "вовлечённость".

Чтобы бот работал корректно в социальной сети во время тестирования были обнаружены и устранены некоторые проблемы. В частности:

  • Обрезка по времени.

Пользователи чаще всего не попадают точно в начало гифок. Тем более, что и при отсылке голосовых сообщений запись начинается не сразу - есть задержка физическая, то есть буквально зависание пальца на кнопке, и есть задержка логическая, то есть мессенджер вставляет небольшую паузу от начала записи. Для устранения задержек я "сдвинул" начало записи к началу видео. Вот таким образом:

Объяснение кода

Функция вырезана из класса.

Для обработки звуков/видео используется ffmpeg

PWF --> место хранение файлов для последующий обработки

cmd --> это переименованная функция system встроенной в python библиотеки os

В функции connect_video_voice соединяется звук, и видео.

Также есть функция по соединению звука и картинки.

def connect_photo_audio(self,imagepath, audiopath, name=urandom(30).hex()):      targetvideotype = "mp4"      cmd(f'ffmpeg -y -loop 1 -i "{imagepath}" -i "{audiopath}" -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pixfmt yuv420p -shortest -vf "scale=trunc(iw/2)2:trunc(ih/2)2" "{self.PWF}/{targetvideotype}/{name}.{targetvideotype}"')      return f'{self.PWF}{targetvideotype}/{name}.{targetvideo_type}'
def connect_video_voice(self,videopath, audiopath, name=urandom(30).hex(),):  sourcevideotype = "mp4"  cmd(f'ffmpeg -streamloop -1 -i "{videopath}" -i "{audiopath}" -shortest -c:v copy -c:a aac -strict experimental -map 0:v:0 -map 1:a:0 -y "{self.PWF}/{sourcevideotype}/{name}.{sourcevideotype}"')      return f'{self.PWF}/{sourcevideotype}/{name}.{sourcevideo_type}'
Логика обрезания

Если звук длинее видео, то видео повторяется по кругу, если же звук меньше чем видео, то видео обрезается до размера звука.

f"ffmpeg -stream_loop -1 -i "{video_path}" -i "{audio_path}" -shortest -c:v copy -c:a aac -strict experimental -map 0:v:0 -map 1:a:0 -y "{self.PWF}/{source_video_type}/{name}.{source_video_type}"
  • Ограничение по времени

Чтобы пользователь не записывал слишком длинные видео, не перегружал систему ради своих приколов да и для того чтобы избежать случайных нажатий я предусмотрел ограничение по времени в одну минуту кодом:

Пояснение о коде

Для работы с телеграммом используется PyTelegramBotAPI

После получения голосового сообщения, в message.voice хранится информация о нем. В том числе хранится и duration, в ней хранится длительность голосового сообщения.

if message.voice.duration > 60:  self.BOT.send_message(message.fromuser.id, "Your message too long. Max size of message: 1 minute")      return

Внедрение

Бот был активно использован для одного свежего "чистого" аккаунта в сети Твиттер без фоловеров. На скриншотах видны два читателя - это те, которые сами присоединились по своей инициативе. Никаких "раскруток" или подобных действий для статистики не предпринималось. Мне было самому интересно сможет ли такая своеобразная реклама без бюджета бота в сети обеспечить рост его известности.

Ежедневно мы публиковали несколько твиттов с внедрённым видео. Вот статистика просмотров

Статистика в Твиттер

Для измерения переходов к самому боту я написал дополнительный код, собирающий статистику обращений к боту и манипуляций с ним.

Объяснение кода

get_users_graphic__activity__ функция, которая вызывается при команде /activity к боту.

Здесь идет проверка на доступы, если пользователь написавший боту /activity не занесен в базу данных как админ, или же как helper, то в графике ему будет отказано.

create_graphic_activity --> функция, которая строит графики на основе функции которая получает данные о пользовательской активности в боте.

limit--> переменная, используемая для указания лимита возвращаемой активности в дня. По умолчанию limit имеет значение Продвижение бота с услугами через твиттер

/activity 3 вернет график активности за последние 3 дня.

def get_users_graphic__activity__(self):    if self.MESSAGE.chat.id in HELPERS or self.MESSAGE.chat.id == ADMIN_USER_ID:        graphic = create_graphic_activity()        if graphic:            try:                limit = int(re.sub('\D', '', self.MESSAGE.text))            except Exception:                limit = 7            self.BOT.send_photo(self.MESSAGE.chat.id, photo=create_graphic_activity(limit=limit))        else:            self.BOT.send_message(self.MESSAGE.chat.id, LANGUAGES["commands"]["server_crashed"])    else:        self.BOT.send_message(self.MESSAGE.chat.id,LANGUAGES["commands"]["you_not_have_permissions"])

При использовании бота я заметил рост обращений к нему. При том что в самих Твиттах ссылка на бот не содержится - она есть только в профиле пользователя. Это значит что в бот перешли самые активные участники, не ограничивающие себя просмотром.

В планах

Возможно некоторым рекламодателям уже можно использовать моего бота для продвижения своих товаров и услуг. Можно включать свой логотип или изображение товара в картинку или дополнять слоганом звуковое сообщение. Я пока продолжу совершенствовать функционал программы. В ближайшее время я планирую дополнить бота функциями выравнивания по силе звука и перезаписью дублей. Если для перезаписей дублей код не трудно дописать, то выравнивание силы звука - нетривиальная задача, поскольку для рекламных целей как раз изменение силы звука может быть "цепляющим" внимание фактором.

Подробнее..

Группа смерти изнутри люди, которые играют в опасные игры

11.03.2021 10:22:28 | Автор: admin


Помните, сколько было разговоров о подростковых суицидальных группах типа синий кит? Широкая огласка и моральная паника способствовали тому, что на ВКонтакте и ряде других площадок такие группы научились оперативно находить и блокировать. Но чем активнее родители и педагоги вели профилактическую работу, предупреждая об игре и выясняя, не участвуют ли в ней дети, тем больше детей узнавало, что есть такая запретная, таинственная, опасная игра. Последствия этого были вполне естественны дальнейшее распространение игры уже не требовало участия взрослых. Синий кит занял особое место в подростковой культуре, где-то рядом с зацепингом и играми с перебеганием перед движущимся транспортом. Как в Мафии, здесь есть разные роли. Кто-то выбирает для себя роль игрока, кто-то куратора, кто-то спасателя, волонтера.

Сегодня мы попробуем увидеть происходящее глазами рядовых участников не тех, для кого в конечном итоге все кончилось плохо, а того подавляющего большинства, которое играло, а потом продолжило жить.

1. Как вступить в тайное общество

Предположим на минуту, что нам нужно организовать групповой чат не вполне легальной тематики. ВКонтакте не подходит у него отличный фильтр по ключевым словам. А еще есть риск, что если в группу вступит подросток, то рано или поздно его родители захотят проверить, на что это там чадо подписано. Что мы делаем, чтобы уменьшить этот риск? Правильно, мы открываем группу в телеграме.

Ну, поехали. Я печальный подросток и хочу найти в телеграме группу синий кит. Спасибо средствам массовой информации, я знаю все секретные кодовые слова (их только ленивый не знает). Я забиваю в поиск все по очереди теги и получаю следующие результаты:

1. Канал с картинками депрессивного содержания. Летающие киты, надписи типа все тлен. Обновляется редко, подписчиков мало.
2. Группа для тех, кто интересуется вопросом. Кто-то пишет, что не верит вообще в реальность игры. Один бывалый парень разъясняет собравшимся, что они дураки, малолетки и ничего не понимают. Девочка Маша двенадцати лет от роду (к которой мы еще вернемся) романтически взывает к таинственному куратору. Приди, куратор, пишет она, я хочу увидеть кита!
3. Канал с анкетами принятых в игру подростков. А вот это уже интересно! В каждой анкете имя (не ник, не логин, а именно человеческое имя, типа Петя или Настя), фотография порезов на запястье и краткое объяснение того, почему Петя или Настя в игре. Где-то это лаконическое хочу узнать, на что способен, а где-то душераздирающие истории с семейным насилием и наркотиками. В информации о канале ссылка на бота, через которого можно вступить в закрытую группу.

Я, гипотетическая девочка условных лет пятнадцати, на этом месте, естественно, воодушевляюсь и иду общаться с ботом.

Бот хочет узнать мое имя (я ограничиваюсь инициалом) и причину вступления в игру. Не будучи оригинальной, я сообщаю, что хочу узнать, на что способна. После этого бот просит загрузить фотографию моих порезов. Я делаю то, что делают многие любопытные подростки на моем месте: скачиваю картинку с интернета, немного обрезаю и выдаю за свою.

Этого оказывается достаточно. На следующий день я получаю ссылку на вступление в закрытую группу.

2. А был ли мальчик

Первое, что я обнаруживаю, зайдя в группу: живых людей там примерно вдвое меньше, чем анкет на канале, и имена не совпадают. К слову, от моей анкеты в конечном итоге остается только фраза хочу узнать, на что способна. Имя там уже другое. Картинка тоже. Я начинаю подозревать, что у админа группы есть заветная папочка с кровавыми фотографиями, откуда он периодически что-то достает и выкладывает для воодушевления. Может быть, в порядке исключения реальное запястье кого-то из реальных пользователей и оказалось на канале, но остальное это, похоже, великая сила гугла.

Я спрашиваю насчет игры. Сидящие в группе девочки объясняют мне, что игра начнется, когда наберется пятьдесят человек в группе, так админ решил. А пока не набралось пятьдесят человек, группа, в общем, предоставлена самой себе.

Со мной знакомятся, пытаются выяснить, сколько мне лет. Для школьников это важно, чтобы понимать, кто из собеседников ребенок несознательный, а кто взрослый разумный шестнадцатилетний человек. Я использую классический прием спрятаться на виду:

Вера: А лет сколько
Е.К.: нискажу, смеяться будете
Вера: Говори
Оля: Не будем
Вера: Мы ждём
Оля: Угу
E.К.: /страшным шепотом/ тридцать! лол. поверили?
Вера: Нет
Оля: Нет. В 30 врятли таким будут заниматься, в 30 если хочешь то идешь без проблем. Я думаю ей лет 12-13
Вера: В 30 максимум сюда могут попасть чтоб контору палить
Оля: Ну или так
E.К.: а я думала только в вк палевно
Вера: Хдд
Оля: Нуу незнаю, незнаю, тут тоже не сложно спалиться
Вера: За то тут канал забанить сложно. Не то что в вк
Оля: Угу
E.К.: а чо будет если спалят?
Вера: Группы начнут банить
Оля: В психушку пойдешь, в лучшем случаи, а так многоо много бесед с психологами...


На этом месте мне делается немного стыдно за свою профессию. Вот он, образ психолога в массовом детском сознании человек, к которому лучше не попадать, а то замучает разговорами! Неудивительно, что наше присутствие в школах так неэффективно. Я делаю мысленную пометку: Лишний раз по ушам не ездить.

Еще через пару минут Вера начинает рассказывать, что нарочно демонстрирует дома свою депрессию, чтобы на нее обратили внимание и отвели к психиатру. Вере очень хочется, чтобы доктор прописал ей каких-нибудь таблеток от настроения, потому что сама она со своими чувствами не справляется. Я предлагаю научить справляться без таблеток, но у Веры нет сил на то, чтобы делать упражнения.

В подростковом возрасте на фоне гормональной бури справляться со своими чувствами действительно очень сложно. Эмоции становятся сильными, практически неуправляемыми. Взрослеющий человек не понимает, что с ним происходит, не понимает, почему ему так плохо, и очень смутно представляет, что со всем этим делать. Банальные шутки вызывают неудержимый хохот. Огорчение от мелких неприятностей легко превращается в глубочайшую депрессию. Одна из распространенных тактик в этом случае напиться успокоительных, чтобы отпустило. Иногда это бывают довольно тяжелые и токсичные препараты, извлеченные, например, из бабушкиной аптечки. Иногда это заканчивается отравлением и в дальнейшем квалифицируется как попытка суицида. А человек мог просто не понимать, когда передозировал препарат, что от десяти стандартных доз ему не станет в десять раз лучше.

Лучше всего, естественно, чтобы препарат подбирал доктор. Но вести ребенка к психиатру стыдно. Ни один родитель не хочет обнаружить, что его ребенок психически ненормальный, поэтому от сигналов тревоги, которые подает Вера, взрослым чаще всего удобнее экранироваться. Поэтому Вера берет проблему в свои руки и начинает активно искать помощи на стороне рассказывать, что ей нужны таблетки, выяснять, что лучше пить от плохого настроения и где это достать. В этот момент, например, с Верой легко сможет вступить в контакт наркодилер.

Вера: Раньше я дико призерала наркоту а щас такая думаю СУКА НАКАЧАЙТЕ НАРКАТОЙ ПЛИЗ
Е.К.: ну на###. у моей подруги кусок нижней челюсти сгнил от той дряни, которой она ставилась
Вера: Оу п####ц


Взывать к разуму занятие по большей части бестолковое. Эффективная аргументация должна содержать мощный запоминающийся образ. Такое, чтоб потом не развидеть. И, например, ребенок, шагающий в окно во имя кита, это потрясающая по силе воздействия картина. Можно бесконечно ссылаться на статистику и доказывать, что только в одном проценте случаев прослеживается связь детско-подросткового суицида с тематическими группами в соцсетях. Нам все равно будет казаться, что игры это самая главная угроза. Просто потому что из такого сюжета получаются куда более интересные и запоминающиеся материалы, чем из типичной истории о том, что ребенку было очень, очень одиноко в собственной семье.

3. Кто кого

Помните девочку Машу, которая хотела найти себе куратора? На первый взгляд кажется, что это несчастное дитя, которое в любой момент может стать жертвой каких-нибудь злоумышленников. Посмотрим, что произойдет, если с Машей действительно кто-нибудь попытается вступить в контакт.

Привет, пишу я, любишь китов?

На следующий день Маша находит мое сообщение и принимается засыпать меня вопросами. Сообщения от Маши приходят со скоростью примерно штука в секунду. Я едва успеваю читать, не то что отвечать.

Маша требует, чтобы я немедленно призналась, что я куратор (и парень к тому же). Маша требует, чтобы я прислала ей её IP-адрес, потому что все кураторы так делают (и она с одной стороны ужасно боится, что я тоже так могу, с другой стороны ей хочется убедиться, что опасность настоящая, а не какая-то там поддельная). Маша пишет: нет уж, это я буду давать тебе задания. Ну-ка, давай, порежь руку! И так далее.

В общем, если в результате общения Маши с Настоящим Куратором кто-то свихнется почему-то мне кажется, что это будет не Маша. Чего на самом деле ищет девочка, которая говорит, что ищет смерти? На самом деле она ищет острых ощущений. Тайны, риска, интриги, но чтобы в конечном итоге выйти победительницей.

Дима: Мне интересно а если я допустим не выполню задание угрозы будут? Я просто хочу чтобы были угрозы. Это как то прям пугает


Каждый год гибнет несколько зацеперов, но мы понимаем, что ребята, которые подсаживаются сзади на поезд, делают это не для того чтобы умереть. Они делают это для того, чтобы выжить и потом иметь возможность сказать: Я это сделал, и со мной ничего не случилось. Игра с реальным риском это адреналин, буря эмоций и возможность круто повысить свой статус среди сверстников. Если ты не побоялся и прошел через игру, значит ты сильный, смелый, ловкий. По своему функционалу такие игры близки к ритуалам инициации у примитивных племен: там где надо уйди одному на охоту и завалить льва или еще что-нибудь в том же духе. Да, это опасно, да, есть некоторый процент летальных исходов, но если ты через это прошел, ты поднимаешься на более высокую ступень в иерархии.

Ну, мы понимаем, что инициатический опыт можно получить по-разному. Например, если тот же самый подросток сходил с группой в горы, в серьезный долгий поход, посмотрел с вершины горы в глаза вечности, а потом с этим опытом вернулся домой, то это ничуть не менее сильный эпизод в его жизни. Но это уже требует некоторой родительской включенности: если не самим сходить с чадом, то как минимум найти туристическую секцию и привести чадо туда. А если специально не создавать условий, подросток находит возможность испытать себя при помощи того, что у него есть под руками. А под руками может быть, например, железная дорога.

4. Одиночество в толпе

Через пару дней после того, как я вступила в группу, ребята решили обсудить, кто зачем пришел. И тут оказалось, что практически весь активный состав группы (те, кто что-то пишет, наговаривает голосом, делится фотографиями) пришел из любопытства. Вера сказала, что ей было бы интересно потроллить куратора. Обсуждать это все там, где может прочитать админ, было немного стремно, и я предложила сделать еще одну группу, где можно поговорить кулуарно. Народ за эту идею с удовольствием ухватился, и синий кит раздвоился на моих глазах: у него появилось подполье.

Когда стало можно говорить свободнее, ребята оживились и стали больше разговаривать на личную тематику. Вера кидает фотографию своего завтрака, Костя рассказывает, как он перекрасил волосы, Лена взахлеб рассказывает в аудиосообщениях, как она провела ночь со своим новым парнем Обычная такая подростковая тематика. Проблема одна: каждый из них говорит о себе, и за редкими исключениями они не дают друг другу никакой обратной связи.

Ну ладно, можно проигнорировать фотографию блинчиков. Но вот Костя упоминает, что его сегодня чуть не сбила машина И тишина. Костя еще раз, в надежде, что его кто-нибудь заметит, говорит: И да, меня сегодня чуть не сбила машина.

Я прошу рассказать, как это произошло. Костя, наконец дождавшись интереса к себе, рассказывает, как он сонный переходил улицу и не заметил машину. Как она сигналила и остановилась буквально в тридцати сантиметрах от него. Это важный, очень эмоциональный эпизод. Костя только что чуть-чуть не умер, и ему хочется об этом поговорить. Если бы в этот момент Косте никто не ответил, для него это значило бы, что на самом деле всем на него наплевать. В такой степени, что не важно, жив он вообще или нет. И это не было бы пустой фантазией, а было бы отражением реального Костиного опыта общения.

Характерная тема в чате это шрамы. Шрамы у подростков где-то в том же смысловом поле, что татуировки и алкоголь. Иногда это проверка на смелость смогу или не смогу? А иногда это такой способ самопомощи. Когда чувствуешь физическую боль, сильные эмоции отступают. Аутичные дети, например, грызут себе руки, когда им тревожно и страшно. Подростки, не справляющиеся со своими чувствами, часто режут запястья.

Вера выкладывает фотографию забинтованного запястья со свежим порезом и комментирует:

Вера: Тип просто широкий, но не глубокий совершенно
Е.К.: ох ё. как же это паршиво должно заживать когда края расходятся
Вера: Это да
Оля: Даа. Оуу бинтиком даже
Вера: Это мама сделала ибо испугалась. Хотя ничего серьёзного не было


И здесь Вера поднимает очень важную тему: часто родители многого не знают о том, что происходит с их детьми, потому что дети не хотят их пугать. Когда девочка смотрит на свой порез, она видит кровь, а потом видит, как кожа заживает. Она может сравнивать свои порезы с порезами друзей, и ее статус в компании отчасти может быть связан с наличием шрамов. Когда мама видит порезы на своем ребенке, у нее смыслы совершенно другие. У нее перед глазами начинают вставать картины, как дочка умирает, истекая кровью. Кое-как отмахнувшись от этой мысли, она начинает представлять, как девочку никуда не берут на работу, потому что кому нужна ненормальная с изрезанными руками? И так далее. А когда мама паникует, она не может быть источником эмоциональной поддержки. Поэтому про то, что может вызвать панику у родителей, подростки предпочитают рассказывать не им, а друг другу. И это могло бы неплохо работать если бы они друг другу отвечали.

На детской площадке часто можно наблюдать, как ребенок подбегает ко взрослому, задает какой-то вопрос и уносится, не дожидаясь ответа. И наоборот: задаешь ребенку вопрос, а он молчит. Откуда это берется? Это когда мы у детей спрашиваем что-нибудь дежурное, типа как дела? и не просим, не дожидаемся ответной реплики. Если все время так общаться, ребенок привыкает к тому, что речь не предполагает взаимодействия. Он ее таким образом вписывает в картину мира. Для него сказать это вбросить в пространство и уйти. Когда он становится старше, то он и в чате ведет себя аналогично: приходит, что-то пишет и тут же уходит в офлайн. А зачем ждать ответа, если все равно никто не ответит?

Психологи из Пенсильванского университета в рамках проекта Мировое благополучие занимаются исследованиями текстов в социальных сетях. Одна из вещей, которые их интересовали, это как можно по тексту понять, страдает ли человек от депрессии. Опуская подробности, они нашли самое главное слово, по частоте употребления которого можно определить депрессию.



Это слово один.

А теперь представим себе сообщество ребят, которые не отвечают друг другу, потому что у них вообще нет такой модели поведения выражать заинтересованность в другом человеке. Даже если они собрались вместе, каждый из них одинок, и то, что он говорит, он говорит в пустоту.

Одного этого уже достаточно для того, чтобы почувствовать себя очень, очень неуютно в этом мире. Дэн Гилберт, специалист по человеческому счастью, утверждает, что нашел только один вполне надежный предиктор удовлетворенности жизнью, и этот фактор качество отношений с другими людьми. В общем, легко можно представить, насколько счастливо сообщество детей, которым сложно даже просто поддерживать диалог, а не то что вступать в отношения друг с другом.

5. Поговори со мной

Какую роль в этой картине играет куратор? Куратор это прежде всего человек, который тебе гарантированно отвечает. То, что он склоняет к самоповреждениям и суициду, второстепенно по сравнению с тем, что с ним можно поговорить. Позже я наблюдала самые разные варианты общения игроков с куратором: куратора троллили, куратора пытались отговорить (одумайся, что ты делаешь, это же плохо и незаконно!), с куратором разговаривали о философии, с куратором крутили романы (одновременно несколько игроков, разного пола), куратора объявляли лучшей подругой и так далее. Иногда это происходило на фоне игры, иногда после игры, иногда вместо игры. Характерный вариант это когда игрок доходит до последнего задания, забивает на последнее задание и продолжает общаться со своим куратором просто так. Можно догадаться, что человеческого общения ему хотелось больше, чем выйти в окно!

Работу в чате я, собственно и начала с того, что стала отвечать на каждый эмоциональный вброс и раскручивать оттуда связный разговор. С одной стороны, это давало определенную модель поведения (которой ребята вполне могли не иметь в реальной жизни), с другой подавало сигнал, что да, ты кому-то важен и интересен. Мы всерьез обсуждали любую поднятую тему, начиная от обработки царапин и укусов, заканчивая пирсингом и хореографией. У активных участников начали формироваться отношения со мной я стала для них постоянной, надежной, узнаваемой фигурой. Подстройка под манеру речи позволяла не сильно выделяться и поддерживать ролевую модель достаточно хорошо функционирующего подростка.

Примерно через месяц после моего прихода стало понятно, что куратор забросил игровой чат и не читает логи. Китовое подполье утратило актуальность, поскольку прятаться от куратора больше не было необходимости, но уже было понятно, что в небольшой компании ребятам проще разговориться и легче выстраивать отношения друг с другом. Когда ребята осознали, что игры не будет, я предложила, чтобы не было скучно, устроить что-то вроде психологического кружка. К тому моменту я уже не скрывала, сколько мне лет и чем я занимаюсь. Тусовка, надо сказать, отнеслась к этой информации совершенно спокойно. Тогда мне показалось, что это спокойное принятие произошло за счет надежных, хорошо выстроенных отношений. Но позже я приходила в другие китовые чаты уже сразу в качестве себя, взрослой тетки-психолога, и удивление иногда было, а отторжения не было. (Почему расскажу дальше.)

В психологический кружок ушла значительная часть актива первоначальной группы собственно, все, с кем я там общалась. К ним присоединились те, кому просто было скучно. Кружок получил рабочее название Анонимные киты и лег в основу китовой группы поддержки. А я отправилась в поле бродить по открытым суицидальным чатам и собирать тех, кому с нами было бы лучше.

6. Демография групп смерти

Основная часть населения суицидальных групп это ребята в возрасте от 13 до 18 лет. В конкретном чате обычно преобладают или те, кто помладше (13-14), или те, кто постарше (от 15). Но это средняя температура по больнице. Дальше начинаются нюансы. Дети более младшего возраста в кита иногда тоже заходят. Самым младшим игроком, которого я видела за полгода, была девочка восьми лет от роду. И да, она играла. Выполняла все задания и регулярно присылала своему куратору фотографии порезов старательно нарисованных на разных участках тела гуашевой краской. Надо сказать, что имитации в китовой теме не такая уж редкая вещь. Со стороны может показаться, что когда куратор выдает задания на порезы, то таким образом он приучает игроков к аутоагрессии. На практике, если человек режется в рамках игры, скорее всего, он резался и раньше, и это не является для него чем-то экстраординарным. Если человек до игры не резался, то он и на игре обычно не режется, а упражняется в карнавальном гриме. Возможны смешанные варианты: например, по собственному желанию человек режет ноги, чтобы окружающие не заметили, а по заданиям рисует себе порезы на руках при помощи гелевой ручки и губной помады.

Главная вещь, которую надо понимать про китовых ребят, это то, что от хорошей жизни в тематические чаты, как правило, не приходят. Это только в желтой прессе и примерно настолько же желтых новостях по телевизору довольный жизнью и благополучный во всех отношениях ребенок может посмотреть японский мультик и испытать непреодолимую тягу к суицидальному поведению. По факту практически у всех, кто приходит в тему, есть вполне объективные серьезные проблемы. Часто целый набор проблем. Иногда диву даешься, как человек вообще выживает в своей жизненной ситуации.

Основная объединяющая тема практически для всего сообщества это не желание умереть, как можно было бы подумать, а чувство одиночества. Умереть планируют не все, некоторые заходят, как они говорят, просто из любопытства, но даже эти любопытствующие жалуются на то, что им очень одиноко. Одиноко это значит нет друзей, не с кем пойти погулять, не клеятся отношения с противоположным полом, нет взаимопонимания с родителями, и если ты испытываешь какие-то сильные и тяжелые переживания, в реальной жизни о них абсолютно не с кем поговорить. Одно это весомый повод почувствовать себя несчастным, но этим, как правило, не ограничивается.

Многие ребята из депрессивных регионов, глухих деревень, и они жалуются на ощущение, что после школы у них нет никакого будущего, разве что бомжевать. Таких зачастую и к специалисту-то не особо отправишь. Какой психолог, если у человека в деревне даже школы, например, нет? Есть магазин и доступ в интернет, а больше примерно ничего, и по крайней мере до конца школы с подводной лодки никуда не денешься. Это само по себе эффективно создает ощущение безнадеги, а в комплекте еще могут быть пьющие родители, домашнее насилие и какие-нибудь много лет не леченные заболевания.

Неблагополучная семья характерная проблема. Часто приходят жаловаться именно на родителей. Что бьют, что не водят ни к одному врачу (хотя надо), что не позволяют продолжить учебу (ты слишком тупая, чтобы поступить в город). Семья может быть неполная, или ее может вообще не быть. Детдомовцы в теме не редкость. Если семья внешне производит впечатление благополучной, то и там могут быть серьезные подводные камни. Например, невозможность поговорить с родителями о своих переживаниях, потому что в ответ тебе говорят: Какие вообще могут быть проблемы в твоем возрасте? Вот у нас жизнь была тяжелая, а ты обут, одет, накормлен, и жаловаться тебе не на что! Проблемы-то, на деле, могут быть очень серьезные, вплоть до изнасилования и наркозависимости, но не спросишь не узнаешь! Ребята, которым в реале очень не хватает близкого взрослого, с которым можно доверительно пообщаться, пытаются найти себе такого взрослого в интернете. И хорошо, если они находят его в волонтере, а не в педофиле. Многие из тем, которые они приносят в чаты, это на самом деле запросы к родителям.

Кира: Нужен твой совет.
Е.К.: Чеслучилось?
Кира: У меня ужасно болит голова. И главный вопрос как сбить температуру.
Е.К.: Много ли температуры?
Кира: 38,5.
Е.К.: Врача надо вызывать, по хорошему.
Кира: Скорая не приедет. Семейный доктор тоже не вариант.
Е.К.: Если найдешь дома парацетамол, можно с него начать.
Кира: Таблеток вообще нет.


Жалобы на здоровье в китовой теме зачастую напоминают ситуацию с медицинской помощью где-нибудь в Африке. Денег нет, медикаментов нет, ближайший медработник в соседнем населенном пункте, а у человека, например, прихватило сердце, и он не понимает, что ему делать. И еще интереснее ситуация становится, если у человека не соматика, а психиатрия.

Китовые чаты это, по сути, заповедник всевозможной психической патологии. Порядка 90% суицидов связано с тем или иным психическим заболеванием, и вполне закономерно, что в суицидальных сообществах скапливаются ребята с различными расстройствами. Причем, в отличие от кабинетов специалистов, там они могут откровенно говорить о том, что чувствуют и что с ними происходит, не опасаясь, что их госпитализируют за лишнее сказанное слово.

В первую очередь, естественно, в ките собираются ребята с разными вариантами депрессий. Бывают относительно легкие депрессивные состояния, когда всерьез умереть не хочется, но мысли иногда посещают. А бывает, что приходят ребята с тяжелыми затяжными депрессиями. Они жалуются, что им больно, плохо, ничто не радует, чувств нет, цвета померкли, терпеть это все никаких сил уже нет, и в кураторе они ищут прежде всего человека, который избавит их от мучений. Иногда сами становятся кураторами: объясняют, что планируют умереть, но перед смертью хотят позаботиться о таких же несчастных людях, как они сами. За помощью эти ребята, как правило, не обращаются, потому что верят, что им все равно уже ничто не поможет. Бывает, что у них есть основания так думать: за плечами несколько госпитализаций, хождение по специалистам, и все безрезультатно депрессия не ушла. Если с игры такие ребята уезжают в стационар, через некоторое время они часто снова возвращаются в тему.

Еще одно характерное для суицидальных сообществ состояние это пограничное расстройство личности. У большинства пограничников (порядка 80%) основным средством эмоциональной регуляции являются самоповреждения. Эмоции пограничников экстремально сильны, и их так трудно выдерживать, что возникает желание прекратить эти переживания любым способом. Боль эффективно заглушает чувства, поэтому пограничники, когда им грустно, или страшно, или стыдно, склонны хвататься за лезвие. Если в чат пришел человек, на котором шрамы исчисляются десятками, это, как правило, именно такая история. Пограничники в суицидальные игры часто ходят не за финальным заданием, а больше для развлечения. Терять им нечего, они уже все равно режутся, почему бы не порезаться еще несколько раз в рамках игры?

Иногда, относительно редко, приходят ребята с психотическими состояниями. С расщеплением личности, с галлюцинациями, с навязчивым желанием убивать людей. Характерно, что они становятся не игроками, а кураторами суицидальных игр. Но на галлюцинации могут жаловаться и рядовые члены сообщества. И хорошо, если техническая возможность дойти до психиатра есть при должной настойчивости человека можно уговорить сходить к доктору. А вот если это то самое село и семья, которая в принципе не обращается ни за какой медицинской помощью (Немедикаментозные способы смягчения галлюцинаторной симптоматики в природе существуют например, средствами когнитивно-поведенческой терапии, но мы, в общем, догадываемся, какова вероятность, что человек с этой информацией встретится.)

Очень много педзапущенных ребят, с задержками развития, с трудностями обучения в школе. Они жертвы травли со стороны одноклассников, над ними смеются, на них кричат учителя, дома на них кричат из-за низких оценок родители (и хорошо, если только кричат). За их неуспешностью в школе стоят зачастую вполне поправимые проблемы: дефицит саморегуляции, дефицит внимания, нарушения сенсорной интеграции. Там мог бы здорово помочь школьный психолог или нейропсихолог если бы он был в наличии и был компетентен. К сожалению, в ответ на предложение пообщаться со школьным психологом часто звучат жалобы на то, что от этого психолога никакого толка. Например, потому что школьный психолог это завуч, который окончил двухмесячные психологические курсы. Или потому что это бабушка лет семидесяти, которая в рамках психолого-педагогической работы в основном занимается тем, что ругается на короткие юбки, косметику и пирсинг, которых в ее время не было.

Функциональные возможности китовой тусовки в среднем невысоки: трудно писать связные тексты из более чем двух-трех предложений, трудно рисовать, трудно выполнять задания, требующие каких-либо организационных или интеллектуальных усилий. Именно поэтому в суицидальных играх такие примитивные задания на уровне сделай один порез на руке. Более сложные задания игроки попросту не тянут, начинают разбегаться.

Часть сообщества составляют люди постарше. Бывает и 20+, и 30+. Тут обычно два варианта. Либо у человека тяжелая психическая патология или наркозависимость, и в силу заболевания он функционирует не на свой возраст, а как раз примерно на подростковый (поэтому с подростками ему комфортнее, чем со сверстниками), либо человек волонтер и хочет нанести немного добра.

Волонтеры и доброжелатели это особая история. Довольно много людей всерьез переживает за суицидальных подростков, и время от времени они приходят в тематические чаты с конкретной целью отговаривать от суицида. Иногда это такие же подростки, но более жизнелюбивые, иногда люди чуть постарше. Чаще всего они действуют очень неумело и сразу начинают вступать в конфронтацию, произнося шаблонные лозунги вида оглянись, жизнь так прекрасна и у тебя вся жизнь впереди. Таких не любят, потому что они страшно далеки от реалий жизни китовой тусовки. Когда ты сидишь в глухой деревне, не имеешь внятных перспектив получить образование и вырваться в город, при этом еще страдаешь букетом заболеваний, от которых в деревне тебя некому лечить (да и не то чтоб родители были заинтересованы везти тебя к врачу), то предложения оглянуться вокруг и увидеть, как прекрасен мир, выглядят в лучшем случае комично, в худшем оскорбительно. Поэтому восторженные энтузиасты в теме обычно не задерживаются.

Чуть более изобретательные доброжелатели прикидываются кураторами. Они исходят из идеи, что если человек пришел искать куратора, то ни с кем, кроме куратора, он разговаривать все равно не станет, а под видом игры как раз можно наладить контакт. Рациональное зерно здесь, кстати, есть. Иногда ребята приходят в чаты в остром состоянии, с туннельным сознанием, и в этот момент их действительно может не интересовать ничего, кроме способов связаться с куратором суицидальной игры. Но это скорее исключение. Обычно ребята вполне доступны диалогу и готовы поговорить о своем опыте и своих переживаниях, не важно, куратор ты, игрок или просто мимо проходил. У стратегии прикинуться куратором есть две основных серьезных проблемы. Во-первых, как показала практика, в группы ряженых кураторов через некоторое время приходят вполне настоящие кураторы и там под прикрытием начинают вербовать игроков. Во-вторых, у игроков, как правило, есть вполне четкие ожидания от игры, они сознательно и целенаправленно идут на игру с заданиями про самоповреждение, и если таких заданий от куратора не поступает, игрок ощущает, что его накололи. Куратора на этом месте посылают далеко, тщательно выстроенный контакт рвется, а игрок отправляется искать себе настоящую игру. Отдельный риск это то, что доброго куратора, если он хорошо замаскировался, могут случайно принять за настоящего и куда-нибудь о нем сообщить. Доброжелателю в этом случае придется долго объяснять, что он не преступник и ничего плохого в виду не имел. Добрая половина людей, которые приходят в чаты и объявляют себя кураторами, это такие вот энтузиасты.

Помимо стихийного, существует еще организованное волонтерство, основная цель которого пресечение деятельности кураторов и предотвращение суицидальных попыток, о планах на которые игроки иногда сообщают в чатах. В частности, Молодежная служба безопасности сидит практически везде. У игроков к этому отношение довольно сложное, потому что волонтер такого вида это в их представлении что-то вроде мента. То есть вроде бы он для пользы и безопасности, только на глаза ему лучше лишний раз не попадаться, а то полиции сдаст или в стационар отправит.

7. Риски

Реальность, как водится, оказывается несколько сложнее, чем ее себе представляют. Деятельность куратора суицидальной игры действительно является уголовно наказуемой, и за нее можно привлечь по статье 110.2 УК РФ. Это статья про побуждение к совершению самоубийства. А вот в деятельности игрока состава преступления нет. Есть статья, что нельзя организовывать суицидальные игры, но нет статьи, что нельзя в них участвовать. Приход сотрудника МВД, которого панически боятся многие игроки, на практике оборачивается некоторым количеством нервотрепки, неприятными объяснениями с родителями и небольшой воспитательной беседой об интернет-рисках, но серьезных негативных последствий не имеет если только не оказывается, что игрок находится в таком тяжелом состоянии, что ему необходима экстренная госпитализация. И вот здесь вступает в действие статья 29 Закона о психиатрической помощи, согласно которой человек может быть госпитализирован помимо своего желания, если он представляет непосредственную опасность для самого себя.

Принудительная госпитализация это палка о двух концах. С одной стороны, действительно, бывают острые состояния, когда человека небезопасно оставлять без присмотра, и необходимо срочное медицинское вмешательство, чтобы привести его в чувство. С другой стороны, качество этого медицинского вмешательства не гарантировано. Например, известно, что при депрессивных расстройствах госпитализация с фармакологической терапией приводит к ослаблению депрессивной симптоматики, но не снижает суицидального риска. Если дополнять фармтерапию психотерапией (в частности, когнитивно-поведенческой), то суицидальный риск снижается примерно вдвое, но вот как раз психотерапии в стационаре зачастую и нет. В результате можно наблюдать, как игроки, отлежав положенный срок в стационаре, снова возвращаются в тему и снова жалуются в чатах на суицидальные мысли.

При пограничном расстройстве госпитализация без исключительно серьезных показаний вообще вредна, поскольку со временем на базе опыта госпитализаций у человека может формироваться стратегия ухода от жизненных трудностей что-нибудь с собой сделать, чтобы положили в больницу, где можно немного отдохнуть. Игрок, который так густо изрезан, что смотреть страшно и хочется сразу отправить в стационар, это, как правило, как раз пограничник и есть. И если мы его без реальной угрозы жизни отправляем на этом месте в стационар, то оказываем ему, на самом деле, медвежью услугу. На одной фармтерапии меньше резаться он все равно не станет. Но может начать резаться больше.

Госпитализация сама по себе может становиться травмирующим опытом. Еще она может провоцировать самостигматизацию все равно я псих, ничего хорошего мне в жизни уже не светит, так что даже и пытаться не надо. Попутно может получиться стигматизация в собственной семье это если родители решают махнуть на ребенка рукой. Чего с ушибленным на голову сделаешь, пропащий человек! Это очень неблагоприятный сценарий: как только человека признали, по сути, бракованным (и он сам себя начал так воспринимать), вероятность обращения за адекватной помощью падает до уровня плинтуса. Готовность к сотрудничеству с врачом у принудительно госпитализированных людей тоже, как правило, не очень высокая. Те же таблетки с большей вероятностью будут выплюнуты, если человек не чувствует, что ему помогают, а чувствует, что его посадили за решетку. Поэтому принудительная госпитализация это последнее средство на тот случай, когда других осмысленных вариантов нет. То есть когда отговорить от совершения попытки никакими силами не удается, или когда при амбулаторном лечении невозможно обеспечить необходимый уровень безопасности. И такие случаи это скорее исключение, чем правило.

Для куратора, как уже было сказано выше, риски более высокие. После задержания психиатрическая экспертиза, а дальнейший маршрут может включать постановку на учет, спецшколу, колонию или опять же принудительное лечение. В течение недели от начала игры, а то и быстрее, куратором начинают интересоваться волонтеры, а следом им начинают интересоваться сотрудники полиции по месту жительства. Место жительства при этом может быть совершенно произвольным, и необязательно в России. Суицидальные игры это международная история. В русскоязычной китовой тусовке можно встретить кураторов и игроков из России, Украины и стран СНГ. Волонтеры связываются с МВД соответствующей страны, и дальше куратора задерживают и судят по законам той страны, гражданином которой он является. В соответствии с отечественным законодательством, реальный случай со смертельным исходом не является необходимым для осуждения куратора достаточно призывов.

Риски, связанные с самой игрой, не так велики, как их себе обычно представляют, но они существуют. Деятельность куратора не является в строгом смысле доведением до суицида. Как мы уже понимаем, в рамках игры трудно даже заставить человека резаться, если он изначально не планировал этого делать, не то что заставить его выйти в окно. Если на фоне игры происходит суицидальная попытка, как правило это связано с тем, что в реальной жизни игрока есть очень серьезные проблемы, которые собственно и толкают его к уходу из жизни. Происходящее на игре с этой точки зрения можно рассматривать как вариант ассистированного суицида. Куратор поддерживает уже существующее у игрока желание умереть и таким образом повышает степень суицидального риска. Причем повышает чаще всего не очень сильно, если судить по количеству игроков, которые, серьезно думая о смерти, прошли игру от начала до конца, а попытки так и не совершили. Существенную опасность общение с куратором представляет для тех игроков, у которых на момент начала игры уже есть тяжелая психическая патология, уровень критики снижен, а произвольный контроль над поведением ослаблен. Это те ребята, у которых и без всяких игр суицидальный риск очень высокий.

Секретные кураторские психотехнологии на практике, как правило, целиком сводятся к бомбардировке любовью, как в тоталитарных сектах. Игроку рассказывают, что он самый лучший, что порезы у него самые красивые, что куратор мечтает с ним встретиться на том свете после игры. Одинокие игроки легко впадают в зависимость от такого отношения, и иногда возникает эффект, когда игрок никакими силами не может перестать общаться с куратором, хотя уже понимает, что это не очень полезное общение и пора бы с ним завязывать. Длительное общение с куратором, в свою очередь, создает благодатную почву для развития страхов. Насмотревшись на картинки с расчлененкой, которые кураторы присылают для воодушевления, некоторые игроки, например, начинают страдать ночными кошмарами. Еще один типичный страх это что если выйти из игры, то куратор обязательно пришлет убийц. В общем, можно представить себе, как это сказывается на душевном состоянии.

Уля: После того как я послушала музыку и посмотрела видео которые скидывала мне кураторша, мне серьезно начало казаться, что я сошла с ума, мне страшно находиться одной в комнате, стала оочень бояться темноты, хотя раньше обожала гулять одной ночью, так же я боюсь засыпать и это ещё не всё...


Помимо вредных факторов, непосредственно связанных с игрой, имеет место еще ряд неспецифических. В первую очередь, это риск стать жертвой чужой немотивированной агрессии. В китовой тусовке троллей и агрессоров много. Часть из них это сами игроки, которые в реальной жизни являются жертвами травли или насилия, поэтому в сети им периодически хочется на ком-нибудь отыграться. Еще одна часть это люди, которые специально приходят в суицидальные чаты, чтобы самоутверждаться за счет слабых и уязвимых. Поскольку многие площадки не модерируются совсем, выгнать оттуда троллей бывает затруднительно.

Время от времени в тематические чаты приходят колумбайнеры, наркодилеры или распространители детской порнографии. Иногда приходят педофилы, прикидывающиеся кураторами. В большом немодерируемом чате педофил, парадоксально, несколько менее опасен, чем на ВК. Если он у кого-то в личке начинает просить фотографий с обнаженкой, и барышне такой поворот разговора не нравится, через две минуты скрин этого разговора попадает в общий чат, а через пять минут педофила дружно матерят все, кто в это время оказался в онлайне.



Более опасный вариант это когда куратор в первую очередь занимается подталкиванием к суициду (и у игрока не возникает сомнений, что это настоящий куратор), а побочно занимается сексуальной эксплуатацией игрока, требуя от него фотографий в рамках заданий. Тут к рискам от самой игры добавляются типичные риски, связанные с пересылкой фотографий шантаж обнародованием фотографий, собственно обнародование.

Поскольку многие из игроков в дополнение к проблемам с самоповреждением имеют еще проблемы с пищевым поведением, в тематических чатах довольно часто можно встретить фотографии анорексичных барышень на стадии глубокого физического истощения и описания экстремальных диет. Для игроков с расстройствами пищевого поведения в ремиссии такой контент является триггерным и может провоцировать рецидивы. То же касается обмена фотографиями порезанных рук тех, у кого сформирована зависимость от порезов, эти фотографии побуждают резаться чаще и глубже, поскольку срабатывает эффект соревнования. Слухи о том, что кто-то в сообществе все-таки совершил суицид, на некоторое время повышают суицидальный риск для всего сообщества может запускаться волна подражаний. Причем необязательно это будут непосредственно суицидальные попытки: могут быть угрозы, анонсы, демонстративные акции или какие-нибудь очень странные выходки, про которые человек потом не может объяснить, что на него нашло. Например, среди зимы пойти гулять в одной футболке на ближайшую заброшку. Таким образом, для людей с не очень устойчивой психикой сам факт нахождения в суицидальной тусовке является небезопасным, даже если они там ни во что не играют, а просто сидят и общаются.

8. Поиски путей помощи

В каком-то смысле суицидальные игры оказались не только вредными, но и полезными во всяком случае, группу повышенного риска теперь хорошо видно, она собирается большими компаниями в тематических чатах, и ее легко находить по ключевым словам. На этом месте, собственно, с группой риска надо было бы начинать как-то работать осталось понять, как это делать.

Исторически одним из первых способов работы было перенаправление группы риска на кризисные линии. В 2017 году, когда на ВК начали активно банить по ключевым словам суицидальные группы, на месте закрытой группы размещалась ссылка на проект Твоя территория чат доверия для подростков и молодежи. Количество обращений в службу резко возросло многие ребята открыли для себя возможность обратиться за помощью. Консультанты не справлялись с наплывом обращений и эмоциональной нагрузкой стало приходить много суицидентов. Недостаток финансирования, ограничивающий количество консультантов, до сих пор является основной проблемой службы. Вот так выглядит статистика обращений на проект Твоя территория за 2013-2020 годы. Можно видеть, что на данный момент консультанты успевают принять примерно одно из четырех обращений. На остальные просто не хватает рук.



Почему формат чата, а не более привычный телефонный? Потому что, как оказалось, в старшем подростковом возрасте спрос на телефоны доверия резко падает. Не потому что проблем становится меньше, а потому что разговаривать по телефону на личные темы становится психологически некомфортно. А вдруг родители что-нибудь услышат? Чат в этом смысле безопаснее, ты можешь сидеть в одной комнате с мамой, и она не узнает, о чем именно ты в этот момент переписывался с консультантом.

Есть, с другой стороны, и ограничения. Во-первых, на кризисную линию ты в любом случае должен обратиться сам. То есть тебе как минимум нужно дозреть до обращения за помощью. Это отсекает очень многих ребят с тяжелой депрессией, которые убеждены, что помочь им уже нельзя. Во-вторых, формат кризисной линии позволяет поговорить об актуальных чувствах, но к работе по формированию недостающих функций и навыков он не располагает. И если, например, обращается одинокий подросток, у которого нет друзей, потому что он не умеет общаться и боится это делать, то за час с ним можно поговорить про его страхи, но нельзя выстроить у него коммуникативные навыки. В-третьих, консультант на кризисной линии так же анонимен, как ты сам, и с ним не получиться выстроить настоящих отношений. Вопрос отношений особенно важен в ситуации текущего суицида когда человек, например, уже успел вылезти на крышу и решил напоследок с кем-то поговорить. Отношения это последняя вещь, за которую можно ухватиться, когда больше тебя ничего не держит, и если собеседник говорит: Я не хочу, чтобы ты уходил, то есть разница, произносит ли эти слова человек, которого ты знаешь и любишь, или человек, с которым ты познакомился только что.

Из этих соображений логически вытекает второй ранний формат помощи а именно, шефство. Шефством над конкретными подростками практически с самого начала занимались волонтеры, основной задачей которых была идентификация кураторов суицидальных игр. Когда волонтер сидит в чате и общается с подростками, то естественным образом выстраиваются какие-то отношения, и с кем-то из ребят они будут особенно близкими. У подростка появляется надежный объект привязанности, человек, которому он доверяет, и когда возникают какие-то проблемы любые проблемы, начиная от насморка, заканчивая желанием выйти в окно, то он обращается со своими проблемами именно к этому человеку. Ограничение здесь понятное отдельно взятый волонтер не может дружить таким образом с большим количеством подростков. И времени не хватит, и эмоционально тяжело. По опыту группы Китобой потолок, после которого начинается стремительное выгорание, это два-три постоянно нуждающихся в контакте кризисных подростка на одного волонтера.

Положим, в плотном сопровождении нуждаются не все члены сообщества, а только те, кто находится в особенно тяжелом состоянии и при этом не имеет других близких контактов. Но потребность переговорить о чем-то волнующем со знакомым надежным человеком периодически возникает у многих. И здесь мы опять же упираемся в нехватку рук. Когда волонтеры сильно ограничены во времени, они начинают игнорировать сообщения в личку, за исключением кризисных, и это, на самом деле, совершенно неполезный для сообщества посыл чтобы на тебя обратили внимание, ты должен начать умирать. Есть большая потребность в людях, которые занимались бы именно шефством. Например, в таком качестве очень востребованы люди с собственным опытом аффективных расстройств, поскольку они хорошо понимают специфику депрессивных состояний и могут поделиться опытом, как из этих состояний вылезать.

От шефа не требуется глубоких познаний в области психологии. Ему в любом случае нужна определенная подготовка, но не масштабов законченного психологического или педагогического образования. Основные умения быть эмоционально теплым и внимательно слушать, не осуждая собеседника за то, как он поступает, потому что в шефе нуждаются в первую очередь как в близком друге. Есть одно но. Если человека накроет и он пойдет на крышу или на рельсы, то именно шеф будет тем, кому он напишет попрощаться. Это сообщение нужно будет успеть увидеть, и потом нужно будет удерживать человека в контакте или пока он не придет в чувство и не передумает умирать, или пока к нему не приедут. Переговоры в ситуации текущего суицида могут длиться три-четыре часа, и произойти это может когда угодно.

Один из главных страхов, связанных с такими ситуациями, это что если человек погибнет, тот, кто разговаривал с ним последним, может пойти под суд как виновник его гибели. В действительности, неуспешная попытка помочь ненаказуема, и даже если человек гибнет после общения с консультантом кризисной линии, винить консультанта не будут. Да, он психолог, да, это его работа попытаться остановить суицидента, но даже работа психолога, проведенная по всем правилам искусства, не дает стопроцентной гарантии, что человек выживет. С другой стороны, нужно будет как-то жить дальше с тем, что этого человека ты не удержал. И нужно принимать возможность того, что однажды кого-то можно не удержать. Естественно, если волонтер работает не как одинокий рейнджер, а в рамках команды, то есть возможность по ходу разговора запросить рекомендаций у более опытных товарищей, инициировать спасательную операцию при необходимости, но в любом случае, когда у тебя в личных сообщениях начинает умирать человек это страшно.

Еще один распространенный миф это что с чужим несовершеннолетним ребенком без разрешения родителей общаться незаконно. Общение как таковое тоже ненаказуемо (иначе, как мы догадываемся, надо было бы сразу привлечь половину интернета), наказуемо вступать с чужим несовершеннолетним ребенком в интимную переписку это статья 135 УК РФ. Если тринадцатилетний человек приходит в чат и хочет поговорить там про то, что его в школе травят, то для того, чтобы пообщаться с ним на эту тему, не нужно ни образования, ни чьего-либо разрешения, достаточно иметь желание и время.

Но, как мы понимаем, если человек находится в тяжелом состоянии, желательно, чтобы он пообщался все-таки с профильным специалистом. Одно из направлений работы волонтеров собственно в этом и заключается: во-первых, убедить подростка, что ему нужно пообщаться с психологом или психиатром, во-вторых маршрутизировать его в нужном направлении. Как ни парадоксально, первое зачастую существенно проще! Сама идея, что проблемы можно решить не только выходом в окно, а настроение чинится не только кровопусканием, а еще хорошо подобранными препаратами, многими воспринимается благосклонно особенно, если уточнить, что в стационар ложиться необязательно, можно наблюдаться амбулаторно. А вот дальше встает вопрос, куда послать.

Школьный психолог, как выше уже упоминалось, может вообще отсутствовать, или он может быть таким, что откровенничать с ним не захочется. Один из барьеров для обращения к школьному психологу это страх, что любая озвученная ему информация может утечь к родителям или учителям. В подростковом возрасте уже хочется конфиденциальности, а у школьного психолога конфиденциальность очень условная. Из-за этого к нему либо вообще не обращаются, либо ему предъявляется сильно отредактированная версия происходящего. Игроки, например, склонны умалчивать, что участвуют в суицидальной игре. Аналогичная проблема возникает, если специалиста выбирали родители, и они с ним в контакте. Психологу, который потенциально может поделиться информацией с мамой, будет рассказано только то, что можно знать маме. А о том, что осталось за кадром, человеку все равно нужно с кем-то поговорить. В результате иногда складывается странная ситуация, когда волонтеры выслушивают не только то, о чем подросток не может поговорить со своими родителями, но и то, о чем он не может поговорить со своим психологом.

Мира: Я хочу чтобы мамка закончила меня к психологам вадить.
Е.К.: Тебе это не помогает?
Мира: Нет. Просто трачу время.
Е.К.: Можно поговорить с психологами. Если у тебя есть ощущение, что их работа тебе не помогает, им полезно об этом знать.
Мира: Ну незнаю. Я все скрываю
Е.К.: Может быть, в этом дело. Психологу очень сложно нанести какую-то пользу, когда он про важные вещи не знает.
Мира: Ну блин. Я столько крови в день вижу п***ц. Своей.
Е.К.: Это имеет смысл обсудить с психологом, потому что с этим можно работать. Как минимум психолог поймет, что тебе навыки эмоциональной регуляции надо собирать.
Мира: Ну стремно они мамены подруги.
Е.К.: Это проблема. Ты им не можешь доверять, потому что боишься, что они все маме расскажут?
Мира: Да


Еще одна серьезная проблема это территориальная доступность. В крупных городах бывает довольно большой спектр вариантов, куда можно отправить за помощью человека с психическим расстройством. МСБ, кстати, собирает контакты клинических центров и конкретных специалистов, которые эффективно работают с суицидальными и самоповреждающимися подростками, так что если вы случайно знаете хороших подростковых психиатров с такой специализацией (где угодно на территории России или Украины), пишите сразу сюда. А вот что делать, если подросток находится в деревне, и семье не особенно интересно, в каком он состоянии? Или, например, в наличии есть только ПНД, где человек уже лежал и никакой положительной динамики не увидел?

Инна: Давали таблетки какието. Потом как овощь и памяти нет. Тупо снотворное лошалинная доза.


Дистанционное образование это сейчас более или менее отлаженная технология. Очному оно все еще уступает по качеству, но во всяком случае оно есть и как-то работает. А вот дистанционной психиатрической помощи в государственной системе здравоохранения пока не предусмотрено. С дистанционной психологической помощью ситуация ненамного лучше. И в некоторых случаях понятно, что посылать человека некуда, и либо он получает хотя бы какую-то помощь прямо здесь, в чатах, либо не получает никакой и нигде.

9. Эксперименты

Дальше начинается методологическая terra incognita отработанных способов профилактики суицидального поведения на базе чатов пока еще не существует. Да и вообще методология работы в чатах как таковая развита очень слабо. Например, есть система подготовки консультантов чата доверия от проекта Твоя Территория, но это во многом адаптация телефоного консультирования к текстовому формату. Если нужно поговорить с отдельно взятым подростком, наработки коллег очень помогают. Но в условиях нехватки волонтеров нужно было идти дальше и работать на уровне сообщества, чтобы ребята в экстренном случае могли чем-то помочь друг другу.

Группа поддержки была очень естественным решением. Практика формирования групп взаимопомощи из взрослых людей с аффективными расстройствами уже какое-то время существует этой темой занимаются в ассоциации Партнерство равных. Ведущий таких групп не психолог (хотя он может иметь психологическое образование), а такой же человек с диагнозом, как все остальные. Все члены группы, включая ведущего, на равных, и если ты говоришь о каких-то своих проблемах, тебя хорошо понимают, потому что у других членов группы проблемы в целом примерно такие же.

Опыт Партнерства равных невозможно было перенести на наш формат напрямую, поскольку они никогда не делали подростковых групп, но многие их наработки оказались очень полезны. (Алена и Настя, спасибо за тренинг ведущих, это было здорово!) Набор правил у нас по итогу получился несколько другой. Например, на нашей группе поддержки можно ругаться матом, но нельзя нарочно обижать друг друга. Наша группа не выровнена по диагнозу: в одной куче сидят ребята с депрессиями, с пограничным расстройством, с БАР, с шизофренией. Объединяющим фактором является не конкретный диагноз, а чувство одиночества и периодически возникающие мысли о смерти.

Что дает формат группы поддержки? Во-первых, в таком формате можно заниматься систематической работой по развитию коммуникативных навыков. На раннем этапе работы группы ведущий, по сути, занимается примерно тем же, чем воспитатель в детском саду: разруливает конфликты, помогает понять, где возникло недопонимание, демонстрирует образцы конструктивной коммуникации.

Таня: Лан все. Досвидание
Марат: Что случилось у тебя мы что обидели тебя да?
Е.К.: Полина расстроилась. Это тяжелая для нее тема.
Марат: Блин жаль конешно что ты уходишь!!! Бл* зря я начал про это. Блин безтакный я человек.
Е.К.: Ты не со зла.
Таня: Я сама начала.


Коммуникативные навыки это та вещь, которую человек может забрать с собой. Они хорошо переносятся из одной ситуации общения в другую. Применительно к китовому сообществу, например, оказалось, что ребята, которые сидели на группе поддержки, потом продолжают общаться на том же уровне и в открытых тематических чатах. Причем не только между собой, а и с другими людьми, которые там сидят. То есть через группу поддержки фактически можно влиять на культуру общения в целом по сообществу.

Еще одна важная функция группы поддержки это построение социальной сети. Для многих ребят группа поддержки становится первым опытом того, что у них есть собственная компания. В ките, как мы помним, аккумулируются те, кого травят в школе и у кого нет друзей в реальной жизни. Когда друзья появляются на группе поддержки, это по крайней мере отчасти решает основную проблему ощущение космического одиночества и что ты на самом деле никому в этом мире не нужен и не интересен. И здесь сразу несколько полезных следствий. Во-первых, человек, который сидит на группе поддержки, не так зависим от волонтера у него есть еще варианты, куда можно пойти поговорить о своих проблемах. Во-вторых, если человек начинает всерьез планировать суицид, то независимо от того, с кем он об этом поговорил, информация по хорошо налаженному сарафанному радио очень быстро дойдет до волонтеров, и ситуация будет под контролем. В-третьих, если где-то на открытой площадке человек подвергается атаке троллей, ему больше не нужно справляться с этим одному он может позвать друзей, или они сами набегут его защищать. Это очень ценный опыт для тех, кто в реальной жизни является жертвой травли.

За счет чего работает группа поддержки? Прежде всего за счет того, что у подростков ведущая деятельность это межличностное общение, и их не нужно специально уговаривать общаться между собой, они это делают естественным образом. И отношения, которые между ними при этом формируются, это настоящие дружеские отношения, а не искусственно сконструированные, как между психологом и его клиентом. Поддержка сверстника может быть неумелой, неловкой, но что важно она абсолютно искренняя.

Для людей с депрессивным складом личности в целом характерно, что о других они беспокоятся больше, чем о себе. Если мы формируем группу из депрессивных людей, то естественно, что в кризисное состояние они будут входить не все одновременно, а по очереди. Соответственно, в тот момент, когда одного участника накрыло, другие участники, которые в этот момент чувствуют себя лучше и у них есть ресурс на поддержку, начинают его утешать и отговаривать от неразумных действий. В следующий раз роли могут распределиться иначе, и в поддержке будет нуждаться тот, кто сейчас был утешителем, а тот, кого утешали, сам станет для другого точкой опоры.

Здесь мы отходим от представления о том, что есть условные больные, которые нуждаются в помощи, и условные сиделки, которые о них заботятся. Мы понимаем, что у каждого человека есть моменты, когда ему тяжело, и есть, с другой стороны, моменты, когда он в тонусе и может сам кого-то поддержать. Группа задействует тот ресурс поддержки, который уже есть внутри сообщества, даже если оно суицидальной тематики.

Это было очень круто, но я чувствовала, что мы можем больше. Где-то еще в самом начале работы группы поддержки я попыталась хотя бы частично реализовать там Penn Prevention Program это программа профилактики суицидального и аутодеструктивного поведения, которая используется в американских школах и американской армии. На русском языке адаптированный для семейного использования вариант этой программы публиковался под заголовком Ребенок-оптимист. По содержанию PPP это по сути вся та же самая когнитивно-поведенческая терапия. PPP у нас не зашла. Во-первых, мы уткнулись в то, что некоторые вещи нужно было объяснять, а ребятам было тяжко слушать аудиосообщения длиннее тридцати секунд. Это было ожидаемо: в депрессивных состояниях вообще все тяжело, и удерживать внимание тоже. Во-вторых, оказалось, что для значительной части группы когнитивная модель недоступна интеллектуально. И это тоже было предсказуемо, с учетом, что в ките скапливаются дети с трудностями обучения в школе. В-третьих, программа предполагала выполнение хотя бы каких-то домашних заданий, а делать задания не было ни сил, ни желания (и сама формулировка задачи часто оказывалась непонятной). Возможно, в условиях классной комнаты все то же самое сработало бы несколько лучше, но для чата это оказался нерабочий вариант. Нельзя сказать, чтобы этот опыт был вообще бесполезным после попыток взять штурмом PPP мы стали больше разговаривать про чувства и отношения, но нужно было искать какие-то другие подходы.

Напрашивалась мысль, что если дети пришли в кита играть, значит с ними можно во что-нибудь играть. Это, в общем-то, не новая идея. Одним из первых средств борьбы с суицидальными играми было создание профилактических игр, выстроенных по той же схеме, но с другими заданиями вызывающими не желание умереть, а желание жить. В Бразилии придумали Розового кита, например. Но это оказался не очень удачный формат. Классический Синий кит и его аналоги опираются на естественные психологические потребности возрастную потребность в риске и потребность выражать свои негативные переживания. Розовый кит давал что-то другое, а не то, за чем пришли игроки, потому для игроков по большей части оказывался неинтересен и не мог эффективно конкурировать с оригинальной игрой. Вдобавок Розовый кит со своим утрированным позитивом не учитывал суровых реалий жизни игроков, в контексте которых предложение полежать в ванне с пеной зачастую звучит как издевательство.



Я предположила, что мы могли бы поиграть в словесные ролевые игры и таким образом развивать навыки кооперации, мышление и позитивное самовосприятие. Ну и актуальные переживания отыграть заодно. Это тоже не сработало оказалось, что отыгрывать воображаемую ситуацию способны буквально единицы, а для остальных это неподъемная задача. До приключения как такового мы даже не дошли запоролись на симуляторе таверны. Я сделала вывод, что сильно переоценила уровень развития игровой деятельности в целом по сообществу, и опустила планку. Мы попробовали поиграть в простые словесные игры. Выяснилось, что поиграть в ассоциации китовые подростки в принципе могут и даже с некоторым удовольствием, а вот игра в города уже оказывается недоступной не хватает эрудиции. Если собирается компания, то ребята успешно самоорганизовываются на Мафию, но только при помощи бота. Кроме Мафии, по собственной инициативе они еще играли в правда или действие, но путались в правилах и быстро уставали.

Итак, элементы КПТ не зашли, игры тоже. Я решила проверить, не получится ли внезапно плюс из двух минусов и запустила для желающих пилотную группу на основе поведенческого тренинга DBT (диалектической поведенческой терапии). DBT изначально была создана для работы с пациентами, имеющими пограничное расстройство личности, суицидальную и парасуицидальную симптоматику. Соответственно, ее методы должны были подходить нам больше, чем классическая когнитивно-поведенческая терапия. Согласно канону, за выполненные задания участникам поведенческого тренинга полагается выдавать наклейки. Поскольку в условиях чата подкрепление наклейками не имеет никакого смысла (там наклейки выполняют роль мимики и пантомимики, а не поощрений), я решила вознаграждать игроков очками опыта и волшебными предметами. В самом начале программы мы создали игровых персонажей, и в дальнейшем все поощения прилетали в профиль персонажа. Тут нам очень сильно помог ролевой бот Шарлия Алвелс, предназначенный для игр по пятой редакции D&D. (Спасибо, Мит!) Вознаграждения полагались за сделанные домашние задания, за героические достижения в области саморегуляции (хотела порезаться, но перетерпела и резаться не стала) и за подвиги в реальной жизни например, собраться с духом и дойти до психиатра.

Марта: Мне можно прям кубок давать! Сколько я решалась на это!
Е.К.: Лови :)))
Шарлия: Предмет +Кубок добавлен в инвентарь Марта!
Марта: Блин та я ж пошутила!
Е.К.: А уже все :))) Кубок прилетел :))))


С легкой геймификацией мы продержались немного дольше, чем по программе PPP, но в конечном итоге все равно уперлись в то, что выполнять домашние задания нет сил, а когнитивная модель малопонятна. Зато выяснилось, что хотя отыгрывать персонажа тяжело, создавать свое сказочное альтер-эго ребятам нравится. И совершенно неожиданно самой популярной игровой механикой оказался отъем очков здоровья за резьбу по телу и прочие вредительские акции. Натурально, игроки приходили и отчитывались: Я порезался, сними с меня сердечко! Некоторые сами предлагали, чтобы я их лишала сердечек за что-нибудь еще например, за энергетики или за выдергивание волос. Это оказался очень удобный способ если не контролировать, то по крайней мере отслеживать нежелательные формы эмоциональной регуляции. С одной стороны, у игрока есть наглядный показатель того, что он делает что-то не то (в виде убывающего здоровья в профиле персонажа). С другой стороны, его при этом никто не осуждает и не ругает. Просто сердечек становится на одно меньше.

Поскольку стало понятно, что писать о себе по крайней мере интересно, дальше я предложила ребятам писать сочинения о своей жизни. Рассказывать о своем тяжелом опыте одно из основных средств восстановления после психической травмы, и у участников, кроме того, появлялась возможность ближе познакомиться друг с другом. Мы попробовали сделать маленький социальный проект, где игроки рассказывали, как на самом деле они дошли до кита. Без лиц, без реальных имен, просто рассказы о жизни и ладошки с котятами. (У многих суицидальных игр есть тотемное животное кит, сова, голубь У нашего проекта тотемным животным был котик.) Тут тоже обнаружился ряд подводных камней. Во-первых, для значительной части сообщества написать связный текст даже о самом себе очень тяжелая задача. Во-вторых, игроки дружно объявили, что не умеют рисовать, и изобразить котика соглашались только после долгих уговоров. В-третьих, включилась паранойя, и народ начал волноваться, что целью сбора информации является отправка всех участников проекта в стационар. Короче говоря, это тоже оказался не наш формат, но некоторое количество очень показательных материалов мы таким образом собрали. Вот тут можно посмотреть. Например, из рассказов становится понятно, что японские мультики тут примерно вообще ни при чем, и бороться надо с какими-то другими вещами. Например, с домашним насилием, с нехваткой культуры доверительного общения внутри семьи и с недоступностью профессиональной помощи в небольших населенных пунктах.

10. Профилактика

Журналисты очень любят задавать вопрос: А что делать родителям, чтобы их ребенок не оказался в таких группах? Телефон, может, проверять? Во-первых, сразу надо уточнить, что нахождение подростка в группе смерти это не проблема, а симптом проблемы. Если человек хочет умереть, то это желание он не приобретает в тематической группе, он уже с ним туда приходит. Поэтому вопрос надо формулировать иначе: что делать родителям, чтобы ребенок не чувствовал себя одиноко, и у него не возникало желания уйти из жизни.

Ответ на этот вопрос очень простой и скучный. С детьми надо общаться. Причем не в тот момент, когда уже проблемы переходного возраста, а с самого начала, когда ребенок еще маленький. Потому что характерные проблемы группы риска это дефициты еще дошкольного этапа развития. Неумение общаться это дефицит коммуникативных навыков, который образуется, когда маленький ребенок, пытаясь пообщаться с родителем, вместо внимания раз за разом получает в руки планшет или телефон. Самоповреждения это дефицит эмоциональной регуляции, который накапливается, когда ребенок вместо слов утешения слышит не хнычь, разнюнился тут, ну-ка успокойся немедленно.

Важно разговаривать с детьми об их переживаниях и верить, что эти переживания серьезны и значимы, даже если по меркам взрослой жизни речь идет о ерундовой проблеме. Если мы уважительно слушаем о маленьких детских бедах, то когда беды вырастут и станут большими и страшными, нам с большей вероятностью о них расскажут, веря, что мы не отмахнемся. Важно быть в курсе, с кем дружит ребенок и как складываются отношения с друзьями. Еще лучше, если с этими друзьями получится поддерживать контакт. Бывает, что человек не скажет о чем-то родителям, а друзьям скажет; если возникнет кризисная ситуация, у них будет возможность поднять тревогу.

Важно вовремя обращаться к специалистам, если у ребенка наблюдаются признаки психического расстройства. Если человек теряет интерес к прежним увлечениям, у него резко упала успеваемость в школе, он стал меньше общаться с друзьями, потерял аппетит и не спит по ночам, это повод обратиться к психиатру, потому что так выглядит депрессия и от нее нужно лечить. Если человек режет руки, истерит на ровном месте и злоупотребляет алкоголем, это тоже повод обратиться к психиатру весьма вероятно, что у человека пограничное расстройство, и он не может справиться со своими экстремальными эмоциями самостоятельно.

Если ребенок рассказывает о том, что его изнасиловали, худшее, что можно сделать, это запретить ему об этом говорить. Такие травмы не проходят сами по себе, и если человек вынужден молчать о том, что пережил, то это разрушает его изнутри и в конечном итоге может подтолкнуть к суициду. Если человек пережил насилие, ему нужен не совет попытаться об этом забыть, а поддержка близких и помощь психотерапевта.

Проверять телефон это, в общем случае, так себе идея. Мало кому нравится, когда супруг или партнер проверяет личную переписку, и детям тоже некомфортно, когда их переписку проверяют родители. Это очень грубое вторжение в личное пространство, и доверительным отношениям это совершенно не способствует. Но можно и нужно рассказывать детям про риски, связанные с общением в сети. Для педагогов по этой теме есть отличная методичка Мы в ответе за цифровой мир.

К сожалению, значительная часть ребят, которые в итоге оказываются в тематических сообществах, растет в семьях, где вопросом профилактики не задаются. И вообще не очень сильно интересуются, в каком состоянии ребенок и что происходит в его жизни. Это значит, что по-хорошему профилактические программы должны быть в образовательных учреждениях. Например, занятия по Penn Prevention Program, поставленные в сетку расписания, уменьшают вероятность развития депрессивных расстройств у школьников примерно вдвое. Еще одна задача на вырост это обеспечение подросткам возможности обратиться за помощью самостоятельно, без участия родителей. Если человек уже сам понял, что ему нужна помощь специалиста, нежелание родителей заниматься этим вопросом не должно становиться барьером. Точно так же не должно становиться барьером к получению помощи то, что человек находится в небольшом населенном пункте со слаборазвитой инфраструктурой.

А пока эффективная система профилактики не выстроена, самым главным защитным фактором остается наше бережное и внимательное отношение друг к другу. Будьте здоровы!
Подробнее..

Как раскрутить Телеграм-канал за 500 и избежать ботоводов

09.09.2020 20:04:18 | Автор: admin
Считается, что для раскрутки в Телеграмм нужен большой бюджет. Так то оно так. Особенно, если вы хотите сразу получить канал с большим охватам и начать хорошо зарабатывать. Только это вряд ли получится у новичка. Если бюджет распределить неправильно, то охваты упадут раньше, чем накопится хорошая сумма на следующие крупные закупы. Если же ваша главная цель сначала сделать хороший канал, то действовать можно постепенно, тщательно анализируя статистику закупов, эффективность рекламных постов и другие подводные камни. Тогда меньше денег улетит на ветер и для раскрутки своего канала понадобится не такая уж крупная сумма.

To buy or not to buy
Можно, конечно, просто купить канал. Но и тут начать сразу зарабатывать получится не у всех. Каналов сейчас продается очень много, и из этого моря предложений очень сложно найти действительно качественный продукт. На биржах полно накрученных каналов, а проверить качество аудитории очень сложно. Я, кстати, так и хотел поступить сначала, и именно по этой причине отказался. И нисколько не жалею об этом. Я уже видел достаточно каналов, у которых после покупки падали охваты, и они переставали обновляться. В их числе были и те, на которые поначалу упал глаз и у меня.

В итоге я решил делать канал с нуля. Над тематикой долго думать не пришлось, так как у меня есть много викторин в Google Play, и этот же контент я и решил использовать в Телеграме, заодно рекламируя и свои мобильные викторины. Так появился мой канал @TriviaGames, в который я решил не вкладывать сразу кругленькую сумму, а пиарить постепенно, но более эффективно. В итоге за 4 месяца мне удалось взять рубежи в 10к подписчиков и 2к охвата. Это конечно не ахти какие показатели, но при этом мои затраты составили около 500 долларов, часть из которых я уже отыграл. И в этом хабе, я решил поделиться кейсом продвижения канала и дать некоторые советы, как закупать рекламу с максимальной эффективностью и избегать ботоводов.

image

Открытый или закрытый
Наполнив за несколько дней канал, который было решено сделать открытым, я подписал на него все свои контакты из Телеграм, чтобы на нем были хоть какие-то подписчики и начал осторожно закупаться в маленьких каналах. Первые блины, как водится, получились комами. Две первых рекламы были совсем неудачными. Но постепенно удавалось нащупывать эффективные посты, и дело пошло гораздо веселее. Большинство реклам приносили мне подписчиков по 5-7 рублей. Но по неопытности бывало нарывался как на каналы, которые наливали мне ботов, так и на те ресурсы, с которых почти никто не приходил.

Первую тысячу подписчиков я сделал, потратив около семи тысяч рублей. После этого, как мне советовали некоторые админы, я решил закрыть канал и стал покупать рекламу в более дорогих ресурсах. И тут эффективность рекламы у меня резко упала. Мне уже редко когда удавалось получать подписчика дешевле 15 рублей. Полагаю, это было связано с тем, что многие просто отказывались подписываться на канал с небольшим количеством подписчиков, чтобы увидеть ответ на вопрос из рекламы. Тогда еще нельзя было открывать закрытые каналы без предварительной подписки на него, как это можно делать сейчас.

Таким образом, в моем случае открытый канал получился гораздо эффективнее. Тут надо упомянуть о том, что все рекламные посты представляли вопросы из моего канала. Как это принято говорить кликбейты. Это были не те загадки, которых сейчас можно в изобилии встретить в рекламных постах, а именно мои же вопросы. При этом, при открытом канале в рекламе была ссылка непосредственно на сам пост. А после того, как пользователь нажимал на кнопку ответа, ему показывался алерт, в котором говорилось о том, что чтобы узнать ответ, необходимо подписаться на канал. Это как оказалось давало гораздо больший эффект, чем закрытый канал с ответом на рекламный пост в закрепе.

Более того, голосовать разрешалось всем, в вот ответ могли видеть только подписчики. Такая схема позволяла мне сразу же вычислять ботоводов. Тех, которые после размещения рекламы наливают на рекламируемый ресурс ботов. В этом случае подписчиков оказывалось больше, чем ответов, а иногда даже больше чем просмотров поста. В то время, как обычно на канал подписываются не более 30 процентов, нажавших на кнопку ответа.

Первая реклама
Получив всего 300 пдп за 4000 рублей на закрытом канале, я снова сделал его открытым и продолжил осторожные закупы. В день покупал 2-3 поста по цене от 300 до 600 рублей. Я тщательно записывал и анализировал всю статистику отдач, чтобы определить, наконец, максимально эффективные посты, с которыми было бы не страшно заходить на крупные каналы. А заодно тестировал и различные тематики. Выяснилось, что ко мне плохо идут с исторических или географических каналов. А вот в литературных каналах и познавалках с фактами оказалась моя аудитория. Здесь порой удавалось покупать подписчиков дешевле 5 рублей. Наконец, я решился и на несколько крупных закупов, которые уместились в 2 дня. В итоге за первые 1,5 месяца я, потратив чуть более 30 тысяч рублей, получил около 4200 подписчиков и 1,5к охвата.

К этому моменту я уже сделал несколько ВП и продал парочку реклам. Эффект от первой своей рекламы я ждал с особым нетерпением. Было безумно интересно узнать отдачу со своего канала. Она получилась по ВП, и мне дали пост с подборкой на 4 канала. Я немного подумал, не попросить ли все-таки отдельный, но решил рискнуть, и не прогадал. На первый сайт из подборки (литературный) пришло почти 100 человек. Второй (познавалка) набрал почти полтинник, а два остальных примерно по 35 пдп. Более чем удачными получились и следующие рекламы.

image

Лето, эх лето
Получив хорошую стату в телеметре, я начал продавать рекламу даже дороже 300 CPM. Но, несмотря на хорошие отдачи, брали ее у меня как-то неохотно. Как мне кажется, многие админы даже не анализируют отдачи, а оценивают канал исключительно по охватам. У меня же охваты вдруг перестали расти. Начался июль самый несезонный месяц для ТГ. А тут еще и карантин закончился. Да и сказывалась моя тактика размещения рекламы напрямую на старые, но эффективные посты, в плане статистики по охватам. В отличие от закрытых каналов с ежедневными закупами, на моем закупы оказывали гораздо меньшее значение на охваты, так как далеко не все после ответа на вопрос, просматривали последние посты на канале. Рекламные то посты охваты набирали исправно, только в Телеметре, который считает охваты за последние 2 дня, это никак не отражалось.

Нужно было пережить это непростое время, и я решил перевести канал на самоокупаемость. Я начал делать много ВП, часто со своей доплатой. Это позволяло мне снижать расходы на рекламу (причем очень серьезно), заполнять свои рекламные места и держать плюсовую стату. После первой недели июля на моем канале было уже 6000 подписчиков. Мои затраты составили чуть более 40 тысяч, а доходы 6 тысяч. И это был самый большой отрицательный баланс за все время существования канала. К концу июля я набрал уже 7,5к подписчиков, потратив в общей сложности 48 тысяч и получив 14. Сейчас на @TriviaGames 10,3к подписчиков и 2к охвата. За все это время потрачено около 60 тысяч и заработано 35 тысяч. Минус постепенно сокращается.

Как избежать ботоводов
За эти четыре месяца я получил уже достаточно опыта, чтобы четко планировать рекламные кампании. Периодически я обращаюсь к уже проверенным каналам, в которых эффективно закупался (в некоторых не раз и не два). С некоторыми админами периодически повторяю ВП. А все новые размещения тщательно анализирую, что позволяет закупаться максимально эффективно. Главный помощник в этом, конечно же, Телеметр. И вот на что я обращаю внимание, чтобы избежать ботоводов.

image

Многое может рассказать уже главная страница канала. В первую очередь я навожу мышь на количество упоминаний в ТГ и смотрю рассчитанную телеметром стоимость подписчика. Если здесь я вижу цифру менее 10 рублей, то канал сразу же начинает вызывать у меня недоверие. Да, покупать подписчика дешевле вполне реально, а телеметр к тому же определяет стоимость пдп, исходя из CPM 300, в то время как летом было полно предложений по CPM 200. И все же, когда эта цифра слишком низкая, есть большое подозрение на ботов. У меня например, она составляет 14,39 рубля, хотя гораздо чаще подписчики мне обходились дешевле 10, а иногда и 5 рублей. Но были и неудачные размещения, было много ВП. Отсюда и такая цифра. Я, конечно, не утверждаю, что с цифрой менее 10 будет обязательно канал-ботовод. Но как правило, дальнейший анализ после такой цифры, только усиливал подозрения.

Далее на этой же странице я смотрю насколько активно закупается канал в последнее время, бросаю взгляд и на правую колонку, где видно больше последних закупов, чем в разделе подробной статистики. Если я вижу частые упоминания канала на биржах продажи или рекламы, то это уменьшает мое желание покупать здесь рекламу. А что касается основного раздела, то больше доверия у меня к каналам. у которых стоит бот телеметра и видно сколько из подписавшихся за определенный час ушли сразу. Хотя, все, что написано конкретно в этом абзаце, только улучшает или ухудшает мое мнение о канале, но не является поводом для принятия решения.

Главное же, что я теперь просматриваю в обязательном порядке это раздел Просмотры постов. Недавно здесь появился очень удобный график количества подписчиков и охвата. И теперь у некоторых каналов сразу же видна накрутка, которая выражается в резком взлете охватов при недостаточном для этого росте подписчиков. Например, я никогда не куплю рекламу, если увижу что-то типа такого.

image

Здесь очень наглядно видно, что за несколько дней охваты канала вдруг увеличились с 0,6 до 2к и продолжают держаться, а при этом количество подписчиков возросло менее значительно. Вот, кстати, как аналогичный график выглядит у меня.

image

Ниже приведены и охваты отдельных постов. Здесь также можно сделать выводы по активности аудитории. если она действительно живая, то посты, вышедшие в 18-19 часов (или тем более раньше) не должны набирать больше просмотров на следующий день. По крайней мере у каналов с охватами в 1-5к.

Не стоит лениться кликать и на почасовые охваты хотя бы одного поста. Здесь вам иногда может открыться такая картина, что анализ канала можно сразу заканчивать. Вот пример.

image

Здесь, как видно из графика, пост за первые час и 15 минут после выхода набрал менее 700 просмотров, а за второй час в 2 раза больше. При этом никакой рекламы канала не было, так что выводы о честности охватов в данном случае можно сделать однозначно. Интересно, что по общей таблице охватов и подписчиков накрутка здесь явно и не читалась.

Вообще, взгляд на охваты некоторых каналов может дать определенное представление и без телеметра. Я, например, подсчитал, что у меня примерно 25% суточно охвата набирается за первый час, а 50% за 2,5-3 часа. И когда на каком-то канале я вижу значительные отклонения от этих показателей как в ту, так или иную стороны, а при этом у канала не было крупных закупов (так что в телеметр заглянуть все-таки придется), то это уже весомый повод сразу переходить к следующему каналу.

Ну и наконец, Рекламные отдачи. Здесь я в первую очередь смотрю на наличие удачных отдач (менее 10 рублей за пдп) и их количество. Если таковых нет совсем, то канал для меня не интересен. Хотя я всегда просматриваю и какие каналы рекламировались, и как шел приход подписчиков по часам. Последнее часто помогает вычислить наливает ли админ этого канала ботов. А поводом для подозрений может стать примерно одинаковые приходы подписчиков в первые 3 часа. Всегда в первый час приходит гораздо больше чем во второй, и тем более в третий (тут кстати главное не забыть посмотреть точное время выхода рекламного поста). Также стоит обращать внимание на количество ушедших сразу у тех каналов, где такая статистика есть. Если у данного канала таковых очень мало, а скажем у другого, рекламировавшего тот же ресурс, под 30 процентов, то рисковать и покупать здесь рекламу крайне опасно.

Стоит взглянуть и на количество рекламных постов в день. Тут понятное дело, чем меньше тем лучше. А если на канале, каждый день выходит по 4 или более рекламы и идут они через один пост, то стоит учитывать, что это сильно скажется на эффективности вашего размещения.

Вот главные показатели, на которые я обращаю внимание при выборе рекламных площадок. Такой тщательный анализ позволяет избегать накрученных каналов, но, правда, не на 100%. За последний месяц я все-таки допустил пару ошибок. В первом случае закрыл глаза на неудачные отдачи при наличии удачных, и в итоге ко мне почти никто не пришел. Во втором, невнимательно посмотрел на динамику охватов. При более тщательном анализе я бы заметил, что посты на том канале слишком быстро набирают 1к охвата и потом прирост практически останавливается. В итоге ко мне пришли то ли боты, то ли рефералы, которые на вопросы не отвечали и рекламируемый пост не просматривали.

К счастью, потерял я на этом немного, так как в первом случае это было ВП на горящее место, а во втором цена рекламы составила всего 200 рублей. И кстати, в последнее время я редко покупаю рекламу дороже 1000 рублей. И совсем не потому, что не хватает бюджета. Просто с более крупных каналов подписчик получается почти всегда дороже, а анализировать их сложнее. Для меня гораздо предпочтительнее разместиться в уже проверенных каналах или искать новые и свежезалитые. Минус такого подхода большое количество потраченного времени (часто на покупку рекламы у меня выходит несколько часов). Но цель, как говорится, оправдывает средства.

Надеюсь, мои советы помогут многим избежать финансовых потерь из-за каналов-ботоводов. Всем удачи и отличных отдач!
Подробнее..

Твиттер Илона Маска в телеграме и с переводом на русский

16.06.2021 16:13:28 | Автор: admin

Хочу поделиться одной моей поделкой, возможно, кому-то она тоже будет полезна. В этой статье я поделюсь тем, что я сделал, чтобы читать Twitter-аккаунт Маска в удобном мне месте и имея под рукой перевод англоязычных твитов на русский.

Проблема

Последние несколько лет замечаю за собой, что хочу начать регулярно почитывать тот или иной блог, но если он не находится в зоне удобного или привычного доступа (к сожалению весь твиттер для меня таков, ничего не могу с собой поделать, не читатель я твиттера), то я довольно быстро забиваю на это. Еще хуже, если блог на другом языке, тут появляется дополнительная проблема, когда из-за технических терминов или разговорного жаргона сложно понять смысл. Собственно такие "преграды" обычно и приводят к тому, что вроде бы и хочется, но как-то не делается.

Идея

Сейчас я делаю на заказ программных роботов, которые в онлайне обрабатывают новостные потоки в соцсетях, фильтруют, выбирают наиболее интересные и цитируемые, и передают заказчику. Я подумал, почему бы мне не использовать свои навыки и не облегчить себе жизнь в описанной выше проблеме. Для этого нужно только каждые сколько-то минут заходить в твиттер, забирать новые сообщения, прогонять их через переводчик и отправлять в канал в телеграме. Кажется, ничего сложного.

Подводные камни

Первая проблема, с которой я столкнулся, это фрилансеры, у которых я пытался заказать кусок кода, который непосредственно выгружает новые посты из твиттера, все подряд отказывались от выполнения заказа. Прямо брали, а потом у одного компьютер сломался, у другого появились другие дела, третий в последний момент передумал.

Вторая проблема, отказ твиттера в выдаче доступа к API в описанных мной кейсах. То есть остается единственный вариант заниматься веб-скраппингом. Ну что ж.

Третья проблема, оказалось, что требуется довольно много ручной работы, чтобы преобразовать пост из твиттера в формат телеграма, и чтобы он прилично выглядел. В частности, картинки, предпросмотры ссылок, упоминания и тд.

Технологии

Я решил попробовать самостоятельно и начал гуглить что-то вроде "parsing twitter without API". Нашлось достаточно много решений, сразу скажу, что решениеtwint библиотека с открытым исходным кодом, которая вполне работоспособна и подошла под мою задачу.

Для того, чтобы перевести текст с английского на русский, я сначала было собирался использовать google translate, но понимал, что в нем ограниченное количество бесплатных переводов, решил что попробую использовать единственную известную мне нейросеть для перевода с английского на русскийfairseqот Facebook AI Research. Качество перевода показалось мне вполне приемлемым с точки зрения того, чтобы понять в чем суть твита, хотя оно и не было идеальным.

Все это я обернул в скрипт на языке программирования python и запустил на постоянную работу на своем сервере.

Примеры кода

Чтобы собрать данные из твиттера без использования выделенных девелоперских доступов, логинов, паролей и API, нужно сделать следующее:

Установить библиотеку twint

pip3 install twint

Запустить код формата

twint -u <name_of_twitter_user> -o output.csv --csv --since 2020-01-01 --retweets

Здесь есть важный момент, что запускается это все из-под bash, при том что у библиотеки есть python API (да и написана она на питоне), но при этом я потратил довольно много времени и оно ни в какую не заводилось. При этом если запускать из командной строки - все кроме автоматического перевода постов у меня работало.

Из функционала, который есть у библиотеки еще отмечу:

  • Возможность искать твиты пользователя по ключевому слову

twint -u username -s pineapple
  • Возможность находить твиты пользователя с указанием номеров телефонов и почт

twint -u username --email --phone
  • Поиск твитов вокруг определенной локации

twint -g="48.880048,2.385939,1km" -o file.csv --csv
  • Сохранение в Elasticsearch или SQLite

twint -u username -es localhost:9200twint -u username --database tweets.db
  • Сохранение фоловеров, подписок и избранных для пользователя

twint -u username --followerstwint -u username --followingtwint -u username --favorites

Данные сохраняются в csv файл, в котором присутствуют такие поля как (перечислю те, которые использовал сам, так как их много и большинство несут мало информации):

id - идентификатор сообщения

conversation_id - идентификатор беседы

created_at - дата создания сообщения

tweet - текст сообщения

mentions - упоминания пользователей твиттера ( список словарей)

urls - вставленные по правилам твиттера ссылки (например на youtube)

photos - ссылки на картинки

link - ссылка на твит

reply_to - список словарей с пользователямя, ответом на твиты которых является твит

У библиотеки есть также возможность перевода на другой язык, но она у меня совсем не заработала. Собственно по этой причине я искал другую возможность. Нашел я, как упоминал выше, открытую разработку Facebook AI Research - библиотеку fairseq, в которой можно скачать веса нейронки для перевода в частности из английского в русский и наоборот.

pip install hydra-core

Итого необходимо было установить:

pip install torch pip install hydra-core==1.0.0 omegaconf==2.0.1pip install fastBPE regex requests sacremoses subword_nmt 

Вообще мануал по установке и пример использование есть на сайте pytorch, но как видите у меня он немного отличается. Для того, чтобы сделать перевод можно пользоваться следующим куском из примера - он вполне рабочий:

import torch# Compare the results with English-Russian round-trip translation:en2ru = torch.hub.load('pytorch/fairseq', 'transformer.wmt19.en-ru.single_model',                        tokenizer='moses', bpe='fastbpe')ru2en = torch.hub.load('pytorch/fairseq', 'transformer.wmt19.ru-en.single_model',                        tokenizer='moses', bpe='fastbpe')paraphrase = ru2en.translate(  en2ru.translate('PyTorch Hub is an awesome interface!'))assert paraphrase == 'PyTorch is a great interface!'

В нем два раза производится перевод и проверяется соотвествие результата исходному варианту. При первом запуске с серверов torch хаба выкачивается большая нейронка, которая довольно шустро работает и на процессоре.

В целом, если не считать способов использования библиотек, у меня набралось еще довольно много кода, чтобы делать полученные сообщения достаточно читабельными, но это уже детали моего применения.

Как пользоваться

Выглядит сейчас это следующим образом. Каждый твит и ретвит на главной странице твиттера Илона Маска пропускается через переводчик, подбираются ссылки и картинки из поста, дальше все это сохраняется в пост в телеграм-канале. Выглядит это так

Итого у меня получилсятелеграм-каналпод названием "Твиттер Илона Маска" (подписывайтесь, мне будет приятно, что это нужно кому-то еще , будет дополнительный стимул поддерживать в будущем), в котором можно

1) читать новые и старые посты Илона Маска

2) видеть перевод текста на русский язык

3) перейти по ссылке на исходный пост в твиттере

И все это без регистрации и смс:)

Если эта статья показалась вам интересной, поставьте, пожалуйста апвоут (так ее увидит больше людей) и подписывайтесь на мой блог втелеграме, там я ежедневно рассказываю о всех своих экспериментах. Если хотите решить похожую проблему для своего бизнеса пишите вличку.

Подробнее..

Практическое применение аннотации в Java на примере создания Telegram-бота

17.12.2020 14:07:58 | Автор: admin
Рефлексия в Java это специальное API из стандартной библиотеки, которая позволяет получить доступ к информации о программе во время выполнения.

Большинство программ так или иначе пользуются рефлексией в различных его видах, ведь его возможности трудно уместить в одной статье.

Многие ответы заканчиваются на этом, но что более важно, это понимание вообще концепции рефлексии. Мы гонимся за короткими ответами на вопросы, чтобы успешно пройти собеседование, но не понимаем основы откуда это взялось и что именно понимать под рефлексией.

В этой статье мы коснемся всех этих вопросов применительно к аннотациям и на живом примере увидим как использовать, находить и писать свою.




Рефлексия



Я считаю, что ошибочно будет думать, что рефлексия в Java ограничивается лишь каким-то пакетом в стандартной библиотеке. Поэтому предлагаю рассмотреть его как термин, не привязывая конкретному пакету.

Reflection vs Introspection


Наряду с рефлексией также есть понятие интроспекции. Интроспекция это способность программы получить данные о типе и других свойствах объекта. Например, это instanceof:

if (obj instanceof Cat) {   Cat cat = (Cat) obj;   cat.meow();}

Это очень сильный метод, без чего Java не была бы такой, какая она есть. Тем не менее дальше получения данных он не уходит, и в дело вступает рефлексия.

Некоторые возможности рефлексии


Если говорить конкретнее, то рефлексия это возможность программы исследовать себя во время выполнения и с помощью неё изменять своё поведение.

Поэтому пример, показанный выше, является не рефлексией, а лишь интроспекцией типа объекта. Но что же тогда является рефлексией? Например, создание класса или вызов метода, но весьма своеобразным способом. Ниже приведу пример.

Представим, что у нас нет никаких знаний о классе, который мы хотим создать, а лишь информация, где он находится. В таком случае мы не можем создать класс очевидным путём:

Object obj = new Cat();    // а куда кошка пропала?

Воспользуемся рефлексией и создадим экземпляр класса:

Object obj = Class.forName("complete.classpath.MyCat").newInstance();

Давайте также через рефлексию вызовем его метод:

Method m = obj.getClass().getDeclaredMethod("meow");m.invoke(obj);

От теории к практике:

import java.lang.reflect.Method;import java.lang.Class;public class Cat {    public void meow() {        System.out.println("Meow");    }        public static void main(String[] args) throws Exception {        Object obj = Class.forName("Cat").newInstance();         Method m = obj.getClass().getDeclaredMethod("meow");         m.invoke(obj);    }}

Поиграть с ним можно в Jdoodle.
Несмотря на простоту, в этом коде происходит довольно много сложных вещей, и зачастую программисту не хватает лишь просто использования getDeclaredMethod and then invoke.

Вопрос #1
Почему в invoke методе в примере сверху мы должны передавать экземпляр объекта?

Далее углубляться я не буду, так как мы уйдём далеко от темы. Вместо этого я оставлю ссылку на статью старшего коллеги Тагира Валеева.

Аннотации


Важной частью языка Java являются аннотации. Это некоторый дескриптор, который можно повесить на класс, поле или метод. Например, вы могли видеть аннотацию @Override:

public abstract class Animal {    abstract void doSomething();}public class Cat extends Animal {    @Override    public void doSomething() {        System.out.println("Meow");    }}

Задумывались ли вы, как оно работает? Если не знаете, то, прежде чем читать дальше, попробуйте догадаться.

Типы аннотаций


Рассмотрим вышеприведённую аннотацию:

@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Override {}

@Target указывает к чему применима аннотация. В данном случае, к методу.

@Retention длительность жизни аннотации в коде (не в секундах, разумеется).

@interface является синтаксисом для создания аннотаций.

Если с первым и последним все более менее понятно (подробнее см.@Targetвдокументации), то@Retentionдавайте разберем сейчас, так как он поможет разделить аннотации на несколько типов, что очень важно понимать.

Эта аннотация может принимать три значения:


В первом случае аннотация запишется в байт-код вашего кода, но не должна сохраняться виртуальной машиной во время выполнения.

Во втором случае аннотация будет доступна и во время выполнения, благодаря чему мы сможем её обработать, например получить все классы, которые имеют данную аннотацию.

В третьем случае аннотация будет удалена компилятором (её не будет в байт-коде). Обычно это бывают аннотации, которые полезны только для компилятора.

Возвращаясь к аннотации@Override, мы видим, что она имеетRetentionPolicy.SOURCEчто в общем-то логично, учитывая, что он используется только компилятором. В рантайме эта аннотация действительно ничего полезного не дает.

SuperCat


Попробуем добавить свою аннотацию (это здорово нам пригодится во время разработки).

abstract class Cat {    abstract void meow();}public class Home {    private class Tom extends Cat {        @Override        void meow() {            System.out.println("Tom-style meow!"); // <---        }    }        private class Alex extends Cat {        @Override        void meow() {            System.out.println("Alex-style meow!"); // <---        }    }}

Пусть у нас в доме будет два котика: Том и Алекс. Создадим аннотацию для суперкотика:

@Target(ElementType.TYPE)     // чтобы использовать для класса@Retention(RetentionPolicy.RUNTIME)  // хотим чтобы наша аннотация дожила до рантайма@interface SuperCat {}// ...    @SuperCat   // <---    private class Alex extends Cat {        @Override        void meow() {            System.out.println("Alex-style meow!");        }    }// ...

При этом Тома мы оставим обычным котом (мир несправедлив). Теперь попробуем получить классы, которые были аннотированы данным элементом. Было бы неплохо иметь такой метод у самого класса аннотации:

Set<class<?>> classes = SuperCat.class.getAnnotatedClasses();

Но, к сожалению, такого пока метода нет. Тогда как нам найти эти классы?

ClassPath


Это параметр, который указывает на пользовательские классы.

Надеюсь, вы с ними знакомы, а если нет, то спешите изучить это, так как это одна из фундаментальных вещей.

Итак, узнав, где хранятся наши классы, мы сможем их загрузить через ClassLoader и проверить классы на наличие данной аннотации. Сразу приступим к коду:

public static void main(String[] args) throws ClassNotFoundException {    String packageName = "com.apploidxxx.examples";    ClassLoader classLoader = Home.class.getClassLoader();        String packagePath = packageName.replace('.', '/');    URL urls = classLoader.getResource(packagePath);        File folder = new File(urls.getPath());    File[] classes = folder.listFiles();        for (File aClass : classes) {        int index = aClass.getName().indexOf(".");        String className = aClass.getName().substring(0, index);        String classNamePath = packageName + "." + className;        Class<?> repoClass = Class.forName(classNamePath);            Annotation[] annotations = repoClass.getAnnotations();        for (Annotation annotation : annotations) {            if (annotation.annotationType() == SuperCat.class) {                System.out.println(                  "Detected SuperCat!!! It is " + repoClass.getName()                );            }        }        }}

Не советую использовать это в вашей программе. Код приведён только для ознакомительных целей!

Этот пример показателен, но используется только для учебных целей из-за этого:

Class<?> repoClass = Class.forName(classNamePath);

Дальше мы узнаем, почему. А пока разберём по строчкам весь код сверху:

// ...// пакет в котором мы сейчас находимсяString packageName = "com.apploidxxx.examples";// Загрузчик классов, чтобы получить наши классы из байт-кодаClassLoader classLoader = Home.class.getClassLoader();// com.apploidxxx.examples -> com/apploidxxx/examplesString packagePath = packageName.replace('.', '/');URL urls = classLoader.getResource(packagePath);File folder = new File(urls.getPath());// Наши классы в виде файловFile[] classes = folder.listFiles();// ...

Чтобы разобраться, откуда мы берём эти файлы, рассмотрим JAR-архив, который создаётся, когда мы запускаем приложение:

com   apploidxxx       examples               Cat.class               Home$Alex.class               Home$Tom.class               Home.class               Main.class               SuperCat.class

Таким образом, classes это только наши скомпилированные файлы в виде байт-кода. Тем не менее File это ещё не загруженный файл, мы только знаем, где они находятся, но мы пока по-прежнему не можем видеть, что находится внутри них.

Поэтому загрузим каждый файл:

for (File aClass : classes) {    // имя файла, на самом деле, Home.class, Home$Alex.class и тд    // поэтому нам нужно избавиться от .class и получить путь к файлу    // как к объекту внутри Java    int index = aClass.getName().indexOf(".");    String className = aClass.getName().substring(0, index);    String classNamePath = packageName + "." + className;    // classNamePath = com.apploidxxx.examples.Home    Class<?> repoClass = Class.forName(classNamePath);}

Всё, что сделано ранее, было только для того, чтобы вызвать этот метод Class.forName, который загрузит необходимый нам класс. Итак, финальная часть это получение всех аннотаций, использованных на класс repoClass, а затем проверка, являются ли они аннотацией @SuperCat:

Annotation[] annotations = repoClass.getAnnotations();for (Annotation annotation : annotations) {    if (annotation.annotationType() == SuperCat.class) {        System.out.println(          "Detected SuperCat!!! It is " + repoClass.getName()        );    }}output: Detected SuperCat!!! It is com.apploidxxx.examples.Home$Alex

И готово! Теперь, когда у нас есть сам класс, то мы получаем доступ ко всем методам рефлексии.

Рефлексируем


Как и в примере сверху, мы можем просто создать новый экземпляр нашего класса. Но перед этим разберём несколько формальностей.

  • Во-первых, кошкам надо где-то жить, поэтому им нужен дом. В нашем случае они не могут существовать без дома.
  • Во-вторых, создадим список суперкотов.

List<cat> superCats = new ArrayList<>();final Home home = new Home();    // дом, где будут жить наши котики

Итак, обработка обретает финальную форму:

for (Annotation annotation : annotations) {    if (annotation.annotationType() == SuperCat.class) {        Object obj = repoClass          .getDeclaredConstructor(Home.class)          .newInstance(home);        superCats.add((Cat) obj);    }}

И снова рубрика вопросов:

Вопрос #2
Что будет, если мы пометим @SuperCat класс, который не наследуется от Cat?

Вопрос #3
Почему нам нужен конструктор, который принимает тип аргумента Home?

Подумайте пару минут, а затем сразу разберём ответы:

Ответ #2: Будет ClassCastException, так как сама аннотация @SuperCat не гарантирует того, что класс, помеченный этой аннотацией, наследует что-то или имплементирует.

Вы можете проверить это, убрав extends Cat у Alex. Заодно вы убедитесь в том, насколько полезной может быть аннотация @Override.

Ответ #3: Кошкам нужен дом, потому что они являются внутренними классами. Всё в рамках спецификации The Java Language Specification глава 15.9.3.

Тем не менее вы можете избежать этого, просто сделав эти классы статическими. Но при работе с рефлексией вы часто будете сталкиваться с такого рода вещами. И вам на самом деле не нужно для этого досконально знать спецификацию Java. Эти вещи достаточно логичны, и можно додуматься самому, почему мы должны передавать в конструктор экземпляр родительского класса, если он non-static.

Подведём итоги и получим: Home.java

package com.apploidxxx.examples;import java.io.File;import java.lang.annotation.*;import java.lang.reflect.InvocationTargetException;import java.net.URL;import java.util.ArrayList;import java.util.List;@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@interface SuperCat {}abstract class Cat {    abstract void meow();}public class Home {    public class Tom extends Cat {        @Override        void meow() {            System.out.println("Tom-style meow!");        }    }        @SuperCat    public class Alex extends Cat {        @Override        void meow() {            System.out.println("Alex-style meow!");        }    }        public static void main(String[] args) throws Exception {            String packageName = "com.apploidxxx.examples";        ClassLoader classLoader = Home.class.getClassLoader();            String packagePath = packageName.replace('.', '/');        URL urls = classLoader.getResource(packagePath);            File folder = new File(urls.getPath());        File[] classes = folder.listFiles();            List<Cat> superCats = new ArrayList<>();        final Home home = new Home();            for (File aClass : classes) {            int index = aClass.getName().indexOf(".");            String className = aClass.getName().substring(0, index);            String classNamePath = packageName + "." + className;            Class<?> repoClass = Class.forName(classNamePath);            Annotation[] annotations = repoClass.getAnnotations();            for (Annotation annotation : annotations) {                if (annotation.annotationType() == SuperCat.class) {                    Object obj = repoClass                      .getDeclaredConstructor(Home.class)                      .newInstance(home);                    superCats.add((Cat) obj);                }            }        }            superCats.forEach(Cat::meow);    }}output: Alex-style meow!

Так что не так с Class.forName?

Сам он как раз-таки делает всё, что от него нужно. Тем не менее мы его используем неправильно.

Представьте себе, что вы работаете над проектов в котором 1000 и больше классов (всё-таки на Java пишем). И представьте, что вы будете загружать каждый класс, который найдёте в classPath. Сами понимаете, что память и остальные ресурсы JVM не резиновые.

Способы работы с аннотациями


Если бы не было другого способа работать с аннотациями, то использование их в качестве меток класса, как, например, в Spring, было бы весьма и весьма спорным.

Но всё же Spring вроде работает. Неужели из-за них моя программа такая медленная? К сожалению или к счастью, нет. Spring работает исправно (в этом плане), потому что использует несколько иной способ для работы с ними.

Прямо в байт-код


Все (надеюсь) так или иначе имеют представление, что такое байт-код. В нём хранится вся информация о наших классах и их метаданных (в том числе аннотаций).

Пора время вспомнить наш RetentionPolicy. В прошлом примере мы смогли найти эту аннотацию, потому что указали, что она является рантаймовой аннотацией. Следовательно, она должна храниться в байт-коде.

Так почему бы нам её просто не прочитать (да, из байт-кода)? Но здесь я не буду реализовывать программу для её чтения из байт-кода, так как это заслуживает отдельной статьи. Впрочем, вы сами можете это сделать это будет отличной практикой, которая закрепит материал статьи.

Для ознакомления с байт-кодом вы можете начать с моей статьи. Там я описываю базовые вещи байт-кода с программой Hello World! Статья будет полезна, даже если вы не собираетесь напрямую работать с байт-кодом. В нем описываются фундаментальные моменты, которые помогут ответить на вопрос: почему именно так?

После этого добро пожаловать на официальную спецификацию JVM. Если вы не хотите разбирать байт-код вручную (по байтам), то посмотрите в сторону таких библиотек, как ASM и Javassist.

Reflections


Reflections библиотека с WTFPL лицензией, которая позволяет делать с ней всё, что вы захотите. Довольно быстрая библиотека для различной работы с classpath и метаданными. Полезным является то, что она может сохранять информацию о уже некоторых прочитанных данных, что позволяет сэкономить время. Можете покопаться внутри и найти класс Store.

package com.apploidxxx.examples;import org.reflections.Reflections;import java.lang.reflect.InvocationTargetException;import java.util.Optional;import java.util.Set;public class ExampleReflections {    private static final Home HOME = new Home();    public static void main(String[] args) {            Reflections reflections = new Reflections("com.apploidxxx.examples");            Set<Class<?>> superCats = reflections          .getTypesAnnotatedWith(SuperCat.class);            for (Class<?> clazz : superCats) {            toCat(clazz).ifPresent(Cat::meow);        }    }        private static Optional<Cat> toCat(Class<?> clazz) {        try {            return Optional.of((Cat) clazz                               .getDeclaredConstructor(Home.class)                               .newInstance(HOME)                              );        } catch (InstantiationException |                  IllegalAccessException |                  InvocationTargetException |                  NoSuchMethodException e)         {            e.printStackTrace();            return Optional.empty();        }    }}

spring-context


Я бы рекомендовал использовать библиотеку Reflections, так как внутри она работает через javassist, что свидетельствует о том, что используется чтение байт-кода, а не его загрузка.

Тем не менее существует множество других библиотек, работающих схожим образом. Их достаточно много, но сейчас я хочу разобрать лишь один из них это spring-context. Он, может быть, лучше первого, когда вы разрабатываете бота в среде Spring. Но и здесь есть пара нюансов.

Если ваши классы это по сути managed beans, то есть находятся в контейнере Spring, то вам незачем повторно их сканировать. Вы просто можете получить доступ к этим бинам из самого контейнера.

Другое дело если вы хотите, чтобы ваши помеченные классы были бинами, тогда вы можете сделать это вручную через ClassPathScanningCandidateComponentProvider, который работает через ASM.

Опять же, довольно редко вы должны будете использовать именно такой метод, но как вариант его стоит рассмотреть.
Я писал на нём бота для ВК. Вот репозиторий, с которым вы можете ознакомиться, но писал я его давно, а когда зашёл посмотреть, чтобы вставить ссылку в статью, то увидел, что через VK-Java-SDK я получаю сообщения с неинициализированными полями, хотя раньше всё работало.

Самое забавное, что я даже версию SDK не менял, поэтому, если вы найдёте, в чем была причина, буду благодарен. Тем не менее загрузка самих команд работает нормально, и это именно то, на что вы можете посмотреть, если хотите увидеть пример работы со spring-context.

Команды в нём представляют из себя вот что:

@Command(value = "hello", aliases = {"привет", "йоу"})public class Hello implements Executable {    public BotResponse execute(Message message) throws Exception {        return BotResponseFactoryUtil.createResponse("hello-hello",                                                      message.peerId);    }}

Примеры кода с аннотацией SuperCat вы можете найти в этом репозитории.

Практическое применение аннотаций в создании Телеграм-бота


Всё это было довольно длинным, но необходимым вступлением для работы с аннотациями. Далее, мы будем реализовывать бота, но цель статьи это не мануал к его созданию. Это практическое применение аннотаций. Здесь могли быть что угодно: от консольных приложений до этих же самых ботов для вк, телеги и прочего.

Также здесь осознанно не будут выполнятся какие-то сложные проверки. Например, до этого в примерах не было никаких чеков на null или правильной обработки ошибок, не говоря уже об их логировании.

Все это делается для упрощения кода. Поэтому, если вы будете брать код из примеров, то не ленитесь доработать его, так вы лучше его поймете и настроите под свои нужды.

Мы будем использовать библиотеку TelegramBots с MIT лицензией для работы с API телеграма. Вы же можете использовать любую другую. Я выбрал её, потому что она могла работать как c (имеет версию со стартёром), так и без спринг-бута.

Собственно, я не хочу также усложнять код, добавляя какую-то абстракцию, если хотите, то можете сделать что-то универсальное, но подумайте, стоит ли оно того, поэтому для этой статьи мы часто будем использовать конкретные классы из этих библиотек, привязывая наш код к ним.

Reflections


Первый бот на очереди это бот, написанный на библиотеке reflections, без Spring. Будем разбирать не всё подряд, а лишь основные моменты, в особенности нас интересует обработка аннотаций. До разбора в статье вы сами можете разобраться в его работе в моём репозитории.

Во всех примерах будем придерживаться того, что бот состоит из нескольких команд, причём эти команды мы не будем загружать вручную, а просто будем добавлять аннотации. Вот пример команды:
@Handler("/hello")public class HelloHandler implements RequestHandler {    private static final Logger log = LoggerFactory      .getLogger(HelloHandler.class);        @Override    public SendMessage execute(Message message) {        log.info("Executing message from : " + message.getText());        return SendMessage.builder()                .text("Yaks")                .chatId(String.valueOf(message.getChatId()))                .build();    }}@Retention(RetentionPolicy.RUNTIME)public @interface Handler {    String value();}

В этом случае параметр /hello будет записан в value в аннотации. value это что-то вроде аннотации по умолчанию. То есть @Handler("/hello") = @Handler(value = "/hello").

Также добавим логгеры. Их мы будем вызвать либо до обработки запроса, либо после, а также комбинировать их:

@Retention(RetentionPolicy.RUNTIME)public @interface Log {    String value() default ".*";    // regex    ExecutionTime[] executionTime() default ExecutionTime.BEFORE;}default` означает, что значение будет применено, если не будет указан `value@Logpublic class LogHandler implements RequestLogger {    private static final Logger log = LoggerFactory      .getLogger(LogHandler.class);        @Override    public void execute(Message message) {        log.info("Just log a received message : " + message.getText());    }}

Но также мы можем добавить параметр, чтобы логгер срабатывал при определённых сообщениях:

@Log(value = "/hello")public class HelloLogHandler implements RequestLogger {    public static final Logger log = LoggerFactory      .getLogger(HelloLogHandler.class);    @Override    public void execute(Message message) {        log.info("Received special hello command!");    }}

Или срабатывал после обработки запроса:

@Log(executionTime = ExecutionTime.AFTER)public class AfterLogHandler implements RequestLogger {    private static final Logger log = LoggerFactory      .getLogger(AfterLogHandler.class);        @Override    public void executeAfter(Message message, SendMessage sendMessage) {        log.info("Bot response >> " + sendMessage.getText());    }}

Или и там, и там:

@Log(executionTime = {ExecutionTime.AFTER, ExecutionTime.BEFORE})public class AfterAndBeforeLogger implements RequestLogger {    private static final Logger log = LoggerFactory      .getLogger(AfterAndBeforeLogger.class);    @Override    public void execute(Message message) {        log.info("Before execute");    }        @Override    public void executeAfter(Message message, SendMessage sendMessage) {        log.info("After execute");    }}

Мы можем делать такое, так как executionTime принимает массив значений. Принцип работы прост, поэтому приступим к обработке этих аннотаций:

Set<Class<?>> annotatedCommands =   reflections.getTypesAnnotatedWith(Handler.class);final Map<String, RequestHandler> commandsMap = new HashMap<>();final Class<RequestHandler> requiredInterface = RequestHandler.class;for (Class<?> clazz : annotatedCommands) {    if (LoaderUtils.isImplementedInterface(clazz, requiredInterface)) {        for (Constructor<?> c : clazz.getDeclaredConstructors()) {            //noinspection unchecked            Constructor<RequestHandler> castedConstructor =               (Constructor<RequestHandler>) c;            commandsMap.put(extractCommandName(clazz),                             OBJECT_CREATOR.instantiateClass(castedConstructor));        }    } else {        log.warn("Command didn't implemented: "                  + requiredInterface.getCanonicalName());        }}// ...private static String extractCommandName(Class<?> clazz) {    Handler handler = clazz.getAnnotation(Handler.class);    if (handler == null) {        throw new           IllegalArgumentException(            "Passed class without Handler annotation"            );    } else {        return handler.value();    }}

По сути, мы просто создаём мапу с именем команды, которую берём из значения value в аннотации. Исходный код здесь.

То же самое делаем с Log, только логгеров с одинаковыми паттернами может быть несколько, поэтому мы чуть меняем нашу структуру данных:

Set<Class<?>> annotatedLoggers = reflections.getTypesAnnotatedWith(Log.class);final Map<String, Set<RequestLogger>> commandsMap = new HashMap<>();final Class<RequestLogger> requiredInterface = RequestLogger.class;for (Class<?> clazz : annotatedLoggers) {    if (LoaderUtils.isImplementedInterface(clazz, requiredInterface)) {        for (Constructor<?> c : clazz.getDeclaredConstructors()) {            //noinspection unchecked            Constructor<RequestLogger> castedConstructor =               (Constructor<RequestLogger>) c;            String name = extractCommandName(clazz);            commandsMap.computeIfAbsent(name, n -> new HashSet<>());            commandsMap              .get(extractCommandName(clazz))              .add(OBJECT_CREATOR.instantiateClass(castedConstructor));        }        } else {        log.warn("Command didn't implemented: "                  + requiredInterface.getCanonicalName());    }}

На каждый паттерн приходится несколько логгеров. Остальное всё так же.
Теперь в самом боте нам нужно настроить executionTime и перенаправлять запросы на эти классы:

public final class CommandService {    private static final Map<String, RequestHandler> commandsMap       = new HashMap<>();    private static final Map<String, Set<RequestLogger>> loggersMap       = new HashMap<>();        private CommandService() {    }        public static synchronized void init() {        initCommands();        initLoggers();    }        private static void initCommands() {        commandsMap.putAll(CommandLoader.readCommands());    }        private static void initLoggers() {        loggersMap.putAll(LogLoader.loadLoggers());    }        public static RequestHandler serve(String message) {        for (Map.Entry<String, RequestHandler> entry : commandsMap.entrySet()) {            if (entry.getKey().equals(message)) {                return entry.getValue();            }        }            return msg -> SendMessage.builder()                .text("Команда не найдена")                .chatId(String.valueOf(msg.getChatId()))                .build();    }        public static Set<RequestLogger> findLoggers(      String message,       ExecutionTime executionTime    ) {        final Set<RequestLogger> matchedLoggers = new HashSet<>();        for (Map.Entry<String, Set<RequestLogger>> entry:loggersMap.entrySet()) {            for (RequestLogger logger : entry.getValue()) {                    if (containsExecutionTime(                  extractExecutionTimes(logger), executionTime                ))                 {                    if (message.matches(entry.getKey()))                        matchedLoggers.add(logger);                }            }            }            return matchedLoggers;    }        private static ExecutionTime[] extractExecutionTimes(RequestLogger logger) {        return logger.getClass().getAnnotation(Log.class).executionTime();    }        private static boolean containsExecutionTime(      ExecutionTime[] times,      ExecutionTime executionTime    ) {        for (ExecutionTime et : times) {            if (et == executionTime) return true;        }            return false;    }}public class DefaultBot extends TelegramLongPollingBot {    private static final Logger log = LoggerFactory.getLogger(DefaultBot.class);    public DefaultBot() {        CommandService.init();        log.info("Bot initialized!");    }        @Override    public String getBotUsername() {        return System.getenv("BOT_NAME");    }        @Override    public String getBotToken() {        return System.getenv("BOT_TOKEN");    }        @Override    public void onUpdateReceived(Update update) {        try {            Message message = update.getMessage();            if (message != null && message.hasText()) {                // run "before" loggers                CommandService                  .findLoggers(message.getText(), ExecutionTime.BEFORE)                  .forEach(logger -> logger.execute(message));                    // command execution                SendMessage response;                this.execute(response = CommandService                             .serve(message.getText())                             .execute(message));                    // run "after" loggers                CommandService                  .findLoggers(message.getText(), ExecutionTime.AFTER)                  .forEach(logger -> logger.executeAfter(message, response));                }        } catch (Exception e) {            e.printStackTrace();        }    }}

Лучше всего узнать код самому и посмотреть в репозитории, а ещё лучше открыть его через IDE. Этот репозиторий подходит для начала работы и ознакомления, но в качестве бота он недостаточно хорош.

Во-первых, между командами не хватает достаточного уровня абстракции. То есть с каждой команды вы можете вернуть только SendMessage. Это можно побороть, использовав более высокий уровень абстракции, например BotApiMethodMessage, но и это на самом деле не решит все проблемы.

Во-вторых, сама библиотека TelegramBots, как мне кажется, не особо ориентирована на такую работу (архитектуру) бота. Если же вы будете разрабатывать бота именно на этой библиотеке, то можете использовать Ability Bot, который указан в wiki самой библиотеки. Но очень хочется увидеть полноценную библиотеку с такой архитектурой. Поэтому можете начать писать свою библиотеку!

Спринговый бот


Это приобретает больше смысла при работе с экосистемой спринга:

  • Работа через аннотации не нарушает общей концепции работы спринг-контейнера.
  • Мы можем не создавать команды сами, а получить их из контейнера, пометив наши команды как бины.
  • Получаем отличный DI от спринга.

Вообще использование спринга в качестве каркаса для бота это тема отдельного разговора. Ведь многие могут подумать, что это слишком тяжело для бота (хотя, скорее всего, они и на Java ботов не пишут).

Но я думаю, что, спринг это хорошая среда не только для энтерпрайза/веб-приложений. Просто он содержит в себе очень много как официальных, так и пользовательских библиотек для своей экосистемы (под спрингом имеется в виду Spring Boot).

И, самое главное, он позволяет реализовать очень много паттернов различными способами, предоставляемыми контейнером.

Реализация


Что ж, приступим к самому боту.

Поскольку мы пишем на спринговом стеке, то мы можем не создавать свой контейнер команд, а воспользоваться уже существующим в спринге. Их можно не сканировать, а получить из IoC контейнера.

Более самостоятельные разработчики могут сразу приступить к чтению кода.

Здесь же я разберу именно чтение команд, хотя в самом репозитории есть ещё пара интересных моментов, которые вы можете рассмотреть самостоятельно.
Реализация очень похожа на бота через Reflections, поэтому аннотации те же.

ObjectLoader.java

@Servicepublic class ObjectLoader {    private final ApplicationContext applicationContext;    public ObjectLoader(ApplicationContext applicationContext) {        this.applicationContext = applicationContext;    }        public Collection<Object> loadObjectsWithAnnotation(      Class<? extends Annotation> annotation    ) {        return applicationContext.getBeansWithAnnotation(annotation).values();    }}

CommandLoader.java

public Map<String, RequestHandler> readCommands() {    final Map<String, RequestHandler> commandsMap = new HashMap<>();        for (Object obj : objectLoader.loadObjectsWithAnnotation(Handler.class)) {        if (obj instanceof RequestHandler) {            RequestHandler handler = (RequestHandler) obj;            commandsMap.put(extractCommandName(handler.getClass()), handler);        }    }        return commandsMap;}

В отличие от прошлого примера здесь уже используется более высокий уровень абстракции для интерфейсов, что, конечно же, хорошо. Также нам не нужно самим создавать экземпляры команд.

Подведём итоги


Только вам решать, что лучше подойдёт под вашу задачу. Я разобрал условно три случая для примерно похожих ботов:

  • Reflections.
  • Spring-Context (без Spring).
  • ApplicationContext из Spring.

Тем не менее я могу дать вам совет, основываясь на своём опыте:

  1. Подумайте, нужен ли вам Spring. Он даёт мощный IoC контейнер и возможности экосистемы, но за всё приходится платить. Обычно я рассуждаю так: если нужны база данных и быстрый старт, то Spring Boot вам нужен. Если же бот достаточно прост, то можно обойтись и без него.
  2. Если же вам не нужны сложные зависимости, то смело используйте Reflections.

Реализация, например, JPA без Spring Data мне кажется довольно трудоёмкой задачей, хотя вы также можете посмотреть на альтернативы в виде micronaut или quarkus, но о них я только наслышан и не имею достаточного опыта, чтобы что-то советовать относительно этого.

Если вы приверженец более чистого подхода с нуля даже без JPA, то посмотрите на этого бота, который работает через JDBC через ВК и Телеграм.

Там вы увидите много записей вида:

PreparedStatement stmt = connection.prepareStatement("UPDATE alias SET aliases=?::jsonb WHERE vkid=?");stmt.setString(1, aliases.toJSON());stmt.setInt(2, vkid);stmt.execute();

Но код имеет двухгодичную давность, так что не советую оттуда брать все паттерны. И вообще я бы не рекомендовал таким заниматься вовсе (работу через JDBC).

Также лично мне не особо нравится работать напрямую с Hibernate. Я уже имел печальный опыт писать DAO и HibernateSessionFactoryUtil (те, кто писал, поймут, о чём я).

Что касается самой статьи, я пытался писать кратко, но достаточно, чтобы, имея в руках только эту статью, вы могли начать разработку. Всё-таки это не глава в книге, а статья на Хабре. Глубже изучить аннотации и вообще рефлексию вы сможете сами, например, создавая того же бота.

Всем удачи! И не забывайте о промокоде HABR, который дает дополнительную скидку 10% к той, что указана на баннере.

image



Подробнее..

Как перестать беспокоиться и начать жить

14.02.2021 14:06:25 | Автор: admin

Мониторинг работы организации с помощью докера и телеграм-бота

Многим хотелось бы знать, если вдруг что-то случится с их сайтом, магазином и т.п., особенно, если это не требует ни денег, ни времени, ни усилий. А ведь это довольно легко сделать: потратив совсем немного свободного времени, создадим докер контейнер, который будет периодически делать запросы в БД, расчитывать на их основании некие метрики, сравнивать их с пороговыми значениями и в случае превышения этих порогов, оповещать заинтересованных лиц.

Первым делом надо завести бота. Как это сделать можно нагуглить за 5 минут. Например, тут недавно была статья. Также нашему боту нужно разрешение на добавление его в группы, если получать сообщения планирует не один человек, а несколько. Для этого при создании бота надо написать BotFather команду /setjoingroups. После этого, собственно надо создать группу, добавить в нее нашего бота и всех заинтересованных в получении сообщений.

Далее воспользуемся библиотекой pytelegrambotapi и закончим подготовительный этап тем, что узнаем CHAT_ID Его можно узнать, например, включив логирование и, воспользовавшись командой из той же статьи, включить своего бота на ожидание команды /start. Затем ввести эту команду в созданной нами группе. Команда придет к боту, он ответит, логах будет выведена масса разной информации, в том числе и нужный нам CHAT_ID группы:

import loggingimport telebotbot = telebot.TeleBot(TOKEN)chat_id = CHAT_IDlogger = telebot.loggertelebot.logger.setLevel(logging.DEBUG)@bot.message_handler(commands=['start'])def start_message(message):    bot.send_message(message.chat.id, 'Привет, ты написал мне /start')bot.polling()

Теперь мы можем посылать сообщения ботом в нашу группу:

bot.send_message(chat_id=CHAT_ID, text=TEXT)

Чтобы было что посылать рассчитаем метрику, по данным полученным из БД. Допустим, у нас каждый бизнес процесс подтверждается СМС клиенту. Соответственно, если давно не посылались СМС, что-то идет не так.

Создадим класс, который будет отвечать за подключение к БД и расчет метрик. Я использовал для доступа в БД библиотеку pymysql. Она легкая и понятная:

import datetimeimport osfrom contextlib import closingimport pymysqlfrom pymysql.cursors import DictCursorfrom constants import *class Monitor:    def __init__(self):        self.starttime = datetime.datetime.today()        self.port = 3306        self.host = os.environ.get('MYSQL_HOST')        self.user = os.environ.get('USER')        self.password = os.environ.get('MYSQL_PWD')        self.db_name = 'backend'def sms_log(self):    with closing(pymysql.connect(host=self.host, port=self.port, user=self.user, password=self.password,db=self.db_name, charset='utf8', cursorclass=DictCursor)) as connection:        end_time = datetime.datetime.today()        start_time = end_time - datetime.timedelta(minutes=TIME_PERIOD)        st_time = start_time.strftime('%Y-%m-%d %H:%M:%S')                end_time = end_time.strftime('%Y-%m-%d %H:%M:%S')        with connection.cursor() as cursor:            query = f"SELECT COUNT(*) FROM sms_log WHERE created_at BETWEEN '{st_time}' AND '{end_time}'"            cursor.execute(query)            for row in cursor:                result = row['COUNT(*)']                if result < SMS_COUNT_ALERT:                    return f"За {TIME_PERIOD} минут с \            f"{start_time.strftime('%H:%M')} " \                 f"было отправлено {result} СМС, предел: {SMS_COUNT_ALERT}"

Подобным образом рассчитываем все интересующие нас метрики, сравниваем их с некими пределами, при превышении которых, высылаем сообщения. Для чего подправим главную функцию бота следующим образом:

def main():    bot = telebot.TeleBot(TOKEN)    chat_id = CHAT_ID    logger = telebot.logger    telebot.logger.setLevel(logging.DEBUG)      monitor = Monitor()    while True:        """         Выполняем запросы в БД каждые 15 (TIME_PERIOD) минут.         """      result = monitor.sms_log()      if result:            bot.send_message(            chat_id=chat_id,             text=result,            disable_notification=not monitor.is_day()        )      . . .      sleep(TIME_PERIOD*60)

Для того, чтобы сообщения ночью приходили бесшумно, используем следующую конструкцию:

disable_notification=not monitor.is_day()

где

@staticmethoddef is_day():    if 9 <= (datetime.datetime.today()).hour <= 23:        return True    else:        return False

также данный метод помогает сравнивать метрики с отличными от дневных пределами в ночное время.

Теперь, когда бот настроен и метрики рассчитаны, остается запихнуть все это добро в контейнер и задеплоить его на какую-нибудь круглосуточно работающую машину, либо в облако.

Докерфайл будет выглядеть примерно следующим образом:

FROM python:3.6-alpineCOPY requirements.txt requirements.txtRUN python -m venv venvRUN venv/bin/pip install -r requirements.txtRUN apk add bashCOPY src srcCOPY .gitignore .gitignoreCOPY boot.sh boot.shCMD ["bash", "./boot.sh"]

где requirements.txt:

PyMySQL==1.0.2pyTelegramBotAPI==3.7.6

и boot.sh:

#!/bin/shsource venv/bin/activateexec python ./src/bot.py

Можно не ставить bash и заменить его на /bin/sh , мне с ним привычнее при отладке, но на боевых условиях это лишнее. Образ также можно выбрать поновее, но и этот отлично справится.

Теперь его надо сбилдить:

docker build -t bot:latest .

И запустить, передав переменные окружения для подключения к БД в команде:

docker run --name bot -d -e USER=ххх -e MYSQL_HOST=ххх -e \MYSQL_PWD=ххх bot:latest

И можно ждать сообщений. Ну или не ждать, тут все зависит от метрик. Делов-то на полдня максимум. Однако, потратив их, мы получаем круглосуточное наблюдение за системой. Почти даром.

Дальше можно, например, настроить передачу рассчитанных метрик в Zabbix или подобный инструмент для логирования, графиков, отчетов и прочего.

Подробнее..

Пишем телеграм бота на node.js

13.07.2020 18:21:24 | Автор: admin
С полным кодом можно ознакомиться по ссылке.

Сегодня мы будем разрабатывать телеграм бота на node js, который умеет выводить статистику зараженных коронавирусом по всем странам.

Прежде всего в контакт-лист телеграмма нужно добавить @botFather и написать ему команду /newBot. Далее задаем имя нашего бота и, если оно не занято, придумываем идентификатор бота, по которому его можно будет найти.


Вот и все, наш телеграмм бот готов и botfather поделился с нами API Token, благодаря которому мы сможем управлять ботом

Далее создадим новый проект, введем npm init и добавим файл bot.js в котором будет разрабатываться наш бот.

Затем я установлю telegraf это один из популярных фреймворков для создания телеграмм бота. Смотрим документацию телеграфа, копируем в наш проект первоначальную настройку бота и быстро пройдемся по всем методам, которые указаны в примере:

const { Telegraf } = require('telegraf')const bot = new Telegraf(process.env.BOT_TOKEN) //сюда помещается токен, который дал botFatherbot.start((ctx) => ctx.reply('Welcome')) //ответ бота на команду /startbot.help((ctx) => ctx.reply('Send me a sticker')) //ответ бота на команду /helpbot.on('sticker', (ctx) => ctx.reply('')) //bot.on это обработчик введенного юзером сообщения, в данном случае он отслеживает стикер, можно использовать обработчик текста или голосового сообщенияbot.hears('hi', (ctx) => ctx.reply('Hey there')) // bot.hears это обработчик конкретного текста, данном случае это - "hi"bot.launch() // запуск бота

Поместим api token в наш пример и запуcтим бота.

node bot

Проверим работу нашего бота:


Теперь разберемся что лежит в ctx

Для этого после объявления константы bot мы можем использовать log:

ctx.message.from.first_name

Перезапустим наш проект, введем команду /start и в консоли мы получим объект, в котором мы сможем посмотреть необходимые данные о юзере:

{ "update_id": 375631294, "message": {   "message_id": 11,   "from": {     "id": 222222,     "is_bot": false,     "first_name": "Женя",     "username": "Evgenii",     "language_code": "ru"   },   "chat": {     "id": 386342082,     "first_name": "Женя",     "username": "Evgenii",     "type": "private"   },   "date": 1593015188,   "text": "/start",   "entities": [     {       "offset": 0,       "length": 6,       "type": "bot_command"     }   ] }}

Нас будет интересовать объект message, из которого мы сможем достать имя юзера

ctx.message.from.first_name

И текст, который он отправил боту:

ctx.message.text

Мы знаем что лежит в ctx и теперь мы можем приступить к подключению стороннего api, с помощью которого мы сможем получать статистику по коронавирусу. Для этого я буду использовать библиотеку, которая называется covid19-api. Установим ее в наш проект и заимпортим в файл bot.js:

const covidApi = require('covid19-api')

Далее мы удалим наш обработчик стикеров и сделаем новый обработчик, который отслеживает текст и отправляет запрос, чтобы получить данные о коронавирусе, используя метод getReportsByCountries, который можно найти в документации covid19-api:

bot.on('text', async ctx => {   const covidData = await covidApi.getReportsByCountries(ctx.message.text) //сюда помещаем сообщение юзера   ctx.reply(covidData) //и выведем полученные данные})

Давайте проверим какие данные мы получим. Для примера напишем нашему боту в телеграме: russia:


Отлично, мы получили целый ряд данных. Но если мы введем название страны с опечаткой наш бот прекратит работать и выдаст ошибку в консоль:


Чтобы это избежать нам нужно сделать обработчик ошибок и оповещать юзера, что такой страны не существует. Так же произведем небольшой рефакторинг кода и сделаем нашего бота более дружелюбным, изменим вывод сообщения, которое отправляется по команде /start, настроем корректное отображения данных о статистике и создадим в отдельном файле константу, которая будет содержать список всех стран на английском языке и будем выводить ее при использовании команды /help.

В итоге получаем код:

const { Telegraf } = require('telegraf');const covidApi = require('covid19-api');const COUNTRIES_LIST = require('./const')const bot = new Telegraf('1170363720:AAFJ4ALJebB8Luh5kt1DStmYYqV3TparhKc')bot.start( ctx => ctx.reply(`   Привет ${ctx.from.first_name}!   Узнай статистику по Коронавирусу.   Введи страну на английском языке и получи статистику.   Получить весь список стран можно по команде /help."`))bot.help( ctx => ctx.reply(COUNTRIES_LIST)) // список всех стран на английском языке можно взять в документации covid19-apibot.on('text', async (ctx) => {   try {       const userText = ctx.message.text       const covidData = await covidApi.getReportsByCountries(userText)       const countryData = covidData[0][0]       const formatData = `           Страна: ${countryData.country},           Случаи: ${countryData.cases},           Смерти: ${countryData.deaths},           Выздоровело: ${countryData.recovered}`       ctx.reply(formatData)   } catch(e) {       ctx.reply('Такой страны не существует, для получения списка стран используй команду /help')   }})bot.launch()

Который срабатывает как нам нужно:


Поздравляю! Мы завершили настройку нашего телеграм бота, который выводит статистику заболевших коронавирусом.
Подробнее..

Из песочницы Онлайн Магазин будущего

04.11.2020 18:10:50 | Автор: admin
Последний кризис показал, как важно уметь продавать онлайн. Угроза второй волны гонит магазины в киберпространство.

Мало сделать сайт. Надо привести в него людей. Стоимость привлечения посетителей в веб-магазины зашкаливает. Остается горестно вспоминать те времена, когда пионеры индустрии деловито занимали места на новой торговой площадке. Поисковики были маленькими, а цены зелеными.

Между тем, новые привычки уже формируются, и важно оказаться в правильном месте раньше конкурентов. Для этого, предлагаю совершить мысленную прогулку в недалекое будущее интернета вообще и онлайн магазина в частности. А направление зададут тренды.

Мы как-то все привыкли, что серьезный интернет бизнес строится на компьютерном интернете. А между тем

image

Уходим от конкуренции


По данным Digital 2020 больше половины времени(50.1%), которое мы проводим в интернете теперь приходится на мобильные телефоны.
Тренд 1: Мобильный интернет начинает доминировать
Аналитики из App Annie заявляют, что на мобильные приложения теперь приходится 10 из каждых 11 минут пользования мобильным устройством, а на просмотр веб-страниц уходит только 9% нашего мобильного времени. Приходится признать, что роль магазинов здесь выполняют мобильные приложения. Правила игры совсем другие. И конкуренция существенно ниже.
Тренд 2: В мобильной среде первую скрипку играют мобильные приложения

Снимаем ограничения


Обычно мобильные магазины работают с небольшим ассортиментом товаров/услуг. Ограничение напрямую связано с маленьким экраном смартфона.

Мы привыкли использовать меню классификации для поиска товара. Прайс в несколько тысяч наименований, в маленьком окошке, превращается в кошмар с картинками (как же без них). Большой объем данных делает классификатор не эффективным.



На заре интернета существовали классификаторы сайтов желтые страницы интернета. Они забыты. Сейчас, мы считаем нормальным, написать запрос и найти ответ в первой десятке выдачи поисковиков.

Похоже, что мы лучше стали общаться с компьютером. Монолог: "Смотри что у меня есть", меняется на диалог: "Что вам угодно?". Если пофантазировать, то вполне естественно сообщить телефону: "Хочу капучино", и получить его, где-нибудь поблизости.
Тренд 3: Среди большого объема данных, доминирует поиск по запросам, близким к естественному общению.
Заменяя классификатор на запросы, мы получим несколько плюшек.

  • Не надо ломать голову что важнее: категория Сапоги/Туфли или Мужские/Женские.
  • Легко использовать сложный товар с характеристиками. Для обуви это размеры и цвет, для автомобилей это марка авто или номер кузова.
  • Мы, побуждаем пользователя формулировать желание. Это помогает онлайн продавцу мониторить ход визита и помогать покупателю не задавая лишних вопросов.

Развивающийся искусственный интеллект делает язык запросов естественнее и точнее. Известны удачные кейсы с запросами по фотографиям или голосом. Обратите внимание, что та-же Яндекс Алиса наиболее полезна именно в мобильном секторе. С компьютера не сделать фотографию или видео так же свободно, как с телефона.
Смартфон в наименьшей степени удобен для коммуникации на экране, в наибольшей для голоса, фото или видео общения.
Примерно половина из 3,7 часов в день, которые люди проводят с мобильными в руках, они тратят на приложения социальных сетей и мессенджеры.

image
Тренд 4: Самые популярные мобильные приложения социальные сети и месcенджеры.
Время подвести итоги и заметить, что интернет смещается в сторону мессенджеров в мобильных устройствах. Вот удивил! Поддержка общения, это прямое назначение телефона. Можно ли утверждать, что к этому стремится центр тяжести всего интернета?

Давайте рассуждать: Интернет, это в первую очередь способ коммуникации. Мобильный телефон это средство коммуникации которое всегда под рукой. Коммуникации с кем? Не только с человеком, но и программой. Самое время вспомнить очередной тренд:


Тренд 5: Чат-боты набирают популярность
В более общем случае я бы сформулировал общее направление так:
Развитие интернета идет в сторону естественного общения человека
с человеком или машиной посредством мобильного терминала.
Я далек от радикальных мыслей, что все остальное вымрет. Думаю, что на горизонте ближайших 5-10 лет будет преобладать такая вот клиент-серверная архитектура, где основными клиентами выступают мобильные телефоны в лице своих владельцев. Не претендуя на роль первооткрывателя посмотрим через призму этой формулировки на онлайн торговлю.

Онлайн магазин будущего, на мой взгляд, должен быть мобильным приложением со способностями естественного общения. Вашим собеседником станет живой консультант или чат-бот. Эдакий продвинутый мессенджер.

Общение покупателя и консультанта на расстоянии очень актуально на фоне пандемии. Такой магазин может стать выходом для офлайн магазинов в условиях локдауна.

Написать Мобильное приложение это недешево. А наделить его способностями серьезного чата и подавно. Как оказаться на этой поляне раньше других?

Снижаем стоимость


Если найдем уже существующее приложение, это серьезно снизит стоимость проекта. Натянем логику чат-бота на морду существующих мессенджеров.

И знаете, выбор пока оказывается не велик Чат-боты, так или иначе, можно сделать во многих мессенджерах, но способности Telegram заметно шире. Самое важное для нас отличие, это возможность программировать кнопки (Помнить и набивать команды вручную, понравится не каждому). Если знаете аналоги напишите пожалуйста в комментарии.

Вдобавок, каналы делают Телеграмм социальной сетью. А это не лишняя плюшка в способностях онлайн магазина.
Телеграмм с чат-ботом это недорогая основа собственного онлайн магазина.
Получается достаточно запрограммировать внутреннюю логику чат-бота, об остальном позаботится мультиплатформенный Telegram.

Я предпринял попытку создать такой чат-бот. То что у меня получилось, после установки Телеграмм, можно посмотреть на https://t.me/repassBot.
Подробнее..

Всё, о чём должен знать разработчик Телеграм-ботов

24.02.2021 18:11:35 | Автор: admin

Вы вряд ли найдете в интернете что-то про разработку ботов, кроме документаций к библиотекам, историй "как я создал такого-то бота" и туториалов вроде "как создать бота, который будет говорить hello world". При этом многие неочевидные моменты просто нигде не описаны.

Как вообще устроены боты? Как они взаимодействуют с пользователями? Что с их помощью можно реализовать, а что нельзя?

Подробный гайд о том, как работать с ботами под катом.

Содержание

Начало работы

Telegram API vs Telegram Bot API

Рассказываю по порядку.

Телеграм использует собственный протокол шифрования MTProto. MTProto API (он же Telegram API) это API, через который ваше приложение Телеграм связывается с сервером. Telegram API полностью открыт, так что любой разработчик может написать свой клиент мессенджера.

Для написания ботов был создан Telegram Bot API надстройка над Telegram API. Перевод с официального сайта:

Чтобы использовать Bot API, вам не нужно ничего знать о том, как работает протокол шифрования MTProto наш вспомогательный сервер будет сам обрабатывать все шифрование и связь с Telegram API. Вы соединяетесь с сервером через простой HTTPS-интерфейс, который предоставляет простую версию Telegram API.

Среди упрощений Bot API: работа через вебхуки, упрощенная разметка сообщений и прочее.

Почему-то мало кто знает о том, что боты могут работать напрямую через Telegram API. Более того, таким образом можно даже обойти некоторые ограничения, которые даёт Bot API.

Об авторизации ботов через Telegram API в официальной документации

Вся информация ниже будет по умолчанию относиться и к Bot API, и к Telegram API. О различиях я буду упоминать. От некоторых ограничений Bot API можно избавиться с помощью локального сервера, об этом в конце статьи.

На чём пишут Телеграм-ботов

Бот должен уметь отправлять запросы Телеграм-серверу и получать от него апдейты (updates, обновления).

Как получать апдейты в Bot API

Получать апдейты можно одним из двух способов:

  • Поллинг просто регулярно отправлять запрос к серверу Телеграма для получения обновлений,

  • Вебхук сделать так, чтобы Телеграм сам отправлял запросы по нужному URL.

Конечно, удобнее использовать библиотеки, чем делать http-запросы "руками".

Если вы попробуете загуглить, как написать Телеграм-бота на Python, вам предложат воспользоваться библиотеками python-telegram-bot и telebot. Но не стоит.

Ну, если вы только хотите познакомиться с разработкой ботов и написать своего hello-world-бота, то можете, конечно использовать и их. Но эти библиотеки могут далеко не всё. Среди разработчиков ботов лучшей библиотекой для ботов на Python считается aiogram. Она асинхронная, использует декораторы и содержит удобные инструменты для разработки. Ещё был хороший Rocketgram, но он давно не обновлялся.

Также ботов часто пишут на JavaScript, для этого обычно используется Telegraf. Библиотеки есть и для многих других языков, но используют их реже.

Если же вы хотите использовать Telegram API, то можете воспользоваться Python'овскими Telethon и Pyrogram.

Пример кода бота

Если вы хотите получить какое-то представление о том, как вообще выглядит код бота, вот вам пример использования на aiogram с его странички на GitHub:

import asynciofrom aiogram import Bot, Dispatcher, typesasync def start_handler(event: types.Message):    await event.answer(        f"Hello, {event.from_user.get_mention(as_html=True)} ?!",        parse_mode=types.ParseMode.HTML,    )async def main():    bot = Bot(token=BOT-TOKEN)    try:        disp = Dispatcher(bot=bot)        disp.register_message_handler(start_handler, commands={"start", "restart"})        await disp.start_polling()    finally:        await bot.close()asyncio.run(main())

Этот бот будет отвечать на команды /start и и /restart.

Создание бота

Единственная информация о Телеграм-ботах, которой в интернете полным-полно: как создать бота. Это делается через специального бота BotFather. Когда вы создадите бота, BotFather даст вам его токен. Токен выглядит примерно так: 110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw. Именно с помощью токена вы сможете управлять ботом.

Один пользователь может создать до 20 ботов.

В BotFather удобно управлять ботами своими командой /mybots.

Юзернеймы

При создании бота нужно выбрать юзернейм. После этого поменять его будет очень сложно.

Как поменять юзернейм бота

Если у вас есть бот, и вы хотите дать ему более короткий юзернейм (который может быть занят неработающим ботом), то вы, теоретически, можете это сделать через @BotSupport.

Для этого бот должен (внезапно) быть рабочим, а также поддерживать английский язык.

Принято использовать такой формат обращения в поддержку:

  1. @old_username,

  2. @new_username,

  3. Что бот делает.

Если вы везунчик 9999 lvl вам ответят.

Юзернейм бота выглядит как обычный юзернейм, но он должен заканчиваться на "bot".
Вы могли видеть ботов с именами @pic, @vid, @sticker, @gamee это официальные боты Телеграма. Им можно нарушать все правила :)

Очень многие юзернеймы уже заняты. Свободных коротких юзернеймов осталось очень мало. И что самое грустное: почти все эти боты мертвы. Просто не отвечают на сообщения. Наверное, это просто разные любопытные люди хотят сделать бота, создают его, а потом забивают. У меня самого есть несколько лежащих ботов. Так что, думаю, лимит в 20 ботов на одного владельца вполне оправдан :)

Оформление бота

Открыв бота, пользователи могут увидеть его профиль.

Оформление бота настраивается в BotFather: меню /mybots Edit Bot. Там можно изменить:

  1. Имя бота.

  2. Описание (Description) это текст, который пользователи будут видеть в начале диалога с ботом под заголовком "Что может делать этот бот?"

  3. Информация (About) это текст, который будет виден в профиле бота.

  4. Аватарка. Аватарки ботов, в отличие от аватарок пользователей и чатов, не могут быть анимированными. Только картинки.

  5. Команды тут имеются ввиду подсказки команд в боте. Подробнее о командах ниже.

  6. Inline Placeholder об инлайн-режиме см. ниже.

Стандартный совет: Потратьте свое время и заполните описание и информацию бота, чтобы пользователям было понятнее и проще его использовать. Можете оставить там свои контакты. И поставьте аватарку, чтобы бота было проще отличать от других чатов в списке.

Сообщения и чаты

Запуск бота пользователем

Когда пользователь впервые открывает бота, он видит кнопку "Запустить" или "Начать" (зависит от платформы пользователя), на английском "Start". Нажимая на эту кнопку, он отправляет команду /start.

Таким образом, первое сообщение от пользователя это всегда /start (либо /start с параметрами, об этом ниже в разделе "Диплинки").

...если пользователь использует официальный клиент

На стороне сервера это не проверяется, поэтому теоретически пользователь может отправить боту любое сообщение через Telegram API.

Сообщения

Понятно, что главная функция бота отправлять и получать сообщения.

И то, и другое можно делать со всеми видами сообщений (фото и видео, файлы, опросы, голосовые сообщения и т. д.).

В Телеграме можно делиться файлами до 2 ГБ, но в Bot API более жесткие лимиты: боты могут скачивать файлы до 20 МБ и отправлять файлы до 50 МБ.

Работа с файлами в Bot API

Если бот уже загрузил файл на сервер Телеграма, то он может использовать file_id, чтобы отправлять этот файл.

Загружать файл на сервер можно в том числе и по URL файла.

Подробнее об отправке файлов в Bot API

Куда может писать бот

Бот может писать в личку только тем пользователям, которые его запустили. Пользователь может заблокировать бота, и тогда бот снова не сможет ему писать.

Боты не могут писать другим ботам.

Бота можно добавить в группу (если в BotFather включена соответствующая настройка). По умолчанию он видит не все сообщения (об этом ниже, в разделе "Видимость сообщений в группах").

В группе боту можно дать права администратора, чтобы он мог выполнять действия админов.

В одной группе может быть до 20 ботов. В публичные группы (группы с юзернеймом) ботов могут добавлять только админы.

Также бота можно добавить в канал, причем только как администратора. Самый частый способ использования ботов в каналах добавление кнопок под постами ("лайки", ссылки и прочее).

Как боты добавляют кнопки

У админа канала может быть специальное право: "Редактирование чужих публикаций". С помощью него боты редактируют посты, добавляя к ним кнопки.

Подробнее о кнопках тоже ниже.

Супергруппы

На самом деле многие группы в Телеграме являются супергруппами.

Почему так? Раньше было четкое разделение на группы и супергруппы. По задумке, супергруппы это группы для сообществ. Супергруппы могут иметь больше участников, публичные ссылки и другие плюшки.

Со временем, видимо, решили, что это неудобная концепция. Теперь обычная группа становится супергруппой, когда у группы меняются какие-нибудь настройки (подробнее тут). Вот такой костыль.

В этой статье под группами я подразумеваю и супергруппы, и обычные группы.

Супергруппу нельзя обратно превратить в группу. С точки зрения API супергруппа устроена так же, как и канал. Важное отличие супергрупп от обычных групп состоит в нумерации сообщений: о нём чуть ниже.

id пользователей и чатов

У каждого пользователя, бота, группы, канала в Телеграме есть собственный id. Различать чаты в коде бота следует именно по id, потому что он никогда не меняется.

В токене бота первая часть это его id. Например, токен 110201874:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw принадлежит боту с id 110201874.

В Bot API перед id супергрупп и каналов пишется -100. Так, id 1356415630 превращается в -1001356415630. Осторожно: вы не сможете сохранить это значение в 32-битный тип числа.

id сообщений

Каждое сообщение в Телеграме имеет свой id. Это относится и к системным сообщениям (пользователь зашел в группу, изменилось название группы и т. д.)

Через Telegram API боты могут получать по запросу сообщения в любом чате по их id.

id сообщений в супергруппах и каналах уникальны для чата: первое сообщение в чате имеет номер 1, второе имеет номер 2 и так далее.

id сообщений в личных сообщениях и обычных группах работают по другому. Там, можно сказать, нумерация сквозная: id сообщения уникально для каждого отправившего его пользователя. Так, первое сообщение от пользователя во всех личках и группах имеет номер 1, второе сообщение от того же пользователя имеет номер 2 и так далее.

Видимость сообщений в группах

Обычно бот должен реагировать именно на команды. Телеграм не уведомляет бота об остальных сообщениях, и это гарантирует приватность переписки.

Но если боту нужно видеть все сообщения в группе (например, если это чат-бот или антиспам-бот), для него можно отключить Privacy mode.

Privacy mode настройка в BotFather, которая по умолчанию включена. В таком режиме бот в группах видит только такие сообщения:

  • Сообщения с упоминанием бота,

  • Ответы на сообщение бота, ответы на ответы и так далее,

  • Системные сообщения,

  • Команды о них в следующем пункте.

А если Privacy mode выключен, то бот видит все сообщения в группе.

Если бот админ в группе, то он в любом случае видит все сообщения.

Бот, работающий через Bot API, в любом случае не будет видеть сообщения от других ботов.

Бот видит не все сообщенияБот видит не все сообщенияЯ включил Privacy mode, а он не работает

Нужно удалить бота из группы и добавить заново.

Исправленный баг с видимостью сообщений

Недавно был найден баг: боты не могли видеть некоторые сообщения от юзеров, если сообщения выглядят как команды с юзернеймом пользователя на конце.

Это могло нарушить работу антиспам- и других ботов.

Сейчас баг уже исправлен.

О Privacy mode в документации Bot API

Команды

Часто используемый способ "общения" пользователей с ботом команды. Команды начинаются на "/" и состоят из латинских букв (можно использовать цифры и нижние подчеркивания).

Команды подсвечиваются как ссылки: нажатие отправляет команду в чат.

В группах, чтобы различать команды от разных ботов, Телеграм предлагает ставить в конце команды юзернейм бота. Например: /start@examplebot.

В BotFather можно указать подсказки команд для бота. Он будут отображаться при вводе "/" и команд. Если есть подсказки, рядом с кнопкой "Отправить" появляется кнопка для открытия меню команд.

Если в подсказках команд есть /help, в профиле бота появляется кнопка "Помощь с ботом". Нажатие на кнопку отправляет эту команду.

Если в подсказках команд есть /settings, в профиле бота появляется кнопка "Настройки бота". Нажатие на кнопку отправляет эту команду.

Разметка сообщений

Как вы, наверное, знаете, сообщения в Телеграме могут содержать не только обычный текст, но и жирный, курсив и др. В Bot API разметку сообщений можно делать в HTML и Markdown.

Разметка в Telegram API

В Telegram API для разметки надо вместе с сообщением передавать entities (MessageEntityBold, MessageEntityItalic и так далее). Хорошие библиотеки сами превращают HTML/Markdown в текст и entities.

Способы выделения текста:

  • Жирный текст

  • Курсив

  • Подчёркнутый текст

  • Зачёркнутый текст

  • Моноширинный текст ("в строке" и "блоком")

  • Ссылка (встроенная в текст)

  • Упоминание пользователя текст, похожий на ссылку, клик по которому открывает профиль пользователя. Если упомянуть в группе её участника, он получит уведомление.
    Чтобы вставить в сообщение упоминание пользователя, в Bot API нужно встроить ссылку на tg://user?id=123456789.

О разметке в документации Bot API

Кнопки

Инлайн-кнопки

Бот может оставлять кнопки под своими сообщениями.

Кнопки под сообщениями (они же inline keyboards / inline buttons) в основном бывают трёх видов:

  • URL button кнопка с ссылкой.

  • Callback button. При нажатии на такую кнопку боту придёт апдейт. С созданием кнопки можно указать параметр, который будет указан в этом апдейте (до 64 байтов). Обычно после нажатий на такие кнопки боты изменяют исходное сообщение или показывают notification или alert.

  • Switch to inline button. Кнопка для переключения в инлайн-режим (об инлайн-режиме см. ниже). Кнопка может открывать инлайн в том же чате или открывать меню для выбора чата. Можно указать в кнопке запрос, который появится рядом с никнеймом бота при нажатии на кнопку.

Дополнительные виды кнопок
  • Login URL button специальная кнопка для авторизации пользователей на сайте. Использовалась, например, в официальном боте @discussbot (до добавления нативных комментариев в Телеграм).

  • Callback game button кнопка для открытия HTML-игры. См. пункт "HTML-игры".

  • Pay button кнопка для платежей. См. пункт "Платежи через ботов".

Клавиатурные кнопки

Есть другой тип кнопок: keyboard buttons. Они отображаются вместо клавиатуры как подсказки. При нажатии на такую кнопку пользователь просто отправит этот текст.

При этом в личных чатах с помощью кнопки можно:

  • Запросить номер телефона пользователя,

  • Запросить геолокацию пользователя,

  • Открыть у пользователя меню создания опроса.

Есть опция resize_keyboard, которая отвечает за то, изменять ли высоту этой "клавиатуры из кнопок". По умолчанию она, почему-то, выключена, и тогда высота клавиатуры стандартная большая. Получаются кнопки как на этой картинке:

Чтобы показать клавиатурные кнопки, бот должен отправить сообщение. Можно отправить клавиатуру, которая свернётся (но не пропадёт) после нажатия на кнопку.

По умолчанию, если показать кнопки в группе, они будут видны всем пользователям. Вместо этого можно отобразить кнопки одновременно для этих пользователей:

  • Для пользователей, юзернеймы которых были в тексте сообщения,

  • Если это ответ на другое сообщение: для пользователя, который его отправил.

Ещё о кнопках

Оба типа кнопок могут составлять несколько рядов, в каждом из которых по несколько кнопок.

При отправке сообщения можно выбрать одно (но не больше) из следующих действий:

  • Добавить к сообщению инлайн-кнопки,

  • Показать клавиатурные кнопки,

  • Убрать все клавиатурные кнопки,

  • Force reply: автоматически заставить пользователя ответить на сообщение. Так произойдёт то же самое, что и при нажатии пользователем кнопки "Ответить". Это нужно для того, чтобы бот мог общаться с пользователями в группах, не нарушая Privacy mode.

Таким образом, нельзя показать оба типа кнопок одновременно.

Взаимодействие с ботом

Ссылки на бота

Юзернеймы ботов работают так же, как и любые другие юзернеймы в Телеграме: бота @examplebot можно открыть по ссылке t.me/examplebot.

Также существует прямая ссылка: tg://resolve?domain=examplebot

Подробнее о ссылках tg://

Такие ссылки могут не только заменять ссылки t.me, но и задавать свои действия. Например, tg://settings открывает настройки.

Список известных таких ссылок есть канале @DeepLink.

Ссылка на добавление в группу

По ссылке t.me/examplebot?startgroup=true у пользователя откроется меню: выбор группы для добавления бота.

Прямая ссылка: tg://resolve?domain=examplebot&startgroup=true

Диплинки

По ссылке t.me/examplebot?start=<ваш текст> пользователь может запустить бота с каким-то стартовым параметром (<ваш текст>).

Как это выглядит:

  1. При переходе по ссылке бот открывается как обычно.

  2. Отображается кнопка "Запустить", даже если пользователь уже запускал бота.

  3. Пользователь нажимает на кнопку и видит сообщение /start (всё как обычно).

  4. Боту вместо этого приходит сообщение /start <ваш текст>

Так бот может отреагировать на запуск не как на обычный "/start", а другим способом.

Часто диплинки используются для реферальных программ (в качестве параметра можно передавать id пользователя, который поделился ссылкой). Есть и другие применения.

Прямая ссылка: tg://resolve?domain=examplebot&start=<ваш текст>

О диплинках в документации Bot API

Инлайн-режим

Инлайн-режим (inline mode) это специальный режим работы бота, с помощью которого пользователь может использовать бота во всех чатах.

Выглядит это так: пользователь вводит юзернейм бота в поле для ввода сообщения. После юзернейма можно ещё записать запрос (текст до 256 символов).

Появляется менюшка с результатами. Выбирая результат, пользователь отправляет сообщение.

Инлайн-режим можно включить в BotFather, там же можно выбрать плейсхолдер вместо стандартного "Search..."

В группе можно запретить использовать инлайн всем или некоторым участникам. В официальных приложениях Телеграм это ограничение объединено с ограничением на отправку стикеров и GIF.

Страничка об инлайн-режиме на сайте Telegram

Результаты инлайн-режима

Результаты можно отображать двумя способами:

  • Сеткой. Удобно для выдачи картинок.

  • Вертикальным списком. Удобно для выдачи текста.

Можно совмещать два типа, но корректно отображается это только на Telegram Desktop.

Приватность и геопозиция в инлайне

Когда пользователь вызывает инлайн-режим, бот не может получить никакую информацию о контексте, кроме id пользователя. Таким образом, бот не может узнать ни чат, в котором вызвали инлайн, ни сообщение, на которое пользователь отвечает, ни даже имя самого пользователя.

Но зато если включить в BotFather настройку "Inline Location Data", то бот сможет видеть геопозицию пользователей, когда они используют инлайн (на мобильных устройствах). Перед этим у пользователей показывается предупреждение.

Inline feedback

Inline feedback это апдейты о выбранных инлайн-результатах. Включаются через BotFather.

Предполагается использование inline feedback для сбора статистики, но не всегда он используется так. Inline feedback позволяет "подгружать" не все результаты сразу, а только выбранный. Например, если бот используется для поиска музыки, то он может загружать не все песни сразу, а только одну.

Важный момент: если вы получили апдейт об отправке инлайн-сообщения, то вы можете его редактировать, только если к нему прикреплены инлайн-кнопки. (Если кнопок нет, то в апдейте не указывается id инлайн-сообщения, по которому происходит редактирование).

Создание наборов стикеров

Боты (и только боты!) могут создавать наборы стикеров. При этом каждый набор стикеров должен принадлежать какому-то пользователю. Посмотреть свои наборы стикеров пользователь может с помощью бота @Stickers.

Платежи через ботов

Телеграм предоставляет ботам возможность принимать платежи от пользователей. Это делается через провайдеров ЮMoney, Сбербанк, Stripe и ещё 7.

Эта возможность используются редко, потому что для использования провайдеров нужно юридическое лицо.

Платежи, к тому же, не работают на iOS из-за ограничений Apple.

Страница Bot Payments API

HTML-игры в ботах

Боты могут позволять пользователям играть в HTML5-игры в чатах. Бот может отправлять сообщения-игры или создавать их через инлайн-режим. Как это работает, можно посмотреть на примере официального @gamebot.

Страница Bot Gaming Platform

Telegram Login Widget

Вы можете добавить на свой сайт авторизацию через Телеграм. Процесс авторизации будет проходить так:

  1. Пользователь должен будет ввести свой номер телефона.

  2. Бот Telegram попросит подтвердить вход.

  3. Пользователь авторизуется и нажимает на "Принять" на сайте.

Telegram Login Widget не связан с Login URL button (см. раздел про кнопки выше), а является его альтернативой.

О Telegram Login Widget на сайте Телеграм

Разработка ботов

Какие апдейты можно получать

Бот не может получить старые сообщения из чата. Бот не может получить список всех своих пользователей. Все, что может получать бот это информацию об обновлениях. В этом заключается главная сложность разработки ботов.

Вы можете получать информацию о новых сообщениях в боте и других событиях, но только один раз. Вам придётся самим хранить список чатов, старых сообщений (если это зачем-то нужно) и так далее. Если вы случайно сотрёте/потеряете эту информацию, вы её больше никак не получите.

В Telegram API бот может чуточку больше: он может получать сообщения по id, получать список участников группы и прочее.

Получение апдейтов: Bot API vs Telegram API

Если вы получили апдейт в Bot API, то второй раз вы его уже не получите.

В Telegram API это не так: пользователь может пользоваться мессенджером через несколько клиентов, каждый из которых должен получать апдейты.

Если запустить для одного бота несколько программ на Telegram API, то каждая из них будет получать все апдейты.

Ограничения Bot API не позволяют сделать то же самое.

Лимиты

Конечно, на запросы к серверу существуют лимиты. В Bots FAQ на сайте Telegram названы следующие:

  • Не больше одного сообщения в секунду в один чат,

  • Не больше 30 сообщений в секунду вообще,

  • Не больше 20 сообщений в минуту в одну группу.

Эти лимиты не строгие, а примерные. Лимиты могут быть увеличены для больших ботов через поддержку.

Другие известные ограничения в Telegram собраны на limits.tginfo.me см. раздел про ботов.

Рассылка по пользователям

Ниже в Bots FAQ сказано, что Bot API не позволяет рассылать сообщения всем юзерам одновременно и что в будущем, может быть, они что-то для этого сделают. И написано это уже несколько лет.

Они советуют растянуть рассылку на длительное время (8-12 часов) и замечают, что API не позволит отправлять сообщения более чем ~30 пользователям в секунду.

Смена владельца бота

Осенью 2020 года появилась возможность передавать ботов другому человеку. Это можно сделать в настройках бота в BotFather. Для этого на вашем аккаунте должна быть включена двухфакторная авторизация не менее, чем за 7 дней до передачи. Передать бота можно только пользователю, который что-либо ему писал.

Локальный сервер Bot API

Также осенью 2020 года исходники Bot API выложили на GitHub. Теперь вы можете поднять собственный сервер Bot API. На GitHub перечислены следующие преимущества:

  • Скачивание файлов с сервера без ограничения (ограничение на отправку файлов пользователями в Телеграме 2 ГБ),

  • Загрузка файлов на сервер до 2000 МБ,

  • Загрузка файлов на сервер с помощью локального пути и URI файла,

  • Использование HTTP URL для вебхука,

  • Использование любого локального IP-адреса для вебхука,

  • Использование любого порта для вебхука,

  • Возможность увеличить максимальное число соединений до 100000,

  • Получение локального пути файла вместо загрузки файла с сервера.

Юзерботы

В начале статьи я рассказывал о том, что такое Telegram API и Telegram Bot API.

Telegram API используется не только для ботов тогда в чём проблема управлять аккаунтами пользователей, как ботами? Люди это делают. Кто-то автоматически ставит текущее время себе на аватарку, кто-то скриптом реагирует на свои сообщения как на команды, кто-то сохраняет сообщения из публичных групп и каналов. Всё это называют юзерботами.

Юзерботов следует использовать аккуратно: за большую подозрительную активность аккаунт могут ограничить или забанить.

Заключение

Я постарался собрать в одном месте и структурировать информацию о всех возможностях Телеграм-ботов. Большое спасибо vanutp, NToneE и Grinrill за помощь с фактами. Если мы что-то забыли пишите, исправлю.

Я специально не разделял большую статью на несколько постов, чтобы можно было быстро найти нужную информацию. К тому же, в начале статьи есть её содержание. Так что можете сохранить её к себе и использовать как справочник :)

Вообще интерфейс бота (то есть интерфейс чата) имеет много ограничений. Но плохо ли это? Действительно удобнее использовать инструмент, когда это часть привычной среды. Я часто прямо в переписке нахожу нужную картинку или информацию с помощью инлайн-ботов. Как заядлый пользователь Телеграма, я люблю использовать ботов. И создаю ботов. И вы создавайте.

Подробнее..

Как я потратил 322 тысячи рублей на продвижение своего Telegram-канала о технологиях и бизнесе

30.04.2021 18:12:21 | Автор: admin

Осенью 2019 года я поспорил со своим другом, что смогу собрать больше подписчиков в Telegram, чем он. Чтобы не отставать, я потратил 322 786 рублей на контент и продвижение моего канала Репродуктор Белоусова, где я пишу о бизнесе и технологиях.

Пари закончилось предсказуемо. Давайте я расскажу, как провел эти пару месяцев и какие выводы сделал для себя. Анализ моих ошибок будет полезен, если вы задумываетесь запустить свой Telegram-канал.

Несколько слов о себе. Меня зовут Николай Белоусов. В 2013 году я основал Madrobots, один из первых магазинов гаджетов в России. В моем портфолио успешно запущенные бренды Биван и Zavtra. Моя команда привела на российский рынок стартапы Picooc и Chipolo, компанию XD Design.

До запуска канала я много писал в Фейсбуке, на Хабре, на vc. Так что у меня не было сомнений, что и Telegram мне покорится. Тем более, что мне понятен текстовый формат контента. В нем я разбираюсь лучше, чем в видео или фото.

With the little help from my friends

  • Потрачено: 62 000 рублей на создание контента и оплату работы редактора

  • Подписчиков: около 1 тысячи

Одной самоуверенности мало, поэтому я подошел к продвижению методично, как маркетолог. Для начала составил контент-план и подумал, откуда брать стартовую аудиторию. Рассуждал я так: подписчики придут ко мне от друзей и окружения. С этим мне повезло, многие мои знакомые ведут Telegram-каналы:

Первым делом я и написал всем людям из списка и договорился о том, чтобы они прорекламировали мой канал. Все согласились, за что им спасибо. Александр Горный попросил в обмен на упоминание в Стартапах дня написать статью. Так появился текст, которым я по сей день горжусь: Где брать деньги на бизнес. Недавно я обновил его с учетом реалий 2021 года.

Прирост аудитории, как и ожидалось, был устойчивым, но небольшим. Вот результаты после размещений рекламы в разных каналах по данным сервиса telemetr.me:

Киба у аппарата: +97
Торшина и На нашей фабричке: +474
Радиорубка Лихачёва: +46
The Edinorog: +251
Стартап дня: +224

Тысяча читателей, собравшаяся послушать меня с нуля, показалась мне многообещающим началом. Взяв хороший старт, я решил не останавливаться и продолжил продвигать канал уже в менее дружелюбных сферах. Это не было правильным решением.

Хождение по ботам

Потрачено: 260 тысяч рублей

Подписчиков: около 4 тысяч

Когда размещения у знакомых исчерпали свой ресурс, я стал присматриваться к нескольким другим источникам аудитории. Для начала я удачно договорился о продвижении в блогах Groks и Мастриды.

Мастриды: +11
Groks: +162

Оттуда пришли десятки людей, не больше, чем я набирал органически. Мне хотелось быстрее и больше нарастить аудиторию, потому что время шло, а пари хотелось выиграть. Поэтому я решил покупать подписчиков массово и случайно связался с ботоводами.

Размещения у ботоводов. Пример 1: +79
Размещения у ботоводов. Пример 2: +260

От них приходила масса читателей, но всё это были боты, мертвые души. Одного ботовода я вывел на чистую воду довольно быстро, но уже после того, как оплатил его услуги.

Отзыв об авторе проекта PR_Hawks, предлагающего подписчиков массово

Следующим логичным шагом было продвижение через лидеров мнений. Я сразу пошел ва-банк и потратил 100 000 рублей на упоминание в канале Артемия Лебедева, теша себя надеждой, что сейчас придут подписчики. Результаты красноречивы:

Эффективность размещения в суперссылке Лебедева 1: +61
Эффективность размещения в суперссылке Лебедева 2: +131

Первый блин комом. Неудача с Лебедевым меня не подкосила. Я решил разместиться у Лены Миро, с которой давно и плодотворно сотрудничаю. Обошлось мне это по дружбе в 40 000 рублей.

Эффективность размещения у Лены Миро: +442

От Миро пришло почти 400 человек, что было уже достойным результатом на фоне остальных размещений.

Это интернет, детка

Парадоксальным образом больше всего подписчиков принес пост моего друга, со спора с которым и начался мой Telegram-канал.

Этот скриншот я приберег напоследок.

Эффективность размещения в канале Продакты не нужны: +718

После одного упоминания в канале @Продакты не нужны на меня подписалось почти 700 человек. Но это не спасло меня, в конце декабря 2019 года я понял, что спор проигран и я ничего не могу поделать. Быстро достучаться до массовой аудитории не получается, как бы я не пытался продвигать себя.

Как именно я потратил 322 786 рублей? Львиную долю я потратил именно на продвижение, эффект от которого был гомеопатическим. Прикладываю разбивку расходов:

Расходы на Telegram-канал@ni404headРасходы на Telegram-канал@ni404head

Разочаровавшись, я почти на год забросил канал. Максимума число подписчиков достигло 06 января 2020 года, а дальше аудитория пошла на спад. Сейчас у меня около пяти тысяч подписчиков и я стал писать снова, пытаясь нарастить аудиторию органически, не пытаясь кого-то обогнать.

Я пишу о профильных темах: гаджетах, новых технологиях, бизнес-трендах, выкладываю конспекты деловых книг и регулярно публикую опросы для читателей. Получается неплохо.

Динамика числа подписчиковДинамика числа подписчиков

Какие выводы можно сделать из моей истории?

  1. Платное продвижение канала в Telegram обходится дорого. Подписчик может стоить сотню рублей.

  2. В ТГ много ботоводов, которые под видом живой аудитории подсовывают ботов.

  3. Продвижение через лидеров мнений неоправданно дорого по сравнению с аудиторией, которую они приводят.

  4. Единственный работающий метод продвижения взаимный пиар дружественных каналов через обмен контентом. Заниматься этим нужно системно, то есть инвестировать много времени в процесс.

Возможно, у вас есть опыт относительно дешевого продвижения канала? Буду признателен за советы и здравую критику.

Если вам понравилась эта колонка, подпишитесь на мой канал @Репродуктор Белоусова.

Подробнее..

Прыжок до небес запускаем телеграм бота на Python в serverless облаке

16.04.2021 00:22:45 | Автор: admin

Одним из современных архитектурных подходов в области облачных вычислений является так называемый Serverless. Этот способ запуска приложений в облаке освобождает разработчиков от нужды администрировать сервер и заботиться о чем-то, кроме кода.

Очевидно, что для такой задачи, как телеграм бот, этот подход очень удобен.

В этой статье описаны все шаги для запуска бота в Yandex.Cloud Functions. Опоры на код я не делаю. Наша основная задача сейчас - настроить запуск в облаке.

Создадим бота

Чтобы создать телеграмм бота, нужно воспользоваться @BotFather. Для этого используйте команду /new_bot. Скопируйте токен (он будет там, где оранжевая полоса)

Настройка Yandex.Cloud

Для работы с Яндекс.Облаком перейдите на сайт https://cloud.yandex.ru/ и войдите в свой аккаунт. Если вы все сделали правильно, вы увидите рабочий дашборд.

Cloud Functions

  • Перейдите в раздел Cloud Functions

  • Создайте новую функцию c названием, например, python-tg-bot.

  • Укажите язык python и выберите самую последнюю версию (python3.8 на момент написания этой статьи).

  • В настройках функции загрузите код бота. Скачать архив можно по ссылке. Параметры укажите как на картинке. В переменные окружения добавьте поле BOT_TOKEN и вставьте токен, полученный в самом начале. После обязательно нажмите Создать версию, чтобы запустить функцию.

  • Запомним идентификатор функции (первая строка)

API-Gateway

Чтобы мы смогли получить доступ к нашей функции, нужно настроить API-Gateway.

  • Перейдите в раздел API-Gateway

  • Создайте новый шлюз и настройте его.Скопируйте конфигурацию и замените YOUR_FUNCTION_ID на идентификатор функции, полученный ранее.

openapi: 3.0.0info:title: for-python-tg-botversion: 1.0.0paths:/:post:x-yc-apigateway-integration:type: cloud-functionsfunction_id: YOUR_FUNCTION_IDoperationId: tg-webhook-function
  • Запомним ссылку, по которой можно вызвать нашу функцию

Устанавливаем webhook

Теперь нужно сообщить телеграму, куда отправлять информацию о новых сообщениях.

Для этого:

  • Установите библиотеку pip install pyTelegramBotAPI

  • Запустите питоновский скрипт:

import telebotbot = telebot.TeleBot("YOUR_TOKEN")bot.remove_webhook()bot.set_webhook("YOUR_URL")

Тестируем

Сделали "эхо-бота". Что дальше?

Как говорилось в начале, такой способ запустить бота очень легок для разработчика, но что же делать, если нам нужна база данных или сложные api-запросы к другим ресурсам. Все это можно реализовать в Yandex.Cloud. Например, с помощью сервисов Yandex Database (тоже serverless) или Object Storage. Отдельные сервисы можно запустить, как отдельные функции. В следующей статье, я расскажу о том, как подключить базу данных Yandex Database к боту.

Именно возможность создавать все по кусочкам и уверенность в том, что однажды настроенный модуль будет работать всегда, отличает serverless подход от простого "давайте свалим все в одну виртуальную машину".

Тарифы Yandex.Cloud

До октября 2021 года на сервисы экосистемы бессерверных вычислений будут действовать специальные тарифы. В рамках этих тарифов определенный объем услуг не будет тарифицироваться. Объем рассчитан так, чтобы у вас была возможность разработать и запустить небольшой сервис, сайт или приложение.

  • Yandex API Gateway

    Каждый месяц не тарифицируются первые 100 000 запросов к API-шлюзам.

  • Yandex Cloud Functions

    Каждый месяц не тарифицируются:

    • первые 1 000 000 вызовов функций;

      \nu = \frac{10^6}{30 * 24 * 60} \approx 23 \text{ } \frac{\text{запроса}}{\text{час}}

    • первые 10 ГБчас выполнения функций.

  • Бессерверный режим Yandex Database

    Каждый месяц не тарифицируются:

    • первые 1 000 000 операций (в единицах RU);

    • первый 1 ГБ/месяц хранения данных.

Полезные ссылки

  1. Репозиторий с кодом бота

  2. Yandex.Cloud

  3. Описание тарифа free tier

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru