Перейти к содержимому

Как залить бота на heroku

  • автор:

Создание и хостинг телеграм бота. От А до Я

Привет, хабрчане! Какой бы заезженной не была тема создания телеграм бота на python3, я не нашёл инструкций, где показан путь от первой строчки кода до деплоинга бота (по крайней мере все методы, что я видел, немного устарели). В этой статье я хочу показать процесс создания бота от написания BotFather-у до деплоинга бота на Heroku.

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

P.S. Пишите если нужна статья по созданию более сложного бота, т.е. с вебхуками, БД с настройками юзеров и т.д.

Содержание

  1. BotFather.
  2. Установка и настройка pipenv. Первый запуск.
  3. Хэндлеры. Отвечаем на команды и сообщения.
    • Основы взаимодействия. Ответ на команды.
    • Основы взаимодействия. Ответ на текстовые сообщения.
    • Основы взаимодействия. Ответ на картинки, документы, аудио и прочие.
    • Строим цепочку ответов.
    • Добавляем парсер в цепочку.
    • Теория. Методы взаимодействия с ботом.
  4. Маркапы. Добавляем клавиатуры для быстрого ответа.
  5. Деплоим бота на Heroku.
  6. Ссылки.
  7. Заключение.

Для начала стоит определиться, что же будет делать наш бот. Я решил написать банального простого бота, кторый будет парсить и выдавать нам заголовки с Хабра.
И так, начнём же.

BotFather

Для начала нам надо зарегистрировать нашего бота в Telegram. Для этого:

В поиске вбиваем @BotFather и переходим в диалог с Отцом Ботов.

Пишем /newbot. Указываем имя бота (то, что отображается в диалогах). Указываем его логин, по которому его можно булет найти.

P.S. Оно должно заканчиваться на Bot/bot

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

Дальше добавим ему пару команд: пропишем /setcommands и одним сообщением, т.к. /setcommands не добавляет команды, а задаёт их с нуля, пошлём ему команды.

all — спарсить заголовки с вкладки «ВСЁ ПОДРЯД»
top — спарсить заголовки с вкладки «ЛУЧШЕЕ»

На этом работа с BotFather закончилась, перейдём к следующей части.

Установка и настройка pipenv. Первый запуск.

Для начала создадим файл, в котором будет основной код бота bot.py. Если бот большой, то сразу создавайте файлы, куда вы вынесете функции, классы и т.д, иначе читаемость кода стремится к нулю. Я добавлю parser.py

Установим pipenv, если его конечно ещё нет.

pip install pipenv
sudo pip3 install pipenv

Установим pipenv в папку проекта.

pipenv install

Установим интересующие нас библиотеки. Я буду работать с PyTelegramBotAPI. Также для парсинга добавим BeautifulSoup4.

pipenv install PyTelegramBotAPI pipenv install beautifulsoup4 

Начинаем писать код!

Открываем bot.py, импортируем библиотеки и создаём главные переменные.

import telebot import parser #main variables TOKEN = "555555555:AAAAaaaAaaA1a1aA1AAAAAAaaAAaa4AA" bot = telebot.TeleBot(TOKEN) 

Запустим бота. Посмотри наличие ошибок.

Как запустить?

python bot.py
python3 bot.py

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

Хэндлеры. Отвечаем на команды и сообщения

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

Основы взаимодействия. Ответ на команды

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

Начнём с самого простого: ответим на команды /start и /go

@bot.message_handler(commands=['start', 'go']) def start_handler(message): bot.send_message(message.chat.id, 'Привет, когда я вырасту, я буду парсить заголовки с Хабра') bot.polling()

Сейчас разберёмся что это и как это работает. Передаём в message_handler параметр commands равный массиву со строками — командами, на которые он будет отвечать описанным ниже образом. (На все эти команды он ответит одинаково). Далее используем send_message, в него записываем id чата (его можно достать из message.chat.id), в который отправить сообщение и, собственно, само сообщение. Нельзя забыть написать bot.polling() в конце кода, иначе бот сразу же выключиться. Почему так мы узнаем позже.

Теперь можно запустить бота и написать ему /start или /go и он ответит.

