Telegram чат-боты на Python с библиотекой pyTelegramBotAPI: от начального уровня до продвинутых решений

Раздел: Веб-разработка -> Telegram боты

Введение в создание 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 можно записывать в файл или БД.

Telegram боты на Python (pyTelegramBotAPI) - comments

En
Py telegram python (python)