— Как создать Telegram-бота?
— Очень просто: откроешь python-telegram-bot, напишешь пару строк кода, и он будет делать всё!
— А ещё можно и сообщения отправлять, и кнопки делать!
В этой статье мы подробно разберём, как создать своего первого Telegram-бота с использованием библиотеки python-telegram-bot, настроим асинхронность и вебхуки, а также рассмотрим несколько реальных примеров задач для новичков и профессионалов. Будем двигаться от простых шагов до более сложных, чтобы ты мог без проблем сделать и чат-бота, и интегрировать его с базой данных или внешними API.
🧰 Инструменты
Для создания Telegram-бота нам понадобится:
- Python 3.7+ (желательно последняя версия).
- Библиотека python-telegram-bot:
Устанавливаем с помощью pip:pip install python-telegram-bot - Telegram-аккаунт и BotFather для создания бота и получения токена.
🔑 Получение токена
- Открываем Telegram и ищем в поиске BotFather.
- Отправляем команду /newbot.
- Следуем инструкциям и получаем токен (что-то вроде 123456789:ABCdefGHIjklMNOpqrSTUVwxyz).
🚀 Пример 1: Первый бот, который говорит "Привет!"
Давай начнём с самого простого: бота, который отвечает на команду /start.
from telegram import Update
from telegram.ext import Updater, CommandHandler, CallbackContext
# Обработчик команды /start
def start(update: Update, context: CallbackContext):
update.message.reply_text("Привет! Я твой первый бот.")
def main():
# Вставь сюда свой токен
TOKEN = 'YOUR_TOKEN_HERE'
# Создаём объект Updater
updater = Updater(TOKEN, use_context=True)
# Получаем диспетчер для регистрации обработчиков
dispatcher = updater.dispatcher
# Регистрируем обработчик команды /start
dispatcher.add_handler(CommandHandler("start", start))
# Запускаем бота
updater.start_polling()
# Ожидаем завершения работы
updater.idle()
if __name__ == '__main__':
main()
📝 Комментарии:
- Updater — главный объект для управления ботом.
- CommandHandler("start", start) — регистрируем обработчик для команды /start.
- update.message.reply_text() — отправка ответа пользователю.
Запускаем этот скрипт, и если всё настроено правильно, при запуске бота он будет отвечать на команду /start фразой "Привет! Я твой первый бот."
⚙️ Пример 2: Асинхронный бот для более сложных задач
Если планируется масштабный проект или интенсивная нагрузка, асинхронность — ваш лучший друг.
import logging
from telegram import Update
from telegram.ext import Application, CommandHandler
# Логирование ошибок
logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=logging.INFO)
logger = logging.getLogger(__name__)
# Асинхронный обработчик команды /start
async def start(update: Update, context):
await update.message.reply_text("Привет, я асинхронный бот!")
async def main():
# Вставь сюда свой токен
TOKEN = 'YOUR_TOKEN_HERE'
# Создаём асинхронное приложение
application = Application.builder().token(TOKEN).build()
# Регистрируем обработчик команды /start
application.add_handler(CommandHandler("start", start))
# Запускаем бота
await application.run_polling()
if __name__ == '__main__':
import asyncio
asyncio.run(main())
🔧 Почему асинхронность?
- Асинхронность помогает обрабатывать большое количество запросов одновременно.
- В реальных проектах с большим трафиком боты должны работать асинхронно, чтобы не было зависаний.
🕸 Пример 3: Используем вебхуки для работы с ботов
Вместо того, чтобы каждый раз опрашивать сервер Telegram через polling, можно настроить вебхуки — так бот будет получать сообщения по мере их появления.
from telegram import Update
from telegram.ext import Application, CommandHandler
from flask import Flask, request
app = Flask(__name__)
# Обработчик команды /start
async def start(update: Update, context):
await update.message.reply_text("Привет! Это бот с вебхуками.")
@app.route(f'/{YOUR_TOKEN}', methods=['POST'])
def webhook():
json_str = request.get_data().decode('UTF-8')
update = Update.de_json(json_str, application.bot)
application.process_update(update)
return 'OK', 200
def main():
global application
TOKEN = 'YOUR_TOKEN_HERE'
application = Application.builder().token(TOKEN).build()
# Регистрируем обработчик команды /start
application.add_handler(CommandHandler("start", start))
# Устанавливаем вебхук
application.bot.set_webhook(url='https://your_domain.com/' + TOKEN)
if __name__ == '__main__':
main()
app.run(host="0.0.0.0", port=5000)
🌐 Комментарии:
- Вебхуки — это когда сервер Telegram отправляет обновления вашему серверу напрямую.
- Настроить вебхук можно с помощью простого фреймворка вроде Flask.
- Не забывайте про HTTPS — вебхуки работают только через защищённое соединение.
🔲 Пример 4: Добавляем inline-клавиатуру
Теперь давай добавим клавиатуру, чтобы бот не только писал текст, но и позволял пользователю выбирать варианты.
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler
# Обработчик команды /start
async def start(update, context):
keyboard = [
[InlineKeyboardButton("Выбрать опцию 1", callback_data='1')],
[InlineKeyboardButton("Выбрать опцию 2", callback_data='2')]
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text('Привет! Выберите опцию:', reply_markup=reply_markup)
# Обработчик нажатий на кнопки
async def button(update, context):
query = update.callback_query
await query.answer()
await query.edit_message_text(text=f"Вы выбрали опцию {query.data}")
async def main():
TOKEN = 'YOUR_TOKEN_HERE'
application = Application.builder().token(TOKEN).build()
# Регистрируем обработчики
application.add_handler(CommandHandler("start", start))
application.add_handler(CallbackQueryHandler(button))
await application.run_polling()
if __name__ == '__main__':
import asyncio
asyncio.run(main())
💡 Как работает inline-клавиатура:
- Мы создаём кнопки с помощью InlineKeyboardButton.
- Каждая кнопка передаёт callback_data, которое потом можно обработать через CallbackQueryHandler.
🧪 Пример 5: Тестирование бота
Немаловажный этап — тестирование. Для этого можно использовать специальную библиотеку для юнит-тестирования.
import unittest
from telegram import Update
from telegram.ext import CommandHandler, CallbackContext
from io import StringIO
from unittest.mock import patch
class TestBot(unittest.TestCase):
@patch('sys.stdout', new_callable=StringIO)
def test_start(self, mock_stdout):
update = Update(update_id=12345, message=type('Message', (), {'text': '/start'}))
context = CallbackContext.from_update(update, dispatcher=None)
start(update, context)
self.assertIn('Привет! Я твой первый бот.', mock_stdout.getvalue())
if __name__ == '__main__':
unittest.main()
🧑🔬 Тестирование важно:
- Проверка функционала бота на этапе разработки поможет избежать багов.
- Используйте patch и unittest для мокирования объектов и проверки результата.
🌐 Интеграция с API
Допустим, мы хотим интегрировать нашего бота с внешним API, например, для получения информации о погоде. Для этого будем использовать requests для отправки HTTP-запросов.
Пример 6: Получаем погоду через API
Для начала, тебе нужно зарегистрироваться на сайте OpenWeatherMap, чтобы получить API-ключ для доступа к данным о погоде.
pip install requests
Далее пишем код:
import requests
from telegram import Update
from telegram.ext import Application, CommandHandler
API_KEY = "YOUR_OPENWEATHERMAP_API_KEY"
CITY = "Moscow"
# Функция для получения данных о погоде
def get_weather():
url = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric&lang=ru"
response = requests.get(url)
data = response.json()
if data.get("weather"):
description = data["weather"][0]["description"]
temp = data["main"]["temp"]
return f"Погода в {CITY}: {description}, температура: {temp}°C"
else:
return "Не удалось получить данные о погоде."
# Обработчик команды /weather
async def weather(update: Update, context):
weather_info = get_weather()
await update.message.reply_text(weather_info)
async def main():
TOKEN = 'YOUR_TOKEN_HERE'
application = Application.builder().token(TOKEN).build()
# Регистрируем обработчики
application.add_handler(CommandHandler("weather", weather))
await application.run_polling()
if __name__ == '__main__':
import asyncio
asyncio.run(main())
🧑🔬 Пояснение:
- get_weather() — отправляет запрос к API OpenWeatherMap, получает данные о погоде и форматирует их.
- weather() — обработчик для команды /weather, который выводит текущую информацию о погоде в выбранном городе.
Теперь, когда пользователь отправляет команду /weather, бот будет отправлять актуальные данные о погоде.
🏙 Интеграция с базой данных (SQLite)
Допустим, нам нужно хранить информацию о пользователях, например, их имя, дату регистрации и предпочтения. Для этого мы можем использовать SQLite, легковесную базу данных, которая отлично подходит для небольших проектов.
Пример 7: Храним информацию о пользователях в базе данных
Устанавливаем библиотеку для работы с SQLite:
pip install sqlite3
Создаём базу данных и таблицу:
import sqlite3
# Создаём соединение с базой данных
conn = sqlite3.connect('bot_users.db')
cursor = conn.cursor()
# Создаём таблицу пользователей
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT,
username TEXT,
registration_date TEXT
)
''')
# Сохраняем изменения и закрываем соединение
conn.commit()
conn.close()
Интеграция с ботом:
Теперь добавим в бота функционал для регистрации пользователей в базе данных.
import sqlite3
from telegram import Update
from telegram.ext import Application, CommandHandler
# Функция для добавления пользователя в базу данных
def add_user_to_db(user_id, first_name, last_name, username):
conn = sqlite3.connect('bot_users.db')
cursor = conn.cursor()
cursor.execute('''
INSERT OR IGNORE INTO users (user_id, first_name, last_name, username, registration_date)
VALUES (?, ?, ?, ?, DATE('now'))
''', (user_id, first_name, last_name, username))
conn.commit()
conn.close()
# Обработчик команды /start
async def start(update: Update, context):
user_id = update.message.from_user.id
first_name = update.message.from_user.first_name
last_name = update.message.from_user.last_name
username = update.message.from_user.username
# Добавляем пользователя в базу данных
add_user_to_db(user_id, first_name, last_name, username)
# Отправляем приветственное сообщение
await update.message.reply_text(f"Привет, {first_name}! Ты успешно зарегистрирован.")
async def main():
TOKEN = 'YOUR_TOKEN_HERE'
application = Application.builder().token(TOKEN).build()
# Регистрируем обработчики
application.add_handler(CommandHandler("start", start))
await application.run_polling()
if __name__ == '__main__':
import asyncio
asyncio.run(main())
📝 Пояснение:
- Мы создали таблицу users, в которой будем хранить информацию о пользователях, которая поступает с команды /start.
- Функция add_user_to_db() добавляет пользователя в базу данных, если его ещё нет (используем INSERT OR IGNORE).
- Теперь каждый новый пользователь, который напишет боту команду /start, будет добавлен в базу данных с его информацией.
🚀 Пример 8: Используем базы данных для хранения предпочтений
Допустим, теперь нужно сохранить предпочтения пользователей, например, язык, который они выбрали.
# Функция для обновления языка пользователя
def update_user_language(user_id, language):
conn = sqlite3.connect('bot_users.db')
cursor = conn.cursor()
cursor.execute('''
UPDATE users SET language = ? WHERE user_id = ?
''', (language, user_id))
conn.commit()
conn.close()
# Обработчик команды /set_language
async def set_language(update: Update, context):
user_id = update.message.from_user.id
language = context.args[0] if context.args else "en" # По умолчанию — английский
# Обновляем язык пользователя в базе данных
update_user_language(user_id, language)
await update.message.reply_text(f"Язык установлен на {language}")
async def main():
TOKEN = 'YOUR_TOKEN_HERE'
application = Application.builder().token(TOKEN).build()
# Регистрируем обработчики
application.add_handler(CommandHandler("set_language", set_language))
await application.run_polling()
if __name__ == '__main__':
import asyncio
asyncio.run(main())
📊 Пояснение:
- Мы добавили команду /set_language, которая позволяет пользователям менять язык.
- Эта информация сохраняется в базе данных, чтобы в будущем использовать её для персонализации сообщений.
🔄 Заключение
Теперь ты знаешь, как интегрировать бота с внешними API для получения данных и как хранить информацию в базе данных. Такие возможности делают твоего бота гораздо более полезным и мощным.
Ты можешь использовать эти примеры для создания более сложных проектов — например, бота, который отслеживает заказы, управляет пользовательскими настройками или интегрируется с CRM-системами.