P.S. Сообщение может быть не только строкой, а, в принципе, чем угодно.

P.S.S. Что за message?

Это json объект, хранящий информацию об отправителе, чате, и самом сообщении.

< 'content_type': 'text', 'message_id': 5, 'from_user': < 'id': 333960329, 'first_name': 'Nybkox', 'username': 'nybkox', 'last_name': None >, 'date': 1520186598, 'chat': < 'type': 'private', 'last_name': None, 'first_name': 'Nybkox', 'username': 'nybkox', 'id': 333960329, 'title': None, 'all_members_are_administrators': None >, 'forward_from_chat': None, 'forward_from': None, 'forward_date': None, 'reply_to_message': None, 'edit_date': None, 'text': '/start', 'entities': [], 'audio': None, 'document': None, 'photo': None, 'sticker': None, 'video': None, 'voice': None, 'caption': None, 'contact': None, 'location': None, 'venue': None, 'new_chat_member': None, 'left_chat_member': None, 'new_chat_title': None, 'new_chat_photo': None, 'delete_chat_photo': None, 'group_chat_created': None, 'supergroup_chat_created': None, 'channel_chat_created': None, 'migrate_to_chat_id': None, 'migrate_from_chat_id': None, 'pinned_message': None >
Основы взаимодействия. Ответ на текстовые сообщения.

Теперь обработаем текстовые сообщения бота. Самое важное что нам нужно знать это то, что текст сообщения храниться в message.text и то, что, чтобы обрабатывать текст в message_handler нужно передавать content_types=[‘text’].

Добавим вот такой код.

@bot.message_handler(content_types=['text']) def text_handler(message): text = message.text.lower() chat_id = message.chat.id if text == "привет": bot.send_message(chat_id, 'Привет, я бот - парсер хабра.') elif text == "как дела?": bot.send_message(chat_id, 'Хорошо, а у тебя?') else: bot.send_message(chat_id, 'Простите, я вам не понял :(')

Тут мы довабили пару переменных: вынесли текст сообщения (в нижнем регистре, чтобы не было лишних проблем с теми кто пишет капсом, заборчиком и т.д.) в переменную text, вынесли message.chat.id в отдельную переменную, чтобы каждый раз не обращаться к message. Также мы построили небольшое ветвление, для ответа на определённые сообщения, а также ответ на случай непонятного боту сообщения.

Итоговый код

import bs4 import parser #main variables TOKEN = "555555555:AAAAaaaAaaA1a1aA1AAAAAAaaAAaa4AA" bot = telebot.TeleBot(TOKEN) #handlers @bot.message_handler(commands=['start', 'go']) def start_handler(message): bot.send_message(message.chat.id, 'Привет, когда я вырасту, я буду парсить заголовки с хабра') @bot.message_handler(content_types=['text']) def text_handler(message): text = message.text.lower() chat_id = message.chat.id if text == "привет": bot.send_message(chat_id, 'Привет, я бот - парсер хабра.') elif text == "как дела?": bot.send_message(chat_id, 'Хорошо, а у тебя?') else: bot.send_message(chat_id, 'Простите, я вас не понял :(') bot.polling() 
Основы взаимодействия. Ответ на картинки, документы, аудио и прочие.

Для ответа на картинки, стикеры, документы, аудио и т.д. нужно всего лишь поменять content_types=[‘text’].

Рассмотрим пример с картинкой, добавив этот код.

@bot.message_handler(content_types=['photo']) def text_handler(message): chat_id = message.chat.id bot.send_message(chat_id, 'Красиво.') 

Все типы контента:

text, audio, document, photo, sticker, video, video_note, voice, location, contact, new_chat_members, left_chat_member, new_chat_title, new_chat_photo, delete_chat_photo, group_chat_created, supergroup_chat_created, channel_chat_created, migrate_to_chat_id, migrate_from_chat_id, pinned_message

Строим цепочку ответов.

Пришло время закончить с элементарными действиями и начать что-то серьёзное. Попробуем построить цепочку ответов. Для этого нам понадобиться register_next_step_handler(). Создадим простой пример, на котором и разберёмся как работает register_next_step_handler().

