Bot de automatización para WhatsApp Web que envía mensajes, implementado con Playwright y tres patrones de diseño fundamentales: Factory Method, Page Object Model y Template Method.
- 🎯 Browser siempre visible: WhatsApp Web requiere browser visible; eliminado headless que causaba fallos
- 🔔 Auto-dismiss popups: "Novedades en WhatsApp Web" (clic en "Continuar") + "Sincronización en pausa"
- 🔄 Retry inteligente: 3 intentos con limpieza gradual (state.json → persistent context → full reset)
- 🚀 Envío múltiple en una instancia: Un solo browser para todos los contactos (sin abrir/cerrar por contacto)
- ⚙️ Rate limiting configurable:
--delaysegundos entre envíos (default 2.5s) - 🔧 Selectores robustos: Fallbacks para botón enviar (aria-label, data-testid, data-icon)
Encapsula todos los selectores DOM y acciones de WhatsApp Web en una sola clase:
- Selectores basados en
data-testidpara máxima estabilidad - Métodos:
search_contact(),type_message(),click_send(),wait_for_qr(),is_logged_in() - Separa la lógica de UI de la lógica de negocio
Centraliza la creación del contexto de navegador:
BrowserFactory.create_context(config)retornaBrowserContextconfigurado- Usa
launch_persistent_context()para persistir cookies, IndexedDB, Service Workers - Si NO hay sesión → crea contexto limpio con
headless=Falsepara escaneo QR manual
Define el algoritmo esqueleto del bot en BaseBotFlow.run():
def run(self):
self.setup()
self.init_browser()
self.authenticate_or_load_session()
self.execute_task()
self.cleanup()WhatsAppBotFlowimplementa los pasos concretos usandoWhatsAppPage
- Python 3.10+
- PDM instalado
# Clonar repositorio
git clone https://github.com/AngBan2x/whatsapp-playwright-bot.git
cd whatsapp-playwright-bot
# Instalar dependencias con PDM
pdm install
# Instalar navegador Chromium
pdm run playwright install chromiumEl bot usa Windows Credential Manager (via keyring) para almacenar números de forma segura.
# Configurar número por defecto (usado por `run.bat` o `send` sin argumentos)
pdm run python -c "
import keyring
keyring.set_password('whatsapp-bot', 'target_phone', '+584120000000')
print('Número por defecto guardado')
"pdm run python -c "
import keyring
print(keyring.get_password('whatsapp-bot', 'target_phone'))
"run.batMantiene la consola abierta al finalizar para ver logs.
# Ver ayuda general
pdm run python main.py --help
# Ver ayuda de subcomando send
pdm run python main.py send --help
# Ver ayuda de subcomando contacts
pdm run python main.py contacts --help# Enviar mensaje predeterminado al número por defecto (keyring target_phone)
pdm run python main.py send
# Enviar a número específico con mensaje personalizado
pdm run python main.py send --to "+58 424-0000000" --message "Hola desde el bot"
# Enviar a múltiples números
pdm run python main.py send --to +584120000000 --to +584240000000
# Enviar a contactos guardados por alias
pdm run python main.py send --contact josh --contact andres
# Combinar números directos y contactos
pdm run python main.py send --to +584120000000 --contact juan --message "Mensaje grupal"
# Simular envío sin abrir navegador (dry-run)
pdm run python main.py send --to +584120000000 --dry-run
# Cambiar delay entre envíos (default: 2.5s)
pdm run python main.py send --to +584120000000 --to +584240000000 --delay 3.0Opciones de send:
| Opción | Descripción |
|---|---|
--to NUMBER |
Número destino (E.164). Repetible para múltiples. |
--contact, -c ALIAS |
Alias de contacto guardado. Repetible. Case-insensitive. |
--message, -m TEXT |
Mensaje personalizado. Si no se usa, usa el predeterminado. |
--dry-run |
Simula sin abrir navegador ni enviar real. |
--delay SECONDS |
Segundos entre envíos múltiples (default: 2.5). |
Nota: Si usas --message, se añade automáticamente: \nRepo: https://github.com/AngBan2x/whatsapp-playwright-bot
# Agregar contacto (alias case-insensitive, número se normaliza)
pdm run python main.py contacts add josh "+58 414-0000000"
pdm run python main.py contacts add andres "+58 412-0000001"
# Listar contactos
pdm run python main.py contacts list
# Ver número de un contacto
pdm run python main.py contacts show josh
# Eliminar contacto
pdm run python main.py contacts remove josh| Ejecución | Comportamiento |
|---|---|
| Primera | Abre Chromium visible (headless=False), muestra QR, espera escaneo manual, guarda sesión en session/ |
| Subsecuentes | Reutiliza sesión persistente desde session/, omite QR, envía mensaje directamente |
| Fallo de sesión | Retry inteligente: 3 intentos (reintento → limpiar state.json → limpiar context → full reset + QR) |
La carpeta
session/está en.gitignore— nunca se sube el estado de autenticación al repositorio.
Tarea finalizada.
Patrones utilizados: Factory Method, Page Object Model, Template Method.
texto
Repo: https://github.com/AngBan2x/whatsapp-playwright-bot
| Popup | Detección | Acción |
|---|---|---|
| Novedades en WhatsApp Web | Texto exacto + botón "Continuar" | Auto-clic en "Continuar" |
| Sincronización en pausa | Textos: "Entendido", "Continuar", "OK", "Aceptar", "Cerrar", "Got it", "Continue" | Auto-clic y espera desaparición |
Ambos popups se detectan y dismissan automáticamente antes de verificar login y antes de enviar cada mensaje.
.
├── .gitignore
├── LICENSE
├── README.md
├── pyproject.toml
├── run.bat
├── session/
└── src/
└── whatsapp_bot/
├── __init__.py
├── main.py # Punto de entrada + CLI
├── config.py # Keyring + contactos + normalización
├── cli.py # Argument parser
├── pages/
│ └── whatsapp_page.py # POM
├── factories/
│ └── browser_factory.py # Factory Method
└── flows/
├── base_bot_flow.py # Template Method (base)
└── whatsapp_bot_flow.py # Implementación concreta
Se aceptan formatos flexibles y se normalizan automáticamente:
+58 412-0000000→+584120000000+58 (414) 000-0000→+584140000000+584120000000→+584120000000(ya normalizado)
Entre envíos múltiples hay un delay configurable (default 2.5s) para evitar bloqueos de WhatsApp Web.
Si falla un destinatario en envío múltiple: se loggea warning y continúa con los siguientes.
--dry-run simula toda la ejecución sin abrir navegador ni enviar mensajes reales.
MIT License — ver LICENSE para detalles.
- Browser siempre visible: WhatsApp Web requiere browser visible; eliminado modo headless
- Popup "Novedades en WhatsApp Web": Auto-clic en "Continuar" (aparece tras primer login)
- Popup "Sincronización en pausa": Auto-dismiss con textos "Entendido", "Continuar", "OK", "Aceptar", "Cerrar", "Got it", "Continue"
- Retry inteligente de sesión: 3 intentos con limpieza gradual (state_only → gradual → full)
- Envío múltiple en una instancia: Un solo browser para todos los contactos (elimina abrir/cerrar Chromium por contacto)
- Rate limiting configurable:
--delaysegundos entre envíos (default 2.5s) - Selectores robustos para botón enviar: Fallbacks aria-label="Enviar/Send", data-testid="wds-ic-send-filled", data-icon="send"
- Detección de sesión mejorada: Verifica cookies + IndexedDB de WhatsApp en persistent context
- Compatibilidad retro:
target_phone(string) +target_phones(lista) coexisten
- CLI completo con subcomandos
sendycontacts - Múltiples destinatarios via
--torepetido y/o--contactrepetido - Contactos predefinidos con alias case-insensitive (
contacts add/list/show/remove) - Mensaje personalizable via
--message(añade link del repo automáticamente) - Normalización de números (acepta espacios, guiones, paréntesis)
- Rate limiting configurable entre envíos (
--delay) - Dry-run para testing sin envío real (
--dry-run) - Error handling robusto: continúa en fallos parciales
- Backward compatibility:
run.batsigue funcionando igual
- Implementación base con 3 patrones: Factory Method, POM, Template Method
- Persistencia de sesión con
storage_state - Gestión de credenciales con
keyring - Script
run.batpara Windows