¿Qué es un Bot de Telegram?
Un bot de Telegram es un programa automatizado que puede interactuar con usuarios a través de la plataforma de Telegram. Puedes crear bots para automatizar tareas, proporcionar información, juegos y mucho más.
Crear tu Bot en Telegram
Paso 1: Hablar con BotFather
1. Abre Telegram y busca @BotFather
2. Envía el comando /newbot
3. Elige un nombre para tu bot
4. Elige un username (debe terminar en 'bot')
5. BotFather te dará un TOKEN - guárdalo en un lugar seguro
Instalación de la Biblioteca
pip install python-telegram-bot==20.7Bot Básico - Hola Mundo
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
# Tu token del BotFather
TOKEN = 'TU_TOKEN_AQUI'
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Comando /start"""
await update.message.reply_text('¡Hola! Soy tu bot de Telegram 🤖')
async def ayuda(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Comando /ayuda"""
texto_ayuda = """
Comandos disponibles:
/start - Iniciar el bot
/ayuda - Mostrar esta ayuda
/info - Información del bot
"""
await update.message.reply_text(texto_ayuda)
def main():
# Crear aplicación
app = Application.builder().token(TOKEN).build()
# Agregar handlers
app.add_handler(CommandHandler('start', start))
app.add_handler(CommandHandler('ayuda', ayuda))
# Iniciar bot
print('Bot iniciado...')
app.run_polling()
if __name__ == '__main__':
main()Manejo de Mensajes
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
TOKEN = 'TU_TOKEN_AQUI'
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
usuario = update.effective_user
await update.message.reply_text(
f'¡Hola {usuario.first_name}! 👋\n'
f'Envíame cualquier mensaje y te responderé.'
)
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Repite el mensaje del usuario"""
mensaje = update.message.text
await update.message.reply_text(f'Dijiste: {mensaje}')
async def mayusculas(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Convierte texto a mayúsculas"""
if context.args:
texto = ' '.join(context.args)
await update.message.reply_text(texto.upper())
else:
await update.message.reply_text('Uso: /mayusculas tu texto aquí')
def main():
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler('start', start))
app.add_handler(CommandHandler('mayusculas', mayusculas))
# Handler para mensajes de texto (no comandos)
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
print('Bot iniciado...')
app.run_polling()
if __name__ == '__main__':
main()Teclados Personalizados
Teclado de Respuesta (Reply Keyboard)
from telegram import Update, ReplyKeyboardMarkup, KeyboardButton
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
async def menu(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Mostrar menú con teclado"""
teclado = [
[KeyboardButton('🎲 Dado'), KeyboardButton('💬 Chiste')],
[KeyboardButton('📊 Estadísticas'), KeyboardButton('ℹ️ Info')],
[KeyboardButton('🔙 Volver')]
]
reply_markup = ReplyKeyboardMarkup(teclado, resize_keyboard=True)
await update.message.reply_text(
'🤖 Menú Principal\nElige una opción:',
reply_markup=reply_markup
)
async def manejar_botones(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Manejar presiones de botones"""
texto = update.message.text
if texto == '🎲 Dado':
import random
numero = random.randint(1, 6)
await update.message.reply_text(f'🎲 Salió: {numero}')
elif texto == '💬 Chiste':
chistes = [
'¿Por qué los programadores prefieren el modo oscuro? Porque la luz atrae bugs! 🐛',
'¿Cuántos programadores se necesitan para cambiar una bombilla? Ninguno, es un problema de hardware. 💡'
]
import random
await update.message.reply_text(random.choice(chistes))
elif texto == 'ℹ️ Info':
await update.message.reply_text('Bot creado con Python 🐍')
def main():
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler('menu', menu))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, manejar_botones))
app.run_polling()
if __name__ == '__main__':
main()Teclado Inline (Botones con Callbacks)
from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import Application, CommandHandler, CallbackQueryHandler, ContextTypes
async def opciones(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Mostrar opciones con botones inline"""
teclado = [
[
InlineKeyboardButton('✅ Opción 1', callback_data='opcion_1'),
InlineKeyboardButton('✅ Opción 2', callback_data='opcion_2')
],
[InlineKeyboardButton('❌ Cancelar', callback_data='cancelar')]
]
reply_markup = InlineKeyboardMarkup(teclado)
await update.message.reply_text(
'¿Qué opción prefieres?',
reply_markup=reply_markup
)
async def boton_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Manejar callbacks de botones inline"""
query = update.callback_query
await query.answer() # Responder al callback
if query.data == 'opcion_1':
await query.edit_message_text('Elegiste la Opción 1 ✅')
elif query.data == 'opcion_2':
await query.edit_message_text('Elegiste la Opción 2 ✅')
elif query.data == 'cancelar':
await query.edit_message_text('Operación cancelada ❌')
def main():
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler('opciones', opciones))
app.add_handler(CallbackQueryHandler(boton_callback))
app.run_polling()
if __name__ == '__main__':
main()Bot Completo con Múltiples Funciones
from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import (
Application,
CommandHandler,
MessageHandler,
CallbackQueryHandler,
filters,
ContextTypes
)
import random
from datetime import datetime
TOKEN = 'TU_TOKEN_AQUI'
# ===== COMANDOS =====
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
usuario = update.effective_user
mensaje = f"""
🤖 ¡Hola {usuario.first_name}!
Bienvenido a ByteNinja Bot.
Comandos disponibles:
/ayuda - Ver todos los comandos
/info - Información del usuario
/dado - Tirar un dado
/moneda - Lanzar una moneda
/clima - Consultar clima
/calculadora - Calculadora simple
"""
await update.message.reply_text(mensaje)
async def info(update: Update, context: ContextTypes.DEFAULT_TYPE):
usuario = update.effective_user
info_texto = f"""
📊 Tu Información:
👤 Nombre: {usuario.first_name}
🆔 ID: {usuario.id}
📛 Username: @{usuario.username or 'No disponible'}
🔗 Link: {usuario.link}
"""
await update.message.reply_text(info_texto)
async def dado(update: Update, context: ContextTypes.DEFAULT_TYPE):
numero = random.randint(1, 6)
await update.message.reply_dice()
await update.message.reply_text(f'🎲 Salió: {numero}')
async def moneda(update: Update, context: ContextTypes.DEFAULT_TYPE):
resultado = random.choice(['Cara', 'Cruz'])
emoji = '👑' if resultado == 'Cara' else '🪙'
await update.message.reply_text(f'{emoji} Resultado: {resultado}')
async def calculadora(update: Update, context: ContextTypes.DEFAULT_TYPE):
if not context.args or len(context.args) < 3:
await update.message.reply_text(
'Uso: /calculadora numero operador numero\n'
'Ejemplo: /calculadora 10 + 5\n'
'Operadores: +, -, *, /'
)
return
try:
num1 = float(context.args[0])
operador = context.args[1]
num2 = float(context.args[2])
if operador == '+':
resultado = num1 + num2
elif operador == '-':
resultado = num1 - num2
elif operador == '*':
resultado = num1 * num2
elif operador == '/':
if num2 == 0:
await update.message.reply_text('❌ No se puede dividir por cero')
return
resultado = num1 / num2
else:
await update.message.reply_text('❌ Operador inválido')
return
await update.message.reply_text(f'✅ Resultado: {resultado}')
except ValueError:
await update.message.reply_text('❌ Números inválidos')
async def recordatorio(update: Update, context: ContextTypes.DEFAULT_TYPE):
if not context.args:
await update.message.reply_text(
'Uso: /recordatorio segundos mensaje\n'
'Ejemplo: /recordatorio 10 Recordatorio de prueba'
)
return
try:
segundos = int(context.args[0])
mensaje = ' '.join(context.args[1:])
await update.message.reply_text(
f'⏰ Te recordaré en {segundos} segundos'
)
# Programar recordatorio
context.job_queue.run_once(
lambda context: context.bot.send_message(
chat_id=update.effective_chat.id,
text=f'🔔 Recordatorio: {mensaje}'
),
segundos
)
except (ValueError, IndexError):
await update.message.reply_text('❌ Formato inválido')
async def encuesta(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_poll(
question='¿Cuál es tu lenguaje de programación favorito?',
options=['Python 🐍', 'JavaScript 📜', 'Java ☕', 'C++ ⚙️'],
is_anonymous=False,
allows_multiple_answers=False
)
# ===== MANEJO DE ARCHIVOS =====
async def manejar_foto(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text('📷 ¡Recibí tu foto! Gracias por compartir.')
# Obtener info de la foto
photo = update.message.photo[-1] # Mejor calidad
file_size = photo.file_size / 1024 # KB
await update.message.reply_text(
f'ℹ️ Tamaño del archivo: {file_size:.2f} KB'
)
async def manejar_documento(update: Update, context: ContextTypes.DEFAULT_TYPE):
documento = update.message.document
await update.message.reply_text(
f'📄 Recibí el documento: {documento.file_name}\n'
f'📊 Tamaño: {documento.file_size / 1024:.2f} KB'
)
# ===== JUEGOS =====
async def adivina_numero(update: Update, context: ContextTypes.DEFAULT_TYPE):
numero_secreto = random.randint(1, 100)
context.user_data['numero_secreto'] = numero_secreto
context.user_data['intentos'] = 0
await update.message.reply_text(
'🎮 ¡Juego iniciado!\n'
'Adivina el número entre 1 y 100\n'
'Escribe tu intento:'
)
async def verificar_numero(update: Update, context: ContextTypes.DEFAULT_TYPE):
if 'numero_secreto' not in context.user_data:
return
try:
intento = int(update.message.text)
context.user_data['intentos'] += 1
numero_secreto = context.user_data['numero_secreto']
if intento == numero_secreto:
intentos = context.user_data['intentos']
await update.message.reply_text(
f'🎉 ¡Correcto! Era {numero_secreto}\n'
f'Lo adivinaste en {intentos} intentos'
)
del context.user_data['numero_secreto']
del context.user_data['intentos']
elif intento < numero_secreto:
await update.message.reply_text('📈 Más alto...')
else:
await update.message.reply_text('📉 Más bajo...')
except ValueError:
pass
# ===== MAIN =====
def main():
app = Application.builder().token(TOKEN).build()
# Comandos
app.add_handler(CommandHandler('start', start))
app.add_handler(CommandHandler('info', info))
app.add_handler(CommandHandler('dado', dado))
app.add_handler(CommandHandler('moneda', moneda))
app.add_handler(CommandHandler('calculadora', calculadora))
app.add_handler(CommandHandler('recordatorio', recordatorio))
app.add_handler(CommandHandler('encuesta', encuesta))
app.add_handler(CommandHandler('juego', adivina_numero))
# Archivos
app.add_handler(MessageHandler(filters.PHOTO, manejar_foto))
app.add_handler(MessageHandler(filters.Document.ALL, manejar_documento))
# Juego
app.add_handler(MessageHandler(
filters.TEXT & ~filters.COMMAND,
verificar_numero
))
print('🤖 Bot iniciado...')
app.run_polling()
if __name__ == '__main__':
main()Configuración y Variables de Entorno
# config.py
import os
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.getenv('TELEGRAM_TOKEN')
if not TOKEN:
raise ValueError('Token no encontrado en variables de entorno')# .env
TELEGRAM_TOKEN=tu_token_aquiLogging y Debugging
import logging
# Configurar logging
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
logger = logging.getLogger(__name__)
# Usar en handlers
async def comando(update: Update, context: ContextTypes.DEFAULT_TYPE):
logger.info(f'Usuario {update.effective_user.id} ejecutó comando')
# ... resto del códigoDeploy del Bot
Mantener Bot Corriendo (Linux)
# Usando screen
screen -S telegram_bot
python bot.py
# Ctrl+A+D para detach
# Volver a la sesión
screen -r telegram_botSystemd Service (Linux)
# /etc/systemd/system/telegram-bot.service
[Unit]
Description=Telegram Bot
After=network.target
[Service]
Type=simple
User=tu_usuario
WorkingDirectory=/ruta/a/tu/bot
ExecStart=/usr/bin/python3 /ruta/a/tu/bot/bot.py
Restart=always
[Install]
WantedBy=multi-user.target# Iniciar servicio
sudo systemctl start telegram-bot
sudo systemctl enable telegram-bot
sudo systemctl status telegram-botBuenas Prácticas
- Usa variables de entorno: No hardcodees tokens
- Maneja errores: Try-except en todos los handlers
- Logging: Registra eventos importantes
- Rate limiting: Controla spam de usuarios
- Valida input: Siempre verifica datos de usuario
- Documentación: Incluye /ayuda con comandos
- Feedback: Confirma acciones al usuario
Conclusión
Crear bots de Telegram con Python es simple y poderoso. Puedes automatizar tareas, crear juegos, proporcionar información y mucho más. La biblioteca python-telegram-bot hace que sea fácil manejar comandos, mensajes, teclados personalizados y archivos. Experimenta creando tu propio bot con funcionalidades únicas.