@bot.message_handler(commands=['start', 'go']) def start_handler(message): chat_id = message.chat.id text = message.text msg = bot.send_message(chat_id, 'Сколько вам лет?') bot.register_next_step_handler(msg, askAge) def askAge(message): chat_id = message.chat.id text = message.text if not text.isdigit(): msg = bot.send_message(chat_id, 'Возраст должен быть числом, введите ещё раз.') bot.register_next_step_handler(msg, askAge) #askSource return msg = bot.send_message(chat_id, 'Спасибо, я запомнил что вам ' + text + ' лет.')

И так, в первой функции добавился bot.register_next_step_handler(msg, askAge), в него мы передаём сообщение, которые хотим послать, и следующий щаг, к которому перейти после ответа пользователя.

Во второй функции всё поинтересней, здесь идёт проверка ввёл ли пользователь число, и, если нет, то функция рекурсивно вызывает сама себя, с сообщением «Возраст должен быть числом, введите ещё раз.». Если пользователь ввёл всё верно, то он получает ответ.

Но, есть тут проблема. Можно повторно вызвать команду /go или /start, и начнётся бардак.

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

@bot.message_handler(commands=['start', 'go']) def start_handler(message): global isRunning if not isRunning: chat_id = message.chat.id text = message.text msg = bot.send_message(chat_id, 'Сколько вам лет?') bot.register_next_step_handler(msg, askAge) #askSource isRunning = True def askAge(message): chat_id = message.chat.id text = message.text if not text.isdigit(): msg = bot.send_message(chat_id, 'Возраст должен быть числом, введите ещё раз.') bot.register_next_step_handler(msg, askAge) #askSource return msg = bot.send_message(chat_id, 'Спасибо, я запомнил что вам ' + text + ' лет.') isRunning = False

С построением простых цепочек мы разобрались, пойдём дальше.

Добавляем парсер в цепочку.

Для начала нужен сам парсер. Обратим внимание на то, что во вкладках «Лучшее» и «Всё подряд» есть дополнительные фильтры: сутки, неделя, месяц и ≥10, ≥25, ≥50, ≥100 соответственно.
Парсер конечно можно написать и в 1 функцию, но я разобью на 2, так будет проще читать код.

Парсер.

import urllib.request from bs4 import BeautifulSoup def getTitlesFromAll(amount, rating='all'): output = '' for i in range(1, amount+1): try: if rating == 'all': html = urllib.request.urlopen('https://habrahabr.ru/all/page'+ str(i) +'/').read() else: html = urllib.request.urlopen('https://habrahabr.ru/all/'+ rating +'/page'+ str(i) +'/').read() except urllib.error.HTTPError: print('Error 404 Not Found') break soup = BeautifulSoup(html, 'html.parser') title = soup.find_all('a', class_ = 'post__title_link') for i in title: i = i.get_text() output += ('- "'+i+'",\n') return output def getTitlesFromTop(amount, age='daily'): output = '' for i in range(1, amount+1): try: html = urllib.request.urlopen('https://habrahabr.ru/top/'+ age +'/page'+ str(i) +'/').read() except urllib.error.HTTPError: print('Error 404 Not Found') break soup = BeautifulSoup(html, 'html.parser') title = soup.find_all('a', class_ = 'post__title_link') for i in title: i = i.get_text() output += ('- "'+i+'",\n') return output

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

