Истории успеха наших клиентов — лучшие проекты
Вход/ Регистрация

Как создать Telegram-бота на Node.js

2816
15 минут чтения
Средний рейтинг статьи: 5

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

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

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

  • Базовый функционал:

    • Ответы на команды.
    • Инлайн-боты.
    • Кнопки.
  • Интеграции с внешними сервисами:

    • API и базы данных.
    • Webhook.
  • Уведомления:

    • Рассылка уведомлений по расписанию, или при наступлении определённых событий.
    • Автоматическая отправка новостей из источников через каждые N секунд.
  • Аналитика:

    • Сборка различной статистики.

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

Сперва нужно создать бота внутри Telegram. Воспользуйтесь официальным ботом BotFather, чтобы зарегистрировать бота. Используйте кнопку «Запустить» (а если вы уже пользовались ботом, то отправьте команду /start), в ответе бота найдите и выберите команду /newbot. BotFather предложит указать имя бота, а затем его username. При этом нужно, чтобы в конце было слово bot. Например, если у вашего бота название Tetris, то username должен быть таким:

  • TetrisBot
  • Tetris_bot
  • Tetrisbot
  • Tetris_Bot

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

Image9

Разработка

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

Перед началом разработки нужно, чтобы на вашем ПК были установлены Node.js и npm. Скачать Node.js можно с официального сайта, а npm установится автоматически вместе с Node.js. Если же вы используете Linux, то установить npm можно, воспользовавшись инструкцией.

Если Node.js установлен, можно приступать к разработке бота. Сперва создайте на GitHub новый приватный репозиторий и в пункте Add .gitignore выберите Node

Image11

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

    
cd Desktop

Затем введите:

    
git clone https://github.com/Tulopex/School-Quiz

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

Далее, после клонирования, не закрывая консоль, введите:

    
cd School-Quiz

Вместо School-Quiz используйте реальное название папки вашего проекта, которая клонировалась с GitHub.

Для инициализации проекта выполните команду:

    
npm init

Вам предложат ввести имя пакета, версию, описание, главный файл по умолчанию, тест команду, Git репозиторий, ключевые слова, автора и лицензию. Вы можете оставить значения по умолчанию, нажимая «Enter».

Image6

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

    
npm install node-telegram-bot-api

После завершения процесса установки можно приступать к написанию кода. Откройте файл package.json и найдите строку scripts, внутрь неё над командой test, введите:

    
"start": "node index.js",

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

