Добавить в корзинуПозвонить
Найти в Дзене
Анастасия Софт

Пишем Telegram-бота на Python: от "Привет!" до inline-клавиатуры

— Как создать Telegram-бота?
— Очень просто: откроешь python-telegram-bot, напишешь пару строк кода, и он будет делать всё!
— А ещё можно и сообщения отправлять, и кнопки делать! В этой статье мы подробно разберём, как создать своего первого Telegram-бота с использованием библиотеки python-telegram-bot, настроим асинхронность и вебхуки, а также рассмотрим несколько реальных примеров задач для новичков и профессионалов. Будем двигаться от простых шагов до более сложных, чтобы ты мог без проблем сделать и чат-бота, и интегрировать его с базой данных или внешними API. Для создания Telegram-бота нам понадобится: Давай начнём с самого простого: бота, который отвечает на команду /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'
Оглавление

— Как создать Telegram-бота?

— Очень просто: откроешь python-telegram-bot, напишешь пару строк кода, и он будет делать всё!

— А ещё можно и сообщения отправлять, и кнопки делать!

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

🧰 Инструменты

Для создания Telegram-бота нам понадобится:

  • Python 3.7+ (желательно последняя версия).
  • Библиотека python-telegram-bot:

    Устанавливаем с помощью pip:pip install python-telegram-bot
  • Telegram-аккаунт и BotFather для создания бота и получения токена.

🔑 Получение токена

  1. Открываем Telegram и ищем в поиске BotFather.
  2. Отправляем команду /newbot.
  3. Следуем инструкциям и получаем токен (что-то вроде 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-системами.