import telebot import bs4 from Task import Task import parser #main variables TOKEN = '509706011:AAF7ghlYpqS5n7uF8kN0VGDCaaHnxfZxofg' bot = telebot.TeleBot(TOKEN) task = Task() #handlers @bot.message_handler(commands=['start', 'go']) def start_handler(message): if not task.isRunning: chat_id = message.chat.id msg = bot.send_message(chat_id, 'Откуда парсить?') bot.register_next_step_handler(msg, askSource) task.isRunning = True def askSource(message): chat_id = message.chat.id text = message.text.lower() if text in task.names[0]: task.mySource = 'top' msg = bot.send_message(chat_id, 'За какой временной промежуток?') bot.register_next_step_handler(msg, askAge) elif text in task.names[1]: task.mySource = 'all' msg = bot.send_message(chat_id, 'Какой минимальный порог рейтинга?') bot.register_next_step_handler(msg, askRating) else: msg = bot.send_message(chat_id, 'Такого раздела нет. Введите раздел корректно.') bot.register_next_step_handler(msg, askSource) return def askAge(message): chat_id = message.chat.id text = message.text.lower() filters = task.filters[0] if text not in filters: msg = bot.send_message(chat_id, 'Такого временного промежутка нет. Введите порог корректно.') bot.register_next_step_handler(msg, askAge) return task.myFilter = task.filters_code_names[0][filters.index(text)] msg = bot.send_message(chat_id, 'Сколько страниц парсить?') bot.register_next_step_handler(msg, askAmount) def askRating(message): chat_id = message.chat.id text = message.text.lower() filters = task.filters[1] if text not in filters: msg = bot.send_message(chat_id, 'Такого порога нет. Введите порог корректно.') bot.register_next_step_handler(msg, askRating) return task.myFilter = task.filters_code_names[1][filters.index(text)] msg = bot.send_message(chat_id, 'Сколько страниц парсить?') bot.register_next_step_handler(msg, askAmount) def askAmount(message): chat_id = message.chat.id text = message.text.lower() if not text.isdigit(): msg = bot.send_message(chat_id, 'Количество страниц должно быть числом. Введите корректно.') bot.register_next_step_handler(msg, askAmount) return if int(text) < 1 or int(text) >11: msg = bot.send_message(chat_id, 'Количество страниц должно быть >0 и 

Тут добавился none_stop=True) к bot.polling , из-за этого бот не будет падать при каждой ошибке.
Task.py

class Task(): isRunning = False names = [ ['лучшие', 'лучшее', 'топ'], ['всё', 'всё подряд', 'all'] ] filters = [ ['сутки', 'неделя', 'месяц'], ['без порога', '10', '25', '50', '100'] ] filters_code_names = [ ['daily', 'weekly', 'monthly'], ['all', 'top10', 'top25', 'top50', 'top100'] ] mySource = '' myFilter = '' def __init__(self): return 

parser.py

import urllib.request from bs4 import BeautifulSoup def getTitlesFromAll(amount, rating='all'): output = '' for i in range(1, amount+1): try: if rating == 'all': html = urllib.request.urlopen('https://habrahabr.ru/all/page'+ str(i) +'/').read() else: html = urllib.request.urlopen('https://habrahabr.ru/all/'+ rating +'/page'+ str(i) +'/').read() except urllib.error.HTTPError: print('Error 404 Not Found') break soup = BeautifulSoup(html, 'html.parser') title = soup.find_all('a', class_ = 'post__title_link') for i in title: i = i.get_text() output += ('- "'+i+'",\n') return output def getTitlesFromTop(amount, age='daily'): output = '' for i in range(1, amount+1): try: html = urllib.request.urlopen('https://habrahabr.ru/top/'+ age +'/page'+ str(i) +'/').read() except urllib.error.HTTPError: print('Error 404 Not Found') break soup = BeautifulSoup(html, 'html.parser') title = soup.find_all('a', class_ = 'post__title_link') for i in title: i = i.get_text() output += ('- "'+i+'",\n') return output
Теория. Методы взаимодействия с ботом.

Мы используем long polling для получения данных о сообщениях от бота.

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

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

Маркапы. Добавляем клавиатуры для быстрого ответа.

Наконец основной код дописан. Теперь можно передохнуть и написать маркапы. Я думаю вы неоднократно видели их, но всё же, приложу скриншот. [SCREENSHOT]

Я выведу маркапы в отдельный файл — markups.py.

В написании маркапов нет ничего сложного. Нужно лишь создать маркап, указать пару параметров, создать пару кнопок и добавить их в маркап, далее просто указываем reply_markup=markup в send_message .

Пример

from telebot import types source_markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) source_markup_btn1 = types.KeyboardButton('Лучшие') source_markup_btn2 = types.KeyboardButton('Всё подряд') source_markup.add(source_markup_btn1, source_markup_btn2) 

В параметры маркапа указываем ширину строки и изменение размеров кнопок, иначе они огромны.