Теперь создайте файле index.js и внутри него напишите следующее:

    
const TelegramBot = require('node-telegram-bot-api'); const fs = require('fs'); const bot = new TelegramBot('TOKEN', { polling: true }); // Вместо слова TOKEN, укажите реальный токен вашего бота, который выдал вам BotFather const ADMIN_ID = '1402655980'; let awaitingSupportMessage = {}; // Хранение информации о пользователях, ожидающих поддержки // Хранение выбранных тем для пользователей let userTopics = {}; // Темы и файлы с вопросами const topics = { math: { name: 'Математика', file: 'questions/math.json' }, english: { name: 'Английский', file: 'questions/english.json' }, history: { name: 'История', file: 'questions/history.json' } }; // Функция для получения вопросов по выбранным темам function getQuestionsByTopics(userId) { const selectedTopics = userTopics[userId] || Object.keys(topics); let allQuestions = []; selectedTopics.forEach(topic => { const questions = JSON.parse(fs.readFileSync(topics[topic].file, 'utf8')); allQuestions = allQuestions.concat(questions); }); return allQuestions; } function getRandomQuestion(userId) { const questions = getQuestionsByTopics(userId); const randomIndex = Math.floor(Math.random() * questions.length); return questions[randomIndex]; } bot.onText(/\/quiz/, (msg) => { const chatId = msg.chat.id; const userId = msg.from.id; // Получаем случайный вопрос const questionData = getRandomQuestion(userId); // Отправляем опрос в виде викторины bot.sendPoll( chatId, questionData.question, // Вопрос questionData.options, // Варианты ответов { type: 'quiz', // Тип викторины correct_option_id: questionData.correct_option_id, // Правильный ответ is_anonymous: false // Вопрос не будет анонимным } ).then(pollMessage => { // Обрабатываем результаты опроса bot.on('poll_answer', (answer) => { if (answer.poll_id === pollMessage.poll.id) { const selectedOption = answer.option_ids[0]; // Проверяем, правильный ли ответ if (selectedOption !== questionData.correct_option_id) { bot.sendMessage(chatId, questionData.explanation); } } }); }); }); bot.onText(/\/settopic/, (msg) => { const chatId = msg.chat.id; const userId = msg.from.id; const keyboard = Object.keys(topics).map(topicKey => ({ text: `${(userTopics[userId] || []).includes(topicKey) ? '✅ ' : ''}${topics[topicKey].name}`, callback_data: topicKey })); bot.sendMessage(chatId, 'Выберите темы для вопросов:', { reply_markup: { inline_keyboard: [keyboard] } }); }); // Обработчик выбора тем bot.on('callback_query', (callbackQuery) => { const message = callbackQuery.message; const userId = callbackQuery.from.id; const topicKey = callbackQuery.data; // Инициализируем выбранные темы для пользователя, если их нет if (!userTopics[userId]) { userTopics[userId] = Object.keys(topics); } // Добавляем или удаляем тему if (userTopics[userId].includes(topicKey)) { userTopics[userId] = userTopics[userId].filter(t => t !== topicKey); } else { userTopics[userId].push(topicKey); } // Обновляем сообщение с кнопками const keyboard = Object.keys(topics).map(topicKey => ({ text: `${userTopics[userId].includes(topicKey) ? '✅ ' : ''}${topics[topicKey].name}`, callback_data: topicKey })); bot.editMessageReplyMarkup({ inline_keyboard: [keyboard] }, { chat_id: message.chat.id, message_id: message.message_id }); }); bot.onText(/\/start/, (msg) => { const chatId = msg.chat.id; bot.sendMessage(chatId, "Привет! Напиши /quiz, чтобы начать викторину. Для выбора тем используй /settopic."); }); console.log('Бот запущен.');

Теперь создайте папку внутри проекта под названием questions, а внутри этой папки нужно создать три JSON-файла:

english.json

    
[ { "question": "Как будет 'я' на английском языке?", "options": ["I", "You", "We"], "correct_option_id": 0, "explanation": "Правильный ответ: I." }, { "question": "Как переводится глагол 'run'?", "options": ["бежать", "идти", "стоять"], "correct_option_id": 0, "explanation": "Правильный ответ: бежать." }, { "question": "Как будет 'он' на английском языке?", "options": ["He", "She", "It"], "correct_option_id": 0, "explanation": "Правильный ответ: He." } ]

history.json

    
[ { "question": "В каком году началась Вторая мировая война?", "options": ["1939", "1941", "1914"], "correct_option_id": 0, "explanation": "Правильный ответ: 1939." }, { "question": "Кто был первым президентом США?", "options": ["Авраам Линкольн", "Джордж Вашингтон", "Франклин Рузвельт"], "correct_option_id": 1, "explanation": "Правильный ответ: Джордж Вашингтон." }, { "question": "Какая страна первой отправила человека в космос?", "options": ["США", "Россия", "Китай"], "correct_option_id": 1, "explanation": "Правильный ответ: Россия." } ]

math.json

    
[ { "question": "Сколько будет 2 + 2?", "options": ["3", "4", "5"], "correct_option_id": 1, "explanation": "Правильный ответ: 4." }, { "question": "Сколько будет 5 * 5?", "options": ["10", "20", "25"], "correct_option_id": 2, "explanation": "Правильный ответ: 25." }, { "question": "Сколько будет 10 / 2?", "options": ["4", "5", "6"], "correct_option_id": 1, "explanation": "Правильный ответ: 5." } ]

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

Дополнение

