Telegram чат-боты на Python с библиотекой pyTelegramBotAPI: от начального уровня до продвинутых решений
Введение в создание Telegram ботов на Python с pyTelegramBotAPI
Библиотека pyTelegramBotAPI (часто называется telebot) представляет собой удобный инструмент для взаимодействия с Telegram Bot API. Она позволяет быстро настроить обработку команд, сообщений, клавиатур и многих других возможностей. Рассматриваются различные подходы к реализации ботов: от простого эхо до многошаговых диалогов с сохранением состояния.
Основное решение: простой эхо-бот
Наиболее эффективный способ начать работу - создать бота, который повторяет сообщения пользователя. Это позволяет убедиться, что токен и окружение настроены верно.
Установка библиотеки выполняется через pip:
pip install pyTelegramBotAPIбиблиотека aiogram python (библиотека aiogram для telegram ботов)
После получения токена от BotFather создается файл bot.py со следующим содержимым:
import telebot
TOKEN = 'ВАШ_ТОКЕН_ЗДЕСЬ'
bot = telebot.TeleBot(TOKEN)
@bot.message_handler(func=lambda message: True)
def echo_all(message):
bot.reply_to(message, message.text)
if __name__ == '__main__':
bot.polling(none_stop=True)Python telegram bot (создание telegram бота на python)
Код импортирует библиотеку, инициализирует бота с токеном, регистрирует обработчик всех текстовых сообщений (lambda возвращает True) и запускает бесконечный опрос сервера. Флаг none_stop позволяет автоматически переподключаться при временных сбоях.
Типичные ошибки:
- Токен недействителен - бот не запускается. Решение: проверить токен в BotFather, убедиться, что он скопирован без лишних пробелов.
- Конфликт вебхука и polling - бот не отвечает. Решение: удалить вебхук командой
bot.remove_webhook()перед polling. - Ошибка сети - бот падает с исключением. Решение: использовать try-except и retry-механизмы, либо увеличить таймауты.
Вариант 1: Обработка команд и клавиатура
Как сделать, чтобы бот реагировал на команды и показывал кнопки?
Используются декораторы @bot.message_handler(commands=['start']) для команд и класс types.ReplyKeyboardMarkup для клавиатуры.
import telebot
from telebot import types
bot = telebot.TeleBot('TOKEN')
@bot.message_handler(commands=['start'])
def send_welcome(message):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)
btn1 = types.KeyboardButton('Привет')
btn2 = types.KeyboardButton('Помощь')
markup.add(btn1, btn2)
bot.send_message(message.chat.id, 'Выберите опцию:', reply_markup=markup)
@bot.message_handler(func=lambda message: message.text == 'Привет')
def say_hello(message):
bot.reply_to(message, 'Здравствуйте!')
bot.polling()
Py telegram python (telegram боты на python (pytelegrambotapi))
Декоратор commands=['start'] срабатывает только при команде /start. Клавиатура создаётся с кнопками, resize_keyboard подгоняет размер кнопок под текст. Обработчик текста 'Привет' реагирует на соответствующее нажатие.
Проблема: бот не отвечает на кнопки, если они скрыты или сообщение не совпадает точно. Решение: проверять пробелы, регистр, использовать фильтр func=lambda message: message.text in ['Привет', 'Помощь'].
Случаи использования:
- Приветственное меню при старте.
- Быстрые ответы на частые вопросы.
Вариант 2: Inline-кнопки и callback
Как реализовать интерактивные кнопки с обратной связью?
Inline-кнопки прикрепляются к сообщению и отправляют callback-запросы при нажатии.
import telebot
from telebot import types
bot = telebot.TeleBot('TOKEN')
@bot.message_handler(commands=['inline'])
def send_inline(message):
markup = types.InlineKeyboardMarkup()
btn = types.InlineKeyboardButton('Нажми меня', callback_data='press')
markup.add(btn)
bot.send_message(message.chat.id, 'Пример инлайн-кнопки:', reply_markup=markup)
@bot.callback_query_handler(func=lambda call: True)
def callback_inline(call):
if call.data == 'press':
bot.answer_callback_query(call.id, text='Кнопка нажата!')
bot.edit_message_text('Вы нажали кнопку', chat_id=call.message.chat.id, message_id=call.message.message_id)
bot.polling()Aiogram python боты (боты на aiogram python)
Кнопка создаётся с параметром callback_data, который передаётся в обработчик callback_query_handler. После нажатия можно показать уведомление и изменить текст сообщения.
Ошибка: callback не обрабатывается, если не зарегистрирован хендлер. Проверить, что декоратор стоит до bot.polling(). Типичная ошибка - забыть вызвать answer_callback_query, из-за чего кнопка может висеть в состоянии загрузки.
Случаи использования:
- Опросы, голосования.
- Меню с пагинацией.
- Подтверждение действий.
Вариант 3: Отправка и получение медиа
Как бот может отправлять и получать изображения?
Для отправки файлов используются методы send_photo, send_document и подобные. Для приёма - обработчики с фильтром content_types=['photo'].
import telebot
from telebot import types
bot = telebot.TeleBot('TOKEN')
@bot.message_handler(commands=['photo'])
def send_photo(message):
with open('cat.jpg', 'rb') as f:
bot.send_photo(message.chat.id, f, caption='Вот кот')
@bot.message_handler(content_types=['photo'])
def handle_photo(message):
file_id = message.photo[-1].file_id
file_info = bot.get_file(file_id)
downloaded_file = bot.download_file(file_info.file_path)
with open('received.jpg', 'wb') as f:
f.write(downloaded_file)
bot.reply_to(message, 'Фото сохранено')
bot.polling()Python bot main py (основной файл бота python)
При отправке фото указывается файл или file_id. При получении message.photo - список объектов разного размера; берётся последний (наибольшее разрешение). Метод get_file получает путь к файлу на сервере Telegram, download_file загружает его.
Проблема: при отправке больших файлов может быть превышен лимит (50 МБ). Решение: использовать сжатие или разбивать на части. При сохранении нужно проверять права на запись в директорию.
Случаи использования:
- Боты-галереи, мемодрочеры.
- Загрузка аватарок или документов пользователей.
Вариант 4: Конечные автоматы (FSM) для многошаговых диалогов
Как создать бота с последовательными вопросами и сбором данных?
Библиотека telebot не имеет встроенной FSM, но можно использовать сторонние обёртки, например, telebot-calendar или реализовать простую машину состояний вручную через хранение состояний в словаре.
import telebot
from telebot import types
bot = telebot.TeleBot('TOKEN')
user_state = {} # словарь: chat_id -> состояние
@bot.message_handler(commands=['register'])
def start_register(message):
user_state[message.chat.id] = 'ask_name'
bot.send_message(message.chat.id, 'Введите ваше имя:')
@bot.message_handler(func=lambda m: user_state.get(m.chat.id) == 'ask_name')
def get_name(message):
name = message.text
user_state[message.chat.id] = 'ask_age'
bot.send_message(message.chat.id, f'Приятно познакомиться, {name}! Теперь сколько вам лет?')
@bot.message_handler(func=lambda m: user_state.get(m.chat.id) == 'ask_age')
def get_age(message):
age = message.text
del user_state[message.chat.id]
bot.send_message(message.chat.id, f'Вы зарегистрированы: имя {message.text}, возраст {age}')
bot.polling()библиотеки python telegram bot (библиотеки python для telegram ботов)
Состояние хранится в глобальном словаре. Обработчики проверяют текущее состояние пользователя. После завершения состояние удаляется.
Ошибка: при перезапуске бота состояния теряются. Для продакшена лучше использовать хранилище, например, Redis. Типичная проблема - пользователь может отправить неожиданное сообщение; нужно добавить обработчик по умолчанию с предложением начать заново.
Случаи использования:
- Регистрация пользователей с анкетой.
- Заказ товаров с выбором параметров.
Вариант 5: Вебхуки вместо polling
Как настроить бота на вебхук для продакшена?
Вебхук позволяет Telegram отправлять обновления на ваш сервер по HTTPS. Это эффективнее polling для высоконагруженных ботов.
import telebot
bot = telebot.TeleBot('TOKEN')
# Удалить старый вебхук перед установкой нового
bot.remove_webhook()
# Установить вебхук
bot.set_webhook(url='https://yourdomain.com/webhook')
# Flask-приложение для приёма обновлений
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def webhook():
update = telebot.types.Update.de_json(request.stream.read().decode('utf-8'))
bot.process_new_updates([update])
return 'OK', 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8443, ssl_context=('cert.pem', 'key.pem'))
Сначала удаляется старый вебхук, затем устанавливается новый URL. Сервер Flask прослушивает порт с SSL-сертификатом. При получении POST-запроса обновление передаётся в bot.process_new_updates.
Проблема: без SSL Telegram не примет вебхук. Решение: использовать Let's Encrypt или самоподписанный сертификат (для теста). Ошибка: неправильный URL - бот не получает обновления. Проверить IP/домен и порт.
Случаи использования:
- Продакшен-боты с высокой нагрузкой.
- Боты, работающие на серверах с постоянным IP.
Расширенные примеры с детальными пояснениями
Пример 1: Бот с регистрацией пользователя и сохранением в SQLite
Этот бот собирает имя, возраст и город, затем сохраняет данные в локальную базу данных SQLite.
import telebot
from telebot import types
import sqlite3
bot = telebot.TeleBot('TOKEN')
def init_db():
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER,
city TEXT
)''')
conn.commit()
conn.close()
init_db()
user_data = {} # временное хранение до сохранения
state = {} # состояния
@bot.message_handler(commands=['register'])
def register_start(message):
state[message.chat.id] = 'get_name'
bot.send_message(message.chat.id, 'Введите ваше имя:')
@bot.message_handler(func=lambda m: state.get(m.chat.id) == 'get_name')
def get_name(message):
user_data[message.chat.id] = {'name': message.text}
state[message.chat.id] = 'get_age'
bot.send_message(message.chat.id, 'Сколько вам лет?')
@bot.message_handler(func=lambda m: state.get(m.chat.id) == 'get_age')
def get_age(message):
if not message.text.isdigit():
bot.send_message(message.chat.id, 'Пожалуйста, введите число.')
return
user_data[message.chat.id]['age'] = int(message.text)
state[message.chat.id] = 'get_city'
bot.send_message(message.chat.id, 'Из какого вы города?')
@bot.message_handler(func=lambda m: state.get(m.chat.id) == 'get_city')
def get_city(message):
user_data[message.chat.id]['city'] = message.text
# Сохраняем в БД
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
data = user_data.pop(message.chat.id)
cursor.execute('INSERT OR REPLACE INTO users (user_id, name, age, city) VALUES (?,?,?,?)',
(message.chat.id, data['name'], data['age'], data['city']))
conn.commit()
conn.close()
del state[message.chat.id]
bot.send_message(message.chat.id, 'Регистрация завершена!')
@bot.message_handler(commands=['me'])
def show_profile(message):
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
cursor.execute('SELECT name, age, city FROM users WHERE user_id = ?', (message.chat.id,))
row = cursor.fetchone()
conn.close()
if row:
bot.send_message(message.chat.id, f'Имя: {row[0]}, Возраст: {row[1]}, Город: {row[2]}')
else:
bot.send_message(message.chat.id, 'Вы ещё не зарегистрированы. Используйте /register')
bot.polling()
Результат: При первом запуске создаётся таблица users. Пользователь проходит три шага, данные сохраняются. Команда /me показывает профиль.
Пример 2: Интеграция с внешним API (погода)
Бот получает название города от пользователя и возвращает текущую погоду через OpenWeatherMap.
import telebot
import requests
bot = telebot.TeleBot('TOKEN')
OWM_API_KEY = 'ваш_ключ'
@bot.message_handler(commands=['weather'])
def ask_city(message):
msg = bot.send_message(message.chat.id, 'Напишите название города:')
bot.register_next_step_handler(msg, send_weather)
def send_weather(message):
city = message.text
url = f'http://api.openweathermap.org/data/2.5/weather?q={city}&appid={OWM_API_KEY}&units=metric&lang=ru'
response = requests.get(url)
if response.status_code == 200:
data = response.json()
temp = data['main']['temp']
desc = data['weather'][0]['description']
bot.send_message(message.chat.id, f'Погода в {city}: {desc}, температура {temp}°C')
else:
bot.send_message(message.chat.id, 'Город не найден. Попробуйте снова.')
bot.polling()
Результат: Пользователь вводит команду /weather, затем название города. Бот отправляет запрос к API и отображает погоду.
Пример 3: Бот с уведомлениями по расписанию (schedule)
Бот отправляет напоминание каждый день в определённое время. Используется библиотека schedule.
import telebot
import schedule
import time
import threading
bot = telebot.TeleBot('TOKEN')
CHAT_ID = 123456789 # заменить на реальный ID
def send_reminder():
bot.send_message(CHAT_ID, 'Не забудьте сделать зарядку!')
schedule.every().day.at('09:00').do(send_reminder)
def run_schedule():
while True:
schedule.run_pending()
time.sleep(1)
threading.Thread(target=run_schedule, daemon=True).start()
@bot.message_handler(commands=['start'])
def start(message):
bot.send_message(message.chat.id, 'Бот запущен. Уведомления будут приходить каждый день в 9:00.')
bot.polling()
Результат: При старте бота запускается поток, который проверяет расписание. Каждый день в 9 утра пользователь получает сообщение.
Пример 4: Inline-режим (поиск через бота)
Бот работает в inline-режиме: пользователь может ввести запрос в любом чате, набрав @botusername, и бот предложит результаты.
import telebot
from telebot import types
bot = telebot.TeleBot('TOKEN')
@bot.inline_handler(func=lambda query: len(query.query) > 0)
def inline_search(inline_query):
query_text = inline_query.query
results = []
# Пример: предложить несколько вариантов ответа
for i, item in enumerate(['Вариант A', 'Вариант B', 'Вариант C']):
if query_text.lower() in item.lower():
results.append(types.InlineQueryResultArticle(
id=str(i),
title=item,
input_message_content=types.InputTextMessageContent(
message_text=f'Вы выбрали: {item}'
)
))
if not results:
results.append(types.InlineQueryResultArticle(
id='0',
title='Нет результатов',
input_message_content=types.InputTextMessageContent(message_text='Ничего не найдено')
))
bot.answer_inline_query(inline_query.id, results)
bot.polling()
Результат: При вводе @botusername и текста в любом чате появляется список статей. Выбор статьи отправляет сообщение с текстом.
Пример 5: Использование middleware для логирования
Можно добавить промежуточный обработчик для логирования всех входящих сообщений.
import telebot
bot = telebot.TeleBot('TOKEN')
@bot.middleware_handler(update_types=['message'])
def log_messages(bot_instance, message):
print(f'Получено сообщение от {message.from_user.id}: {message.text}')
@bot.message_handler(commands=['start'])
def start(message):
bot.send_message(message.chat.id, 'Привет! Логирование активно.')
bot.polling()
Результат: Каждое входящее сообщение перед обработкой выводится в консоль. В production можно записывать в файл или БД.