Можно конечно заполнять отдельно каждую строк.

markup = types.ReplyKeyboardMarkup() itembtna = types.KeyboardButton('a') itembtnv = types.KeyboardButton('v') itembtnc = types.KeyboardButton('c') itembtnd = types.KeyboardButton('d') itembtne = types.KeyboardButton('e') markup.row(itembtna, itembtnv) markup.row(itembtnc, itembtnd, itembtne)
def start_handler(message): if not task.isRunning: chat_id = message.chat.id msg = bot.send_message(chat_id, 'Откуда парсить?', reply_markup=m.source_markup) bot.register_next_step_handler(msg, askSource) task.isRunning = True

Применим полученные знания к нашему боту.

Итоговый код

from telebot import types start_markup = types.ReplyKeyboardMarkup(row_width=1, resize_keyboard=True) start_markup_btn1 = types.KeyboardButton('/start') start_markup.add(start_markup_btn1) source_markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) source_markup_btn1 = types.KeyboardButton('Лучшие') source_markup_btn2 = types.KeyboardButton('Всё подряд') source_markup.add(source_markup_btn1, source_markup_btn2) age_markup = types.ReplyKeyboardMarkup(row_width=3, resize_keyboard=True) age_markup_btn1 = types.KeyboardButton('Сутки') age_markup_btn2 = types.KeyboardButton('неделя') age_markup_btn3 = types.KeyboardButton('Месяц') age_markup.add(age_markup_btn1, age_markup_btn2, age_markup_btn3) rating_markup = types.ReplyKeyboardMarkup(row_width=3, resize_keyboard=True) rating_markup_btn1 = types.KeyboardButton('Без порога') rating_markup_btn2 = types.KeyboardButton('10') rating_markup_btn3 = types.KeyboardButton('25') rating_markup_btn4 = types.KeyboardButton('50') rating_markup_btn5 = types.KeyboardButton('100') rating_markup.row(rating_markup_btn1, rating_markup_btn2) rating_markup.row(rating_markup_btn3, rating_markup_btn4, rating_markup_btn5) amount_markup = types.ReplyKeyboardMarkup(row_width=3, resize_keyboard=True) amount_markup_btn1 = types.KeyboardButton('1') amount_markup_btn2 = types.KeyboardButton('3') amount_markup_btn3 = types.KeyboardButton('5') amount_markup.add(amount_markup_btn1, amount_markup_btn2, amount_markup_btn3)
import telebot import bs4 from Task import Task import parser import markups as m #main variables TOKEN = '509706011:AAF7aaaaaaaaaaaaaaaaaaaAAAaaAAaAaAAAaa' bot = telebot.TeleBot(TOKEN) task = Task() #handlers @bot.message_handler(commands=['start', 'go']) def start_handler(message): if not task.isRunning: chat_id = message.chat.id msg = bot.send_message(chat_id, 'Откуда парсить?', reply_markup=m.source_markup) bot.register_next_step_handler(msg, askSource) task.isRunning = True def askSource(message): chat_id = message.chat.id text = message.text.lower() if text in task.names[0]: task.mySource = 'top' msg = bot.send_message(chat_id, 'За какой временной промежуток?', reply_markup=m.age_markup) bot.register_next_step_handler(msg, askAge) elif text in task.names[1]: task.mySource = 'all' msg = bot.send_message(chat_id, 'Какой минимальный порог рейтинга?', reply_markup=m.rating_markup) bot.register_next_step_handler(msg, askRating) else: msg = bot.send_message(chat_id, 'Такого раздела нет. Введите раздел корректно.') bot.register_next_step_handler(msg, askSource) return def askAge(message): chat_id = message.chat.id text = message.text.lower() filters = task.filters[0] if text not in filters: msg = bot.send_message(chat_id, 'Такого временного промежутка нет. Введите порог корректно.') bot.register_next_step_handler(msg, askAge) return task.myFilter = task.filters_code_names[0][filters.index(text)] msg = bot.send_message(chat_id, 'Сколько страниц парсить?', reply_markup=m.amount_markup) bot.register_next_step_handler(msg, askAmount) def askRating(message): chat_id = message.chat.id text = message.text.lower() filters = task.filters[1] if text not in filters: msg = bot.send_message(chat_id, 'Такого порога нет. Введите порог корректно.') bot.register_next_step_handler(msg, askRating) return task.myFilter = task.filters_code_names[1][filters.index(text)] msg = bot.send_message(chat_id, 'Сколько страниц парсить?', reply_markup=m.amount_markup) bot.register_next_step_handler(msg, askAmount) def askAmount(message): chat_id = message.chat.id text = message.text.lower() if not text.isdigit(): msg = bot.send_message(chat_id, 'Количество страниц должно быть числом. Введите корректно.') bot.register_next_step_handler(msg, askAmount) return if int(text) < 1 or int(text) >5: msg = bot.send_message(chat_id, 'Количество страниц должно быть >0 и 

