IT-инфраструктура для бизнеса и творчества
Разработка
Daniil Lebedev

Telegram-бот с помощью таблицы Google

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

Оригинал данной статьи на английском: Mars Escobin: Seven Easy Steps to Create a Telegram Bot Using Webhooks

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

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

Краткое введение в веб-хуки

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

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

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

Веб-хуки как рыболовные крючки

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

Именно так работают API polling и webhooks. С помощью опроса API приложение проверяет другое приложение в каждый установленный период времени, чтобы увидеть, есть ли данные для извлечения, в то время как с помощью веб-хуков приложение просто ждёт передачи данных, которая начинается событием.

А что такое события?

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

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

Требования

Есть две вещи, которые нам нужны, чтобы создать бота с веб-хуками:

  1. Пропуск — мы не можем просто так получить доступ к данным из другого приложения. Разработчикам нужен способ отследить, кто получает доступ к их приложениям с черного хода. Для этого они выдают уникальные ключи всем, кто хочет войти в их приложения вне основного пользовательского интерфейса. Я покажу вам, как быстро получить ключ Telegram — буквально за минуту.
  2. Загрузочный док — как только у нас появится доступ к другому приложению, мы сможем начать извлекать из него данные. Но для этого нам нужен загрузочный док — место для приема этих данных. Наш док — URL веб-приложения. Приложение не может выгрузить данные, если у нас нет загрузочной платформы. С платформы же мы можем делать с данными все, что захотим: проверять их, манипулировать ими, отправить в другое приложение или даже обратно в наше приложение.

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

Теперь представьте, что кран — это веб-хук, а корабли — два разных приложения; загрузочный док — это адрес приложения. Хук извлекает данные из App 1 (корабля внизу слева) и отправляет их на URL-адрес веб-приложения. Оттуда можно отправить эти данные в App 2 (корабль вверху справа) или сделать с ними всё, что захотите. Этот контейнер теперь ваш. Открывайте, проверяйте и отправляйте!

Рождение бота

Теперь, когда у вас есть понимание, как работают веб-хуки, мы можем создать бота!

Пропуск

Во-первых, нам нужен пропуск. В некоммерческих приложениях может потребоваться запросить у разработчика напрямую, но, к счастью, есть очень простой способ получить ключи входа (или токены) авторизации в Telegram. Ключи нам даст BotFather!

  • Кликните по ссылке.
  • Поздоровайтесь с ним (надо отдать должное).
  • Отправьте придуманное вами имя бота.
  • БАМ! Токен у вас в руках! ?

Настройка таблицы Google

Как только у нас будет токен, создайте электронную таблицу Google и перейдите в меню Инструменты → Редактор сценариев. Именно здесь мы будем писать код.

Строим загрузочный док

Нам нужен URL приложения, чтобы получать данные из Telegram. К счастью, у Google очень простая публикация веб-приложений через редактор сценариев. Когда мы опубликуем скрипт, то получим уникальный адрес веб-приложения. Нажимайте Publish в редакторе скриптов Google Spreadsheet.

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

И теперь у нас есть адрес веб-приложения! ?

Сохраните все ссылки в переменных

Теперь, когда у нас есть пропуск и загрузочный док, давайте создадим веб-хук — наш крючок. Согласно документации Telegram API, все запросы к API (App Programming Interface) должны быть такими: https://api.telegram.org/bot<token>/METHOD_NAME. Похоже, нам будет очень часто нужна эта ссылка. Давайте сохраним все нужные ссылки в переменных, чтобы мы могли легко писать их позже:

var token = "1379225052:AAHXeY6p816laT1nrVLU-qX3ufMXcymqyoM"; var telegramUrl = "https://api.telegram.org/bot" + token; var webAppUrl = "https://script.google.com/macros/s/AKfycbyGlsL9W7VG413SHoJ6LSNxs_uW8ZtbLY7h0hk9oOruxmZlizg/exec"; var token = "1379225052:AAHXeY6p816laT1nrVLU-qX3ufMXcymqyoM"; var telegramUrl = "https://api.telegram.org/bot" + token; var webAppUrl = "https://script.google.com/macros/s/AKfycbyGlsL9W7VG413SHoJ6LSNxs_uW8ZtbLY7h0hk9oOruxmZlizg/exec";

Настройка веб-хука

Чтобы настроить хук, давайте напишем функцию, которая позволит нам извлекать данные из Telegram с помощью токена от Botfather. Эти данные должны быть отправлены непосредственно на адрес нашего веб-приложения. Вы можете скопировать и вставить код ниже и нажать кнопку «Опубликовать», когда закончите.

function setWebhook() { var url = telegramUrl + "/setWebhook?url=" + webAppUrl; var response = UrlFetchApp.fetch(url); }

Когда вы публикуете (или развёртываете) свой код, вам могут предложить авторизовать свое собственное приложение для доступа к вашим данным в Google:

Авторизуйте приложение: жизнь слишком коротка, чтобы прожить её в безопасности:

Настройка обмена сообщениями

Есть две вещи, которые наш бот должен знать, прежде чем сможет отправить кому-то сообщение:

  • Кому сообщение? Идентификатор чата.
  • Что напишем? Текст сообщения.

Запишем эти требования как параметры функции. Не стесняйтесь копировать и вставлять код:

function sendMessage(chat_id, text) { var url = telegramUrl + "/sendMessage?chat_id=" + chat_id + "&text="+ text; var response = UrlFetchApp.fetch(url); Logger.log(response.getContentText()); }

Настройка запроса POST

По словам разработчиков Telegram, все запросы к API должны идти по HTTPS. Они также упомянули, что поддерживают только запросы GET и POST. GET означает, что кто-то пытается получить данные. POST означает, что кто-то пытается их отправить. Это единственная концепция в учебнике, которую я ещё не освоила, поэтому я перестану притворяться, что знаю, о чем говорю, и просто покажу вам эту статью, которая помогла мне лучше понять принцип.

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

function doPost(e) { var contents = JSON.parse(e.postData.contents); var chat_id = contents.message.from.id; var text = "Beep boop bop, message received."; sendMessage(chat_id,text) }

Нам нужна эта функция, потому что она — наш способ отправки данных в Telegram и сам Google требует, чтобы его пользователи сценариев приложений — то есть мы — включали либо функцию doGet, либо doPost, когда публикуем веб-приложение. Вот документация об этом. В этом документе Google объясняет, что означает аргумент (e) в функции. Он представляет собой данные из события, созданного человеком внутри приложения, к которому подключен наш веб-хук. В нашем случае аргумент e содержит все данные, генерируемые всякий раз, когда человек отправляет сообщение Telegram-боту. И именно в аргументе мы получим идентификатор чата пользователя. В конце концов, все предыдущие бредни оправдались ? (может быть).

Итак, вот история нашего бота:

  • Когда пользователь общается с нашим ботом Telegram, происходит событие. Оно генерирует данные, получаемые нами из e.
  • Веб-хук автоматически отправляет e на URL-адрес веб-приложения.
  • Как только e попадёт в URL-адрес веб-приложения, оно захочет отправить запрос POST в Telegram. Он запросит Telegram об отправке сообщения пользователю.
  • Однако он не может отправить запрос с неполными требованиями. Нам нужен идентификатор чата человека и сообщение, которое мы хотим отправить в Telegram. Функция doPost переносит сообщение внутри переменной text.
  • doPost также обрабатывает идентификатор chat, но сначала ей нужно проанализировать e, чтобы найти его.
  • После обнаружения она передаёт параметры в Telegram с помощью функции sendMessage. Всё: сообщение передаётся пользователю. Запрос завершен. И вот — работающий бот:

На случай, если ты запутался…

Весь код:

var token = "1379225052:AAHXeY6p816laT1nrVLU-qX3ufMXcymqyoM"; var telegramUrl = "https://api.telegram.org/bot" + token; var webAppUrl = "https://script.google.com/macros/s/AKfycbyGlsL9W7VG413SHoJ6LSNxs_uW8ZtbLY7h0hk9oOruxmZlizg/exec"; function setWebhook() { var url = telegramUrl + "/setWebhook?url=" + webAppUrl; var response = UrlFetchApp.fetch(url); } function sendMessage(chat_id, text) { var url = telegramUrl + "/sendMessage?chat_id=" + chat_id + "&text="+ text; var response = UrlFetchApp.fetch(url); Logger.log(response.getContentText()); } function doPost(e) { var contents = JSON.parse(e.postData.contents); var chat_id = contents.message.from.id; var text = "Beep boop bop, message received."; sendMessage(chat_id,text) }
(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ { name: 'camera', url: `${cdnUrl}CameraCat`, text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', link: 'https://vc.ru/selectel/306690', num: 3 }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', num: 1 }, { name: 'cloud', url: `${cdnUrl}CloudCat`, text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', link: 'https://vc.ru/dev/294799-maneki-neko', num: 2 } ] let buttonCycle = document.querySelector('.button--cycle') let buttonChoose = document.querySelector('.button--choose') let buttonMobile = document.querySelector('.button--mobile') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) buttonChoose.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) buttonMobile.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { sendEvent(`Promo ${articles[currentArticleNumber].num} Right`, 'Click') if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?3' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } const sendEvent = (label, action = 'Click') => { const value = `SelectelDIY — loc: Footer — ${label} — ${action}`; if (window.dataLayer !== undefined) { window.dataLayer.push({ event: 'data_event', data_description: value, }); } }; function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите научим?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg?3`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
23 комментария
Популярные
По порядку
Написать комментарий...

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

11

Меня это совершенно не напрягло, после прочтения статьи захотел подписаться. 

0

Хочется принимать решение о том, читать статью или не читать по аннотации. Заголовок не всегда раскрывает суть. А в аннотации байт на подписку на канал. Кто мешает его в конец статьи поставить? Или хотя бы не в аннотационную часть?

1

не пойти бы тебе в ж...пу

–2

Нагибайся, мудень, коли приглашаешь

–1

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

4

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

1

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

2

Я думаю, за этот перевод даже денег заплатили:
" я ещё не освоила".

2

Автор оригинала — девушка. Или Вас что-то другое смущает.

1

Гугл о таком точно не знает, значит переводили руками. Смущает то, что перевод (не мне одному) всё равно кажется как из Гугла.

0

Гугл не знает слово «освоила»? Гм.

–1

В первом лице английского языка нет женского пола.

0

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

2

Есть сайт Bots.business. С помощью него можно развернуть бота на базе любой таблицы Google. Достаточно просто опубликовать ссылку на эту таблицу и скормить её приложению.

Команды и ответы прописываются в колонке. Можно добавить и логику на базе Javascript.

1

Что-то смотрю на "весь код" и не пойму, когда функция setWebhook вызывается?

1

руками один раз. Это как раз хорошо понятно на видео от 2017 года.

0

Для создания собственного Telegram-бота потребуется минимум программирования.

Верю.

–2

Сделал все как в статье, но так бот и не работает, ничего не отвечает.

0

Токен уникальный...получили своего?

0

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

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

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

0

Редактор скриптов в гугл таблицах не открывается. Кто-нибудь знает ак с этим быть?

0
Читать все 23 комментария
Мвидео отказал в замене товара ненадлежащего качества. Битый телевизор

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

Путин поручил разработать вариант налогового вычета для частных инвесторов при долгосрочных вложениях в российские акции Статьи редакции

Фондовый рынок должен не только финансировать инвестиционные проекты, но и приносить доход гражданам, считает президент.

Мвидео, облажались. Дважды

1. Мультиварка

Это Элви Рэй Смит: он мечтал создать анимационный фильм на компьютере, соосновал Pixar, но ушёл из компании из-за Джобса Статьи редакции

Смит создал альфа-канал, который используется в Photoshop и других редакторах, работал в Xerox и LucasFilm и убеждал всех, что за компьютерной графикой будущее, однако всерьез его никто не воспринимал – кроме Стива Джобса.

«Мегафон» заблокировал 36 тыс. ₽ на 2 недели по ФЗ № 115

Являюсь абонентом Мегафона второй десяток лет. Несколько лет назад завёл себе карту Мегафон-банка. Очень нравилось, и рекомендовал всем, так как:

Kornia - Python библиотека для обработки изображений в задачах CV

В этой статье я хотел бы познакомить читателей с библиотекой для ЯП python — Kornia, имеющей богатый функционал в области computer vision. Библиотека написана с использованием pytorch, в ее основе лежат готовые решения, такие как torchvision, PIL, skimage, tf.image, OpenCV. В Kornia реализована возможность выполнения вычислений не только с…

Минэкономразвития РФ приняло предложения РСПП по совершенствованию рынка интеллектуальной собственности

На актуализации плана дорожной карты ТДК (трансформация делового климата) «Интеллектуальная собственность» в соответствии с пожеланиями бизнес-сообщества настоял первый заместитель председателя правительства Андрей Белоусов.

Эксперимент: оформляем банковские карты без бумажных документов

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

На сайтах с эквайрингом от ПСБ появился Yandex Pay

Покупатели с аккаунтом «Яндекса» смогут оплачивать покупки, не вводя данные карты.

null