Недавно в Telegram добавили внутреннюю валюту Telegram Stars, а также предоставили обновление для API, с помощью которого можно добавить донат в вашем боте в Stars. Добавим команду donate внутрь файла index.js, при отправке которой бот будет присылать счёт для оплаты.

    
bot.onText(/\/donate/, (msg) => { const chatId = msg.chat.id; bot.sendInvoice(chatId, 'Донат', 'Донат на поддержку проекта', 'unique_payload', '', // Пустой provider_token для Stars Payments 'XTR', // Валюта "XTR" [{ label: 'Донат', amount: 1 }], // Сумма: 1 Stars ); });

Также добавим ещё одну команду — support. С её помощью большое количество пользователей вашего бота смогут написать обращение к вам, при этом у вас не будет множества лишних чатов с различными людьми! Пользователи смогут отправлять текст, фото и видео, а бот будет пересылать эти обращения администратору (в данном случае вам). Эту команду также расположите внутри файла index.js.

В начале файла добавьте:

    
const ADMIN_ID = 'ID'; let awaitingSupportMessage = {}; // Хранение информации о пользователях, ожидающих поддержки

Благодаря этому ID бот будет понимать, кому нужно переслать сообщение от пользователей. Чтобы узнать свой ID, можно воспользоваться ботом Get My ID, в котором достаточно отправить команду /start

Далее в конце файла добавьте:

    
bot.onText(/\/support/, (msg) => { const chatId = msg.chat.id; const userId = msg.from.id; // Сообщаем пользователю, что ожидаем его обращение bot.sendMessage(chatId, "Пожалуйста, отправьте ваше обращение в одном сообщении, включая текст, фото или видео!"); // Отмечаем, что этот пользователь сейчас пишет обращение awaitingSupportMessage[userId] = true; }); // Обработка всех сообщений bot.on('message', (msg) => { const userId = msg.from.id; // Проверяем, что пользователь отправил сообщение после команды /support if (awaitingSupportMessage[userId]) { const chatId = msg.chat.id; const caption = msg.caption || ''; // Подпись, если есть // Проверка на тип сообщения и пересылка соответствующего контента администратору if (msg.text) { // Если сообщение содержит текст bot.sendMessage(ADMIN_ID, `Новое обращение от пользователя @${msg.from.username || msg.from.first_name} (ID: ${userId}):\n\n${msg.text}`); } else if (msg.photo) { // Если сообщение содержит фото const photo = msg.photo[msg.photo.length - 1].file_id; // Берём фото с максимальным разрешением bot.sendPhoto(ADMIN_ID, photo, { caption: `Новое обращение от @${msg.from.username || msg.from.first_name} (ID: ${userId})\n\n${caption}` }); } else if (msg.video) { // Если сообщение содержит видео const video = msg.video.file_id; bot.sendVideo(ADMIN_ID, video, { caption: `Новое обращение от @${msg.from.username || msg.from.first_name} (ID: ${userId})\n\n${caption}` }); } else { // Если тип сообщения не поддерживается bot.sendMessage(msg.chat.id, "К сожалению, данный тип сообщения не поддерживается."); } // Подтверждаем пользователю, что его обращение отправлено bot.sendMessage(chatId, "Ваше обращение отправлено. Администратор свяжется с вами в ближайшее время."); // Убираем пользователя из списка тех, кто пишет обращение delete awaitingSupportMessage[userId]; } });

Развертывание на сервере

Теперь, чтобы бот мог работать на постоянной основе, необходимо загрузить и запустить его на сервере. Для развёртывания я буду использовать сервис Timeweb Cloud.

VDS и VPS

Гибкие виртуальные серверы с почасовым
биллингом по всему миру: Россия, Азия и Европа.

Загрузка на GitHub

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

Вводите эти команды в консоль последовательно.

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

    
git add .

Создаем коммит с сообщением «first commit», фиксируя все изменения, добавленные командой git add:

    
git commit -m "first commit"

Отправляем изменения на GitHub:

    
git push

Настройка сервера

Если вы ещё не являетесь клиентом Timeweb Cloud, предварительно нужно зарегистрироваться.

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

Image5

Далее, нам нужно создать облачный сервер. При создании сервера, в первом пункте перейдите во вкладку «Маркетплейс» и выберите Node.js, а версию Ubuntu поставьте самую новую. С помощью этого, когда ваш сервер начнёт работать, на нем сразу будет установлен Node.js и вам не придется устанавливать его вручную.

Screenshot 10 09 24 14:16:26

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

Image2

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

Image10

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

Image3

В авторизации и Cloud-init ничего не меняйте. В информации о сервере введите имя сервера, его описание, а также выберите проект, который мы создали ранее.

Image7

Когда всё выбрали, нажимайте на кнопку «Заказать». Через некоторое время, сервер запустится и можно продолжить работу.

Запуск бота

После создания сервера, на вкладке «дашборд», скопируйте Root-пароль для входа и перейдите на вкладку «консоль». Введите логин пользователя «root» и нажмите «Enter». Далее, вставьте пароль, который вы скопировали и также нажмите «Enter». При вставке или написании пароля, он не будет виден! Если всё правильно указали, то вас поприветствуют.

Image1

Теперь введите команду, чтобы получить последние обновления:

    
sudo apt-get update

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

    
cd / sudo mkdir Bot cd Bot

Вместо папки «Bot», вы можете создать папку с другим именем. 

Перенесем код с GitHub на наш сервер.

Чтобы удостовериться, что Git установлен на сервере (по умолчанию он всегда установлен) выполните:

    
git --version

Установим глобальные настройки Git, чтобы он был настроен на ваш профиль на GitHub:

    
git config --global user.name "ваш username на Github" git config --global user.email "email, который указан при регистрации"

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

    
git clone https://github.com/Tulopex/School-Quiz

При клонировании у вас снова попросят ввести username, а затем пароль. Если у вас установлена двухфакторная аутентификация на аккаунте, то при вводе обычного пароля, вам будет выдавать ошибку о том, что пароль неверный. Чтобы вы могли клонировать репозиторий с 2FA на аккаунте, вам нужно создать личный токен доступа.

Для создания личного токена доступа на GitHub выполните следующие шаги: 

  1. Перейдите в настройки профиля: 

Нажмите на свою аватарку в правом верхнем углу и выберите «Settings»

  1. В левом меню выберите «Developer settings».

  2. Создание нового токена: 

    1. В разделе «Personal access tokens» выберите «Tokens (classic)».
    2. Нажмите кнопку «Generate new token». 
  3. Установите параметры токена: 

    1. В поле «Note» укажите описание для токена.
    2. Установите срок действия токена в поле «Expiration». 
    3. Выберите необходимые разрешения для токена в разделе «Select scopes». Например, для работы с репозиториями выберите repo
  4. Нажмите кнопку «Generate token». 

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

Перейдите в вашу папку с проектом с помощью  команды:

    
cd School-Quiz

Вместо School-Quiz укажите название своего проекта. Чтобы установить пакеты вашего проекта, выполните команду:

    
npm install

После установки пакетов, можно запустить проект, с помощью:

    
npm start

В консоли появится сообщение «Бот запущен». Но есть одна проблема, если вы перезапустите сервер или закроете консоль, то бот перестает работать! Чтобы бот работал постоянно, а также автоматически запускался после перезагрузки, достаточно установить менеджера процессов pm2.

Установите pm2 командой:

    
sudo npm install pm2 -g

Затем запустите сервер Node.js, используя pm2:

    
sudo pm2 start index.js --name "bot-quiz" --watch

В примере используется имя «bot-quiz». Так будет называться запущенный процесс. Вы можете придумать любое другое имя.

Настройте автозапуск при запуске или перезагрузке сервера:

    
sudo pm2 startup

Сохраните все введенные изменения:

    
sudo pm2 save

Image4

Разверните свое Node.js-приложение
на VDS/VPS Timeweb Cloud

Cloud MSK 15

477 ₽/мес

Процессор
1 x 3.3 ГГц
Память
1 ГБ
NVMe
15 ГБ
Канал
1 Гбит/с
Публичный IP
Cloud MSK 30

657 ₽/мес

Процессор
1 x 3.3 ГГц
Память
2 ГБ
NVMe
30 ГБ
Канал
1 Гбит/с
Публичный IP

Заключение

В данной статье мы подробно рассмотрели процесс создания Telegram-бота на платформе Node.js, начиная с регистрации бота через BotFather и заканчивая развертыванием готового решения на сервере.

2816
15 минут чтения
Средний рейтинг статьи: 5
Хотите внести свой вклад?
Участвуйте в нашей контент-программе за
вознаграждение или запросите нужную вам инструкцию
img-server
Пока нет комментариев