Ура! С кодом впринципе разобрались. Теперь самое важное — деплоинг бота не хероку.

Деплоим бота на Heroku.

Для начала надо зарегистрироваться на Хероку и на Гитхабе.

Теперь создаём репозиторий на гитхабе. (нажмите плюсик слева от вашего аватара)
Сейчас нам нужен Procfile (Procfile.windows для windows). Создаём его и записываем в него bot: python3 bot.py

Теперь удаляем TOKEN из bot.py, здесь он не нужен, ведь мы будем загружать этот файл на гитхаб. Через тот же терминале, что использовали для запуска бота, заливаем файлы на гитхаб. (Предворительно удалите папку __pycache__).

echo "# HabrParser_Bot" >> README.md git init git add . git add * git commit -m "Initial Commit" -a git remote add origin origin https://github.com/name/botname.git #Указываем свою ссылку git push -u origin master 

Гит просит логин и пароль, спокойно вводим и преступаем к деплоингу бота на хероку. Пишем всё в том же терминале.

Теперь возвращаем TOKEN в bot.py, здесь он нужен, ведь мы будем загружать этот файл на хероку.

heroku login #Вводим email и пароль heroku create --region eu habrparserbot #Не забываемпоменять имя приложения #P.S. в имени могут быть только буквы в нижнем регитсре, цифры и тире. heroku addons:create heroku-redis:hobby-dev -a habrparserbot #И снова меняем имя! heroku buildpacks:set heroku/python git push heroku master heroku ps:scale bot=1 # запускаем бота heroku logs --tail #включаем логи 

Чтобы выключить бота

heroku ps:stop bot

И, не забываем перед залитием на гитхаб и удалить TOKEN из нашего bot.py. Ведь нам не нужно, чтобы кто-то им пользовался. Можно конечно воспользоваться .gitignore и вынести токены в отдельный фай.

Поздравляю!

Работа окончена, бот работает удалённо.

Ссылки

Заключение

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

UPDATES

UPD1
  • Добавлены якори в содержание.
  • Изменён алгоритм залития кода на гитхаб и хероку.
  • Убрана версия PyTelegramBotAPI, т.к. теперь хероку работает нормально с новыми версиями.

Деплой бота на сервере Heroku

Может кто--нибудь дать инструкцию, как развернуть бота на сервере heroku (написанном на python )? Спасибо заранее.

Отслеживать

5,746 3 3 золотых знака 22 22 серебряных знака 44 44 бронзовых знака

задан 22 окт 2018 в 8:00

518 1 1 золотой знак 6 6 серебряных знаков 19 19 бронзовых знаков

Официальную документацию читали? devcenter.heroku.com/articles/getting-started-with-python

22 окт 2018 в 8:17

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

  • Первым делом создайте Git репозиторий в папке с ботом: git init
  • Войдите в аккаунт Heroku : heroku login
  • Создайте приложение: heroku create appname --region eu
  • Создайте файл Procfile с содержимым: bot: python main.py
    • Если бот на веб-хуках, замените bot на web . Но на бесплатном тарифе, бот будет засыпать каждые 30 минут если не будет подключений, по этому на Heroku free лучше держать ботов на лонг-поллинге. Но проблема с засыпанием веб приложения решается с помощью http://kaffeine.herokuapp.com/.
    • Теперь наша папка выглядит приблизительно так: Procfile main.py requirements.txt

    Отслеживать

    ответ дан 22 окт 2018 в 8:14

    Pavel Durmanov Pavel Durmanov

    5,746 3 3 золотых знака 22 22 серебряных знака 44 44 бронзовых знака

    22 окт 2018 в 8:50

    @Midnight Вы в Procfile точно bot указали?

    22 окт 2018 в 8:54

    Нет, у меня там web написано

    22 окт 2018 в 8:55

    @Midnight А нужно bot

    22 окт 2018 в 8:56

    Не подскажете почему на серваке вываливается ошибка? 2018-10-23T15:06:30.166700+00:00 app[bot.1]: File "/app/.heroku/python/lib/pytho n3.6/site-packages/aiogram/utils/exceptions.py", line 116, in detect 2018-10-23T15:06:30.166702+00:00 app[bot.1]: raise err(cls.text or description) 2018-10-23T15:06:30.166712+00:00 app[bot.1]: aiogram.utils.exceptions.Terminated ByOtherGetUpdates: Conflict: terminated by other getupdates request; make sure t hat only one bot instance is running

    Как разместить телеграм бота на heroku?

    есть где-нибудь в сети пошаговая(на сколько это вообще возможно) инструкция по деплою telegram бота на python на heroku? если кто-то разъяснит лично было бы совсем прекрасно. допустим у меня папка с файлом bot.py, что дальше-то?

    • Вопрос задан более трёх лет назад
    • 23642 просмотра

    Комментировать
    Решения вопроса 0
    Ответы на вопрос 2

    ptrvch

    вебдев-энтузиаст. Django, AngularJS

    Создайте в корневом каталоге файл Procfile, в нем введите следующее:
    worker: python bot.py
    Потом в командной строке в рабочем каталоге включите worker:
    heroku ps:scale worker=1

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

    Ответ написан более трёх лет назад
    Комментировать
    Нравится 5 Комментировать

    Вот есть неплохая инструкция: Развертывание Python бота для ВКонтакте на Heroku
    Для телеграма принцип такой же.

    Ответ написан более трёх лет назад
    Нравится 3 1 комментарий
    MajorTom69 @MajorTom69 Автор вопроса
    спасибо большое, я искал что-то типа такого, сегодня же опробую
    Ваш ответ на вопрос

    Войдите, чтобы написать ответ

    python

    • Python
    • +1 ещё

    Как заставить селениум просто открыть страницу и ждать?

    • 1 подписчик
    • 19 минут назад
    • 45 просмотров

    Как разместить Telegram-бота на сервере?

    Уже не первый раз меня спрашивали о том, как разместить своего бота на сервере и запустить его. В этой статье, я постараюсь коротко и ясно объяснить об этом. Но делать я это буду на бесплатном хостинге — Heroku.

    1. Создание бота
    2. Размещение бота на сервере Heroku
    3. Запуск бота на сервере Heroku
    4. Размещение бота на своём сервере
    5. Запуск бота на своём сервере

    Я разбил статью на 5 глав. Как я сказал ранее, статья будет короткой. И с помощью этой навигации будет проще ориентироваться по требуемой информации.

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

    Статью о том, как написать своего Telegram-бота на NodeJS я уже писал. Думаю я объяснил там всё достаточно понятно. Изучить её, если у вас еще нету бота и вы хотите его разработать на NodeJS. Если вы написали своего бота не на JavaScript, то можете пропускать эту часть и приступать ко второй главе.

    Размещение бота на Heroku

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

    Особой разницы в размещении бота на Heroku или на отдельном сервере нету. Тут всё достаточно просто.

    1. Зарегистрируйтесь на сайте Heroku
    1. Войдите в свой аккаунт и создайте первый проект, нажав на "Create new app".
    1. Придумайте название своему проекту. Название должно быть уникальным. Выбор региона не принципиален.
    2. После создания проекта, вам будет предложены варианты деплоя (размещения) вашего проекта на Heroku.

    Тут есть несколько вариантов. Я опишу только первые два.

    • Heroku Git — с помощью CLI от Heroku, вы можете очень просто разместить своего бота на сервере Heroku.
    • GitHub — вы можете подключить свой аккаунт GitHub и склонировать ваш репозиторий на сервер Heroku.

    Я буду пользоваться первым вариантом.

    Следуя простой инструкции, указанной в разделе "Deploy", можно загрузить свой проект на сервер Heroku.

    1. Скачайте Heroku CLI для работы с Herokue сервером.
    2. Войдите в аккаунт Heroku через CLI.

    heroku login

    1. Зайдите в папку вашего проекта через консоль (терминал).

    cd my-telegram-bot

    1. И выполните эти две команды по очереди. (Если вы уже инициализировали Git, то первую команду выполнять не надо).

    heroku git:remote -a archakov-im-telegram-bot

    Первая — инициализирует Git в вашей папке. Вторая — установит ссылку на репозиторий Heroku, для деплоя (размещения) вашего проекта на сервере.

    Когда внесли все правки и убедились, что всё должно работать нормально, создайте в папке с вашим проектом — Procfile. Без расширения, просто - Procfile.

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

    web: node index.js

    В моем случае, это npm start . Так как у меня код написан на ES6, мне нужно конвертировать ES6 в ES5 с помощью Babel. И только после этого, у меня запускается команда запуска бота, типа: node index.js .

    Запуск бота на сервере Heroku

    Почти готово. Вам осталось теперь просто запушить вашего бота на сервер Heroku и запустить бота.

    git commit -m \"init\"
    git push heroku master

    Если вам лень каждый раз вбивать эти команды, пропишите в package.json в scripts, следующую команду:

    \"deploy\": \"git add . && git commit -m \'fix\' && git push heroku master\"

    Если же бот не запустился после пуша, выполните последнюю команду для запуска бота на Heroku и готово!

    heroku ps:scale web=1

    Размещение бота на своём сервере

    Тут тоже достаточно всё просто. Если вы не хотите публиковать своего бота на GitHub'e, вы можете использовать BitBucket.

    Регестрируемся. Создаем репозиторий, нажав на плюсик слева.

    Называем репозиторий как хотим, тут всё так же, как и на GitHub.

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

    cd my-telegram-bot
    git remote add origin git@bitbucket.org:Archakov06/archakov-im-telegram-bot.git

    У вас должна быть другая ссылка на репозиторий. Кликните на "I have an existing project" и ниже указана команда с вашим репозиторием.

    Пушим всё на BitBucket репозиторий. На своём сервере клонируем репозиторий с BitBucket и любые изменения просто скачиваем командой:

    git pull origin master

    Запуск бота на своём сервере

    После того как вы склонировали репозиторий и установили все зависимости на вашем сервере, вам остается запустить бота в фоновом режиме — Запуск Node.js в фоновом режиме.

    nohup nodejs index.js > /dev/null 2>&1 &
    ps aux | grep node

    Или же есть еще два варианта запуск бота:

    1. Nodemon — следит за любыми изменениями в файле и перезапускает бота (скрипт).
    2. Docker — более сложный, но грамотный вариант для запуска бота. При правильной настройке Docker-контейнера, можно поставить автоматически запуск при фейле бота.

    Если у вас бот не запустился, проверьте логи, командой heroku logs .

    Если вы рассчитываете на халяву от Heroku и ожидаете, что ваш бот будет хоститься на их сервере, то мне придётся вас огорчить. Ваш бот будет работать 30 секунд, после чего отключается. Переодично включается, когда как. В общем, Heroku подходит для теста бота в «боевом режиме».

    Это уже 6 или 7 статья по разработке телеграм ботов. Думаю, мой блог скоро превратится в "блог о программировании телеграм ботов". Что самое странное, я написал больше 55 статей про разные темы, но 90% запросов из поисковых систем, связаны с телеграм ботами. Тем не менее приложу к этой статье несколько своих статей по Telegram.

    • NodeJS: Делаем кнопки в Telegram API (inline-keyboards)
    • Полезные чаты Telegram для веб-разработчиков
    • Node.JS: Делаем своего Telegram бота
    Archakov Dennis

    Fullstack Developer (ReactJS, NodeJS) / UI Designer.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *