Bot automatizado inteligente para realizar el fichaje de entrada y salida en la plataforma Bizneo HR de Rock Internet.
ChronoBot es un sistema automatizado que gestiona el fichaje horario en Bizneo HR usando web scraping con Playwright. El bot está diseñado para simular comportamiento humano y ejecutarse de forma autónoma en horarios aleatorios dentro de ventanas configurables.
- Login automático con gestión persistente de sesiones (evita logins repetidos)
- Detección y gestión de reCAPTCHA con intervención manual asistida
- Verificación de acción esperada: solo hace clic si el botón coincide con la tarea programada
- Simulación de comportamiento humano: movimientos de ratón, delays aleatorios, velocidad de escritura variable
- Horarios aleatorios dentro de rangos configurables (evita patrones predecibles)
- Respeta días festivos y fines de semana (configurable por archivo JSON)
- Sistema de reintentos automáticos cada 1 minuto ante fallos
- Ejecución dual: mañana (entrada) y tarde (salida) con validación independiente
- Modo Manual: ejecución inmediata para pruebas y debugging
- Modo Servicio: ejecución continua en segundo plano respetando horarios
- Servicio Windows: instalación como servicio del sistema con inicio automático
- Logging completo con niveles configurables (DEBUG, INFO, WARNING, ERROR)
- Capturas de pantalla automáticas en puntos críticos y errores
- Registro detallado de acciones (tomadas, saltadas, fallidas)
- Trazabilidad completa de cada ejecución
┌─────────────────────────────────────────────────────────────┐
│ ChronoBot │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ Scheduler │─────▶│ Scraper │─────▶│ Bizneo │ │
│ │ (Horarios) │ │ (Playwright)│ │ HR │ │
│ └──────────────┘ └──────────────┘ └──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Config │ │ State Mgmt │ │
│ │ Holidays │ │ (Sessions) │ │
│ └──────────────┘ └──────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ Logging & Screenshots │ │
│ └─────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Responsabilidad: Gestión de tareas programadas y control de horarios
Funcionalidades:
- Genera horarios aleatorios diarios dentro de ventanas configuradas
- Verifica días laborables (excluye festivos y fines de semana)
- Controla ejecución única por ventana horaria
- Resetea flags automáticamente al cambiar de día
- Ejecuta verificaciones cada 1 minuto
- Implementa sistema de reintentos ante fallos
Lógica de Ejecución:
# Cada minuto verifica:
1. ¿Es un día laborable? → Si no, skip
2. ¿Ya se ejecutó esta tarea hoy? → Si sí, skip
3. ¿Es el momento exacto programado? → Si no, wait
4. ¿La tarea tuvo éxito? → Marcar como ejecutada / Si no, permitir reintentoVentanas Horarias:
- Mañana: Rango configurable (ej: 08:30-09:10) → Acción esperada: "Iniciar"
- Tarde: Rango configurable (ej: 18:00-19:00) → Acción esperada: "Finalizar"
Responsabilidad: Automatización de interacción web con Playwright
Funcionalidades:
- Gestión de navegador: Chromium con configuración anti-detección
- Manejo de sesiones: Carga/guarda estado para evitar logins repetidos
- Proceso de login:
- Detección automática si ya está logueado
- Relleno de formulario con delays humanos
- Detección de reCAPTCHA
- Espera asistida para resolución manual de CAPTCHA
- Verificación activa de login exitoso
- Clic inteligente en botón:
- Localiza botón de Chrono
- Verifica tipo de acción (Iniciar vs Finalizar)
- Compara con acción esperada
- Solo hace clic si coincide
- Registra acción tomada o razón de omisión
- Simulación humana:
- Movimientos de ratón en curvas aleatorias
- Delays variables entre acciones
- Velocidad de escritura realista
Flujo de Autenticación:
1. Navegar a URL → Wait networkidle
2. ¿Ya logueado? → Sí: Skip login | No: Continuar
3. Delay inicial + movimientos de ratón (2-4s)
4. Click campo email → Escribir con delay (50-150ms por tecla)
5. Delay (500-1000ms)
6. Click campo password → Escribir con delay
7. Delay (800-1500ms)
8. ¿Hay reCAPTCHA? → Sí: Esperar resolución manual | No: Continuar
9. Click botón "Entrar"
10. Esperar y verificar login exitoso (hasta 40s)
11. Guardar estado de sesión
Flujo de Clic en Botón:
1. Delay inicial (1-2s)
2. Wait selector: button[data-gtm-category="chrono"]
3. Leer texto del botón
4. Determinar acción actual: "iniciar" | "finalizar" | "desconocido"
5. ¿Acción coincide con esperada?
→ SÍ: Simular movimiento ratón → Click → Return (success=True, action_taken=True)
→ NO: Screenshot → Return (success=True, action_taken=False)
6. Esperar procesamiento (3-5s)
7. Screenshot final
Responsabilidad: Utilidades transversales del sistema
Componentes:
- Config: Carga y gestión de configuración desde JSON
- HolidayChecker: Verificación de festivos y fines de semana
- setup_logging: Configuración de sistema de logs
- ensure_directories: Creación de directorios necesarios
Responsabilidad: Persistencia de sesión del navegador
Contenido:
- Cookies de sesión
- Local storage
- Session storage
- Origen y permisos
Ventajas:
- Evita login en cada ejecución
- Reduce exposición a CAPTCHA
- Acelera el proceso
- Mantiene sesión entre reinicios
07:00 → Scheduler inicia (run_service.py)
│
├─ Genera horario aleatorio mañana: 08:47
├─ Genera horario aleatorio tarde: 18:23
├─ Log: próximas ejecuciones programadas
│
08:00 → Loop cada 1 minuto
│
08:47 → ¡Hora exacta alcanzada!
├─ Verifica: ¿Es laborable? ✓
├─ Verifica: ¿Ya ejecutada? ✗
├─ Llama: scraper.run(expected_action='iniciar')
│ ├─ Navega a Bizneo
│ ├─ Carga sesión guardada → Ya logueado ✓
│ ├─ Busca botón Chrono
│ ├─ Lee texto: "Iniciar" ✓
│ ├─ Compara: esperado='iniciar', actual='iniciar' → Match ✓
│ ├─ Simula mouse + Click
│ └─ Return: {success: true, action_taken: true}
├─ Marca: morning_executed = True
└─ Log: ✓ Tarea mañana completada
│
18:23 → ¡Hora exacta alcanzada!
├─ Verifica: ¿Es laborable? ✓
├─ Verifica: ¿Ya ejecutada? ✗
├─ Llama: scraper.run(expected_action='finalizar')
│ ├─ Navega a Bizneo
│ ├─ Carga sesión guardada → Ya logueado ✓
│ ├─ Busca botón Chrono
│ ├─ Lee texto: "Finalizar" ✓
│ ├─ Compara: esperado='finalizar', actual='finalizar' → Match ✓
│ ├─ Simula mouse + Click
│ └─ Return: {success: true, action_taken: true}
├─ Marca: evening_executed = True
└─ Log: ✓ Tarea tarde completada
│
00:00 → Nuevo día detectado
├─ Reset: morning_executed = False
├─ Reset: evening_executed = False
└─ Genera nuevos horarios aleatorios
08:00 → Usuario ficha entrada manualmente en Bizneo
│
08:47 → Scheduler ejecuta tarea mañana
├─ Llama: scraper.run(expected_action='iniciar')
│ ├─ Navega a Bizneo
│ ├─ Ya logueado ✓
│ ├─ Busca botón Chrono
│ ├─ Lee texto: "Finalizar" (porque ya está iniciado)
│ ├─ Compara: esperado='iniciar', actual='finalizar' → No match ✗
│ ├─ Screenshot: 'skipped_finalizar'
│ └─ Return: {success: true, action_taken: false}
├─ Marca: morning_executed = True (evita reintentos)
└─ Log: ⏭️ Ejecutada sin acción: botón es "finalizar" pero se esperaba "iniciar"
│
18:23 → Scheduler ejecuta tarea tarde
├─ Llama: scraper.run(expected_action='finalizar')
│ ├─ Navega a Bizneo
│ ├─ Busca botón Chrono
│ ├─ Lee texto: "Finalizar" ✓
│ ├─ Compara: esperado='finalizar', actual='finalizar' → Match ✓
│ └─ Click exitoso → Ficha salida
└─ Log: ✓ Tarea tarde completada
08:47 → Scheduler ejecuta tarea mañana
├─ Llama: scraper.run(expected_action='iniciar')
│ ├─ Navega a Bizneo
│ └─ ERROR: Timeout (red caída)
├─ Return: {success: false}
├─ NO marca morning_executed (permite reintento)
└─ Log: ✗ Tarea mañana falló: Timeout, se reintentará
│
08:48 → Loop ejecuta tarea mañana (reintento automático)
├─ Verifica: ¿Ya ejecutada? ✗ (porque falló)
├─ ¿Es hora exacta? ✗ (pero sigue en ventana)
└─ Skip (espera minuto exacto)
│
[La red se recupera]
│
08:49 → Loop ejecuta tarea mañana
├─ Ahora está fuera del minuto exacto programado (08:47)
├─ Pero morning_executed = False
└─ En implementación actual: solo intenta en minuto exacto
NOTA: Sistema actual intenta solo en minuto aleatorio programado.
Para reintentos continuos durante toda la ventana,
necesitaría modificar lógica de verificación de tiempo.
Primera ejecución del día (sesión expirada):
│
08:47 → Scheduler ejecuta tarea mañana
├─ Llama: scraper.run(expected_action='iniciar')
│ ├─ Navega a Bizneo
│ ├─ No hay sesión válida → Login necesario
│ ├─ Rellena email + password
│ ├─ DETECTA reCAPTCHA ⚠️
│ ├─ Log: ⚠️ CAPTCHA DETECTADO
│ ├─ Muestra mensaje en consola
│ ├─ Espera resolución manual (hasta 3 min)
│ │ └─ Loop: verifica cada 2s si ya está logueado
│ ├─ Usuario resuelve CAPTCHA + hace login
│ ├─ Bot detecta login exitoso ✓
│ ├─ Guarda nueva sesión
│ ├─ Continúa: busca botón y hace clic
│ └─ Return: {success: true, action_taken: true}
└─ Log: ✓ Login completado manualmente (con CAPTCHA)
│
Siguientes ejecuciones:
│
└─ Usa sesión guardada → Sin CAPTCHA ✓
Nivel 1: Reintentos dentro del login
- Contexto: Después de hacer clic en "Entrar"
- Frecuencia: Cada 2 segundos
- Duración: Hasta 40 segundos (20 intentos)
- Verifica: Si el login fue exitoso o hay mensaje de error
Nivel 2: Reintentos de tarea completa
- Contexto: Si la tarea falla por cualquier motivo
- Frecuencia: Cada 1 minuto (siguiente ciclo del scheduler)
- Duración: Mientras esté en la ventana horaria Y no se haya ejecutado exitosamente
- Condición: Solo en el minuto aleatorio programado
| Resultado | success | action_taken | morning_executed | Comportamiento |
|---|---|---|---|---|
| Click exitoso | ✅ true | ✅ true | ✅ true | No reintenta |
| Botón incorrecto | ✅ true | ❌ false | ✅ true | No reintenta (acción correcta) |
| Error de red | ❌ false | ❌ false | ❌ false | Reintenta siguiente minuto |
| Timeout login | ❌ false | ❌ false | ❌ false | Reintenta siguiente minuto |
| Error CAPTCHA | ❌ false | ❌ false | ❌ false | Reintenta siguiente minuto |
| Botón no encontrado | ❌ false | ❌ false | ❌ false | Reintenta siguiente minuto |
Ejemplo:
- Hora programada: 08:47
- Intento a las 08:47 → Falla (red caída)
- Red se recupera a las 08:50
- Resultado: NO reintenta (espera hasta 08:47 del día siguiente)
Solución potencial (no implementada):
# En lugar de verificar minuto exacto:
if (current_time.hour == self.morning_target_time.hour and
current_time.minute == self.morning_target_time.minute):
# Podría verificar si está dentro de la ventana:
if self._is_time_in_range(current_time, morning_config['start_time'],
morning_config['end_time']):El archivo de configuración controla todos los aspectos del comportamiento del bot:
{
"credentials": {
"email": "tu.email@empresa.com",
"password": "tu_contraseña_aqui"
},
"schedule": {
"morning": {
"enabled": true,
"start_time": "08:30",
"end_time": "09:10"
},
"evening": {
"enabled": true,
"start_time": "18:00",
"end_time": "19:00"
},
"timezone": "Europe/Madrid"
},
"platform": {
"url": "https://rockinternet.bizneohr.com",
"timeout": 30000
},
"browser": {
"headless": true,
"save_state": true,
"state_file": "playwright-state/state.json",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
},
"logging": {
"enabled": true,
"log_file": "logs/chrono_bot.log",
"level": "INFO"
}
}| Parámetro | Tipo | Descripción |
|---|---|---|
email |
string | Email de acceso a Bizneo HR |
password |
string | Contraseña de acceso a Bizneo HR |
| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
morning.enabled |
boolean | true | Habilita ejecución matutina |
morning.start_time |
string | "08:30" | Inicio ventana horaria (formato HH:MM) |
morning.end_time |
string | "09:10" | Fin ventana horaria |
evening.enabled |
boolean | true | Habilita ejecución vespertina |
evening.start_time |
string | "18:00" | Inicio ventana horaria |
evening.end_time |
string | "19:00" | Fin ventana horaria |
timezone |
string | "Europe/Madrid" | Zona horaria (lista IANA) |
Nota sobre horarios aleatorios:
- El bot genera un minuto aleatorio dentro de cada ventana
- Ejemplo: ventana 08:30-09:10 → podría ejecutar a las 08:47
- Se regenera diariamente para evitar patrones
| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
url |
string | - | URL de Bizneo HR |
timeout |
integer | 30000 | Timeout para operaciones (milisegundos) |
| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
headless |
boolean | true | true: navegador invisible, false: navegador visible |
save_state |
boolean | true | Guardar sesión para evitar login repetido |
state_file |
string | "playwright-state/state.json" | Ruta del archivo de estado |
user_agent |
string | (ver config) | User-Agent del navegador |
Modos headless:
- Producción:
headless: true(invisible, menos recursos) - Debugging:
headless: false(ver navegador en acción) - CAPTCHA: Automáticamente se muestra el navegador si detecta CAPTCHA
| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
enabled |
boolean | true | Habilita logging a archivo |
log_file |
string | "logs/chrono_bot.log" | Ruta del archivo de log |
level |
string | "INFO" | Nivel: DEBUG, INFO, WARNING, ERROR |
Niveles de logging:
- DEBUG: Máximo detalle (incluye verificaciones cada minuto)
- INFO: Operaciones normales y resultados
- WARNING: Acciones saltadas, reintentos
- ERROR: Fallos y excepciones
Define los días festivos en los que el bot NO ejecutará:
{
"holidays": [
{"date": "2025-01-01", "name": "Año Nuevo"},
{"date": "2025-01-06", "name": "Reyes Magos"},
{"date": "2025-05-01", "name": "Día del Trabajador"},
{"date": "2025-08-15", "name": "Asunción de la Virgen"},
{"date": "2025-10-12", "name": "Día de la Hispanidad"},
{"date": "2025-11-01", "name": "Todos los Santos"},
{"date": "2025-12-06", "name": "Día de la Constitución"},
{"date": "2025-12-08", "name": "Inmaculada Concepción"},
{"date": "2025-12-25", "name": "Navidad"}
]
}Nota: Los fines de semana se detectan automáticamente (no es necesario añadirlos).
Para actualizar festivos:
python update_holidays.py- Python 3.8 o superior
- Windows 10/11 (para instalación como servicio)
- Conexión a internet estable
- Chromium (se instala automáticamente con Playwright)
git clone <url-del-repositorio>
cd biz_scrappython -m venv venv
venv\Scripts\activatepip install -r requirements.txtpython -m playwright install chromium-
Copia el archivo de configuración de ejemplo:
copy config.json.sample config.json
-
Edita
config.jsoncon tus credenciales y ajusta los horarios según tu necesidad:{ "credentials": { "email": "tu.email@empresa.com", "password": "tu_contraseña" }, "schedule": { "morning": { "start_time": "08:30", "end_time": "09:10" }, "evening": { "start_time": "18:00", "end_time": "19:00" } } }
Actualiza los festivos del año actual:
python update_holidays.pyO edita manualmente days/holidays.json con los festivos de tu localidad.
Para ejecutar el bot manualmente y verificar que funciona:
python run_manual.pyCaracterísticas de este modo:
- ✅ Ejecuta inmediatamente (sin esperar horarios)
- ✅ Hace clic en cualquier botón disponible (sin validar acción esperada)
- ✅ Ejecuta incluso en festivos y fines de semana
- ✅ Ideal para pruebas iniciales y verificación de configuración
- ✅ Útil para debugging con
headless: false
Casos de uso:
- Primera configuración: verificar credenciales
- Resolver CAPTCHA inicial y guardar sesión
- Debugging de problemas
- Fichaje manual cuando el servicio no está activo
Para ejecutar el bot como un proceso permanente:
python run_service.pyCaracterísticas de este modo:
- ✅ Ejecución continua en segundo plano
- ✅ Respeta horarios aleatorios configurados
- ✅ Valida acción esperada (mañana=Iniciar, tarde=Finalizar)
- ✅ No ejecuta en festivos ni fines de semana
- ✅ Sistema de reintentos automático
- ✅ Logging completo de todas las operaciones
Control del servicio:
# Detener (en la misma terminal)
Ctrl+C
# Ver logs en tiempo real (en otra terminal)
Get-Content logs\chrono_bot.log -Wait -Tail 20Para que el bot se ejecute automáticamente al iniciar Windows:
-
Abrir PowerShell como Administrador
-
Navegar al directorio del proyecto
cd C:\ruta\a\biz_scrap
-
Activar el entorno virtual
venv\Scripts\activate
-
Instalar el servicio
python install_windows_service.py install
-
Iniciar el servicio
net start ChronoBotService
# Detener el servicio
net stop ChronoBotService
# Desinstalar el servicio
python install_windows_service.py uninstall
# Ver estado en el Administrador de Servicios
services.mscEl proyecto incluye varios scripts para facilitar la gestión:
python run_manual.pyEjecuta el bot inmediatamente sin restricciones de horario.
python run_service.pyEjecuta el bot como servicio permanente respetando horarios.
python clear_session.pyElimina la sesión guardada. Útil cuando:
- Cambias de contraseña en Bizneo
- La sesión está corrupta
- Quieres forzar un nuevo login
python update_holidays.pyHerramienta interactiva para actualizar festivos del año:
- Genera festivos nacionales de España automáticamente
- Permite añadir festivos locales/autonómicos
- Muestra resumen con día de la semana
- Valida formato de fechas
python test_connection.pyVerifica que se puede acceder a Bizneo HR (si existe en el proyecto).
El bot registra todas sus operaciones en logs/chrono_bot.log con formato:
2025-10-09 08:47:23 - ChronoBot.Scheduler - INFO - 🌅 ¡Hora programada alcanzada! Ejecutando tarea de la MAÑANA
2025-10-09 08:47:28 - ChronoBot.Scraper - INFO - Botón encontrado: 'iniciar'
2025-10-09 08:47:35 - ChronoBot.Scraper - INFO - ✓ Clic realizado exitosamente en botón 'iniciar'
# Ver últimas 50 líneas
Get-Content logs\chrono_bot.log -Tail 50
# Ver logs en tiempo real
Get-Content logs\chrono_bot.log -Wait -Tail 20
# Buscar ejecuciones de hoy
Select-String -Path logs\chrono_bot.log -Pattern "2025-10-09"
# Buscar solo errores
Select-String -Path logs\chrono_bot.log -Pattern "ERROR"
# Buscar acciones completadas
Select-String -Path logs\chrono_bot.log -Pattern "Clic realizado"
# Buscar acciones saltadas
Select-String -Path logs\chrono_bot.log -Pattern "SALTANDO clic"El bot toma capturas en momentos clave guardadas en screenshots/:
| Nombre | Momento | Descripción |
|---|---|---|
before_login_YYYYMMDD_HHMMSS.png |
Antes de login | Formulario rellenado |
captcha_detected_*.png |
Si detecta CAPTCHA | Para verificar detección |
after_login_success_*.png |
Login exitoso | Confirmación de sesión |
before_click_*.png |
Antes de clic | Botón localizado |
after_click_iniciar_*.png |
Después de clic | Confirmación de entrada |
after_click_finalizar_*.png |
Después de clic | Confirmación de salida |
skipped_*.png |
Acción saltada | Botón no coincide |
*_error_*.png |
En errores | Captura del problema |
Para ver el navegador en acción y diagnosticar problemas:
- Edita
config.json:
{
"browser": {
"headless": false
},
"logging": {
"level": "DEBUG"
}
}-
Ejecuta en modo manual:
python run_manual.py
-
Observa el navegador ejecutando las acciones
-
Revisa logs con nivel DEBUG para máximo detalle
INFO - 🌅 ¡Hora programada alcanzada! Ejecutando tarea de la MAÑANA
INFO - Sesión activa detectada, omitiendo login
INFO - Botón encontrado: 'iniciar'
INFO - ✓ Procederemos a hacer clic: acción esperada 'iniciar' coincide
INFO - ✓ Clic realizado exitosamente en botón 'iniciar'
INFO - ✓ Tarea de la mañana completada: Clic realizado en botón "iniciar"
INFO - 🌅 Ejecutando tarea de la MAÑANA (esperando botón INICIAR)
INFO - Botón encontrado: 'finalizar'
WARNING - ⏭️ SALTANDO clic: se esperaba 'iniciar' pero el botón es 'finalizar'
WARNING - ⏭️ Tarea de la mañana ejecutada sin acción
Interpretación: Ya habías fichado entrada manualmente.
ERROR - Timeout durante el login: Navigation timeout of 30000 ms exceeded
WARNING - ✗ Tarea de la mañana falló: Error: Timeout, se reintentará
Interpretación: Problema temporal, reintentará en 1 minuto.
biz_scrap/
├── src/ # Código fuente principal
│ ├── __init__.py # Inicializador del paquete
│ ├── utils.py # 📦 Config, HolidayChecker, logging
│ ├── scraper.py # 🌐 BizneoScraper - Playwright automation
│ └── scheduler.py # ⏰ ChronoScheduler - Tareas programadas
│
├── days/ # Configuración de calendario
│ └── holidays.json # 📅 Días festivos (editables)
│
├── logs/ # Registro de operaciones
│ └── chrono_bot.log # 📝 Log principal (auto-generado)
│
├── screenshots/ # Capturas de debugging
│ └── *.png # 📸 Screenshots automáticos
│
├── playwright-state/ # Persistencia de sesión
│ └── state.json # 🔐 Sesión del navegador (auto-generado)
│
├── venv/ # Entorno virtual Python
│ └── ... # (no incluir en git)
│
├── run_manual.py # 🚀 Ejecución manual inmediata
├── run_service.py # 🔄 Servicio programado continuo
├── install_windows_service.py # ⚙️ Instalador servicio Windows
├── clear_session.py # 🗑️ Limpiar sesión guardada
├── update_holidays.py # 📆 Actualizar festivos
├── test_connection.py # 🔍 Verificar conectividad (opcional)
│
├── config.json # ⚠️ Configuración (NO subir a git)
├── config.json.sample # 📋 Plantilla de configuración
├── requirements.txt # 📦 Dependencias Python
├── .gitignore # 🚫 Exclusiones de git
├── README.md # 📖 Esta documentación
├── FUNCIONAMIENTO.md # 📘 Guía de funcionamiento detallada
├── INSTALL.md # 📗 Guía de instalación (si existe)
└── QUICK_START.md # ⚡ Guía rápida (si existe)
-
src/scraper.py(570 líneas): Motor principal de automatización con Playwright- Gestión de navegador y sesiones
- Login con detección de CAPTCHA
- Clic inteligente en botones
- Simulación de comportamiento humano
-
src/scheduler.py(282 líneas): Sistema de programación de tareas- Generación de horarios aleatorios
- Control de días laborables
- Sistema de reintentos
- Gestión de ejecución dual (mañana/tarde)
-
src/utils.py(125 líneas): Utilidades compartidas- Clase Config para gestión de configuración
- HolidayChecker para validación de festivos
- Setup de logging
- Creación de directorios
run_manual.py: Ejecución única sin restriccionesrun_service.py: Servicio continuo con schedulerinstall_windows_service.py: Instalador de servicio Windows
config.json: Configuración activa (credenciales, horarios, opciones)days/holidays.json: Lista de festivos del añoplaywright-state/state.json: Sesión del navegador (cookies, storage)
logs/chrono_bot.log: Registro de todas las operacionesscreenshots/*.png: Capturas de pantalla automáticas
⚠️ NUNCA subasconfig.jsona GitHub o repositorios públicos- El archivo
.gitignoreya lo excluye automáticamente - Usa contraseñas fuertes y únicas
- Revisa periódicamente los logs de acceso
Síntoma: FileNotFoundError: No se encontró el archivo de configuración: config.json
Solución:
# Copiar plantilla
copy config.json.sample config.json
# Editar con tus credenciales
notepad config.jsonSíntoma: El bot se detiene indicando que faltan credenciales
Solución: Verifica que config.json tiene email y password configurados:
{
"credentials": {
"email": "tu.email@empresa.com",
"password": "tu_contraseña_real"
}
}Solución completa:
# 1. Instalar dependencias
pip install -r requirements.txt
# 2. Instalar navegadores de Playwright
python -m playwright install chromium
# 3. Verificar instalación
python -m playwright --versionSíntoma: No encuentra módulos como schedule, pytz, etc.
Solución:
# Verifica que estás en el entorno virtual
venv\Scripts\activate
# Reinstala dependencias
pip install -r requirements.txtDiagnóstico paso a paso:
-
Ver navegador en acción:
// config.json { "browser": {"headless": false}, "logging": {"level": "DEBUG"} }
-
Ejecutar en modo manual:
python run_manual.py
-
Revisar capturas:
- Ve a
screenshots/ - Busca la última captura
before_click_*.png - ¿Se ve el botón en la página?
- Ve a
-
Verificar logs:
Select-String -Path logs\chrono_bot.log -Pattern "Botón encontrado"
Posibles causas y soluciones:
| Causa | Síntoma en logs | Solución |
|---|---|---|
| Sesión expirada | "No se pudo completar el login" | python clear_session.py + ejecutar de nuevo |
| Selector cambió | "No se encontró el botón (timeout)" | Contactar IT (selectores cambiaron en Bizneo) |
| Red lenta | "Timeout" | Aumentar timeout en config.json a 60000 |
| Página cargando | "Botón no encontrado" | Ejecutar de nuevo (red lenta) |
Síntoma: reCAPTCHA en cada ejecución, no guarda la sesión
Diagnóstico:
# ¿Existe el archivo de estado?
dir playwright-state\state.json
# ¿Tiene permisos de escritura?Soluciones:
-
Verificar configuración:
{ "browser": { "save_state": true, // ← Debe ser true "state_file": "playwright-state/state.json" } } -
Limpiar y regenerar sesión:
python clear_session.py python run_manual.py # Resuelve CAPTCHA, guarda sesión python run_service.py # Ahora usará sesión guardada
-
Verificar permisos:
- Asegúrate de que la carpeta
playwright-state/tiene permisos de escritura
- Asegúrate de que la carpeta
Síntoma: En logs aparece "se esperaba 'iniciar' pero el botón es 'finalizar'"
Interpretación: Esto es comportamiento normal, significa que:
- Mañana: Ya habías fichado entrada manualmente → El botón ya es "Finalizar"
- Tarde: Olvidaste fichar entrada → El botón aún es "Iniciar"
Acción:
- Si es mañana y ya fichaste: ✅ Todo bien, no necesita hacer nada
- Si es tarde y no fichaste entrada:
⚠️ Ficha entrada y salida manualmente
Síntoma: "Error al instalar servicio: Access denied"
Solución:
# 1. Cerrar terminal actual
# 2. Abrir PowerShell como Administrador (clic derecho > Ejecutar como administrador)
# 3. Navegar al proyecto
cd C:\ruta\a\biz_scrap
# 4. Activar entorno virtual
venv\Scripts\activate
# 5. Instalar servicio
python install_windows_service.py installDiagnóstico:
-
Ver estado del servicio:
Get-Service ChronoBotService -
Ver logs del sistema:
- Abrir
eventvwr.msc(Visor de Eventos) - Ir a: Registros de Windows → Aplicación
- Buscar eventos de "ChronoBotService"
- Abrir
-
Verificar rutas:
# El servicio debe ejecutarse desde el directorio del proyecto # Verifica que config.json existe en la ruta
Soluciones comunes:
# Detener servicio (si está corriendo)
net stop ChronoBotService
# Desinstalar servicio
python install_windows_service.py uninstall
# Reinstalar servicio
python install_windows_service.py install
# Iniciar servicio
net start ChronoBotService
# Ver estado
sc query ChronoBotServiceCausas posibles:
- Internet caído temporalmente
- VPN desconectada (si es necesaria)
- Firewall bloqueando conexión
- Bizneo HR temporalmente inaccesible
Solución:
-
Verificar conectividad:
ping rockinternet.bizneohr.com
-
El bot reintentará automáticamente cada 1 minuto durante la ventana horaria
-
Si persiste, ejecutar manualmente más tarde:
python run_manual.py
Diagnóstico:
-
Ver horarios programados:
# Buscar en logs la línea de horarios Select-String -Path logs\chrono_bot.log -Pattern "Hora aleatoria generada"
Ejemplo de salida:
🎲 Hora aleatoria generada para MAÑANA: 08:47 🎲 Hora aleatoria generada para TARDE: 18:23 -
Verificar zona horaria:
// config.json { "schedule": { "timezone": "Europe/Madrid" // ← Verifica que es correcta } }
-
Verificar día laborable:
# ¿Es festivo o fin de semana? Select-String -Path logs\chrono_bot.log -Pattern "festivo"
Nota: El bot ejecuta en un minuto aleatorio dentro de la ventana, no al inicio de la ventana.
Solución completa:
# 1. Actualizar config.json con nueva contraseña
notepad config.json
# 2. Limpiar sesión antigua
python clear_session.py
# 3. Generar nueva sesión
python run_manual.pyVerificar:
# ¿Existe la carpeta?
dir screenshots
# Si no existe, crearla
mkdir screenshots
# Ejecutar de nuevo
python run_manual.pySolución: Rotar logs periódicamente
# Hacer backup del log actual
copy logs\chrono_bot.log logs\chrono_bot_backup_$(Get-Date -Format 'yyyyMMdd').log
# Vaciar log actual
Clear-Content logs\chrono_bot.logMejor solución: Configurar rotación automática (future enhancement)
- Revisa los logs semanalmente para asegurarte de que todo funciona
- Verifica en Bizneo que los fichajes se registraron correctamente
- Mantén el PC encendido durante las ventanas horarias programadas
- Actualiza festivos al inicio de cada año:
python update_holidays.py
- Usa modo manual (
run_manual.py) para pruebas rápidas - Activa
headless: falsesolo cuando necesites ver el navegador - Cambia a nivel DEBUG temporalmente para más detalles
- Revisa capturas en
screenshots/ante problemas
- Usa el servicio Windows para máxima confiabilidad
- Configura inicio automático con el equipo
- Mantén
headless: truepara menor consumo de recursos - Revisa logs periódicamente para detectar problemas tempranos
# Backup de configuración
copy config.json config.json.backup
# Backup de festivos
copy days\holidays.json days\holidays.json.backup
# Backup de sesión (si funciona bien)
copy playwright-state\state.json playwright-state\state.json.backup- ⏰ Horarios aleatorios: El bot ejecuta en un minuto aleatorio dentro de cada ventana horaria (no al inicio)
- 🎲 Regeneración diaria: Los horarios se generan nuevos cada día para evitar patrones
- ✅ Ejecución única: Solo se ejecuta una vez por ventana horaria (mañana y tarde)
- 📅 Días laborables: No se ejecuta en fines de semana ni festivos configurados
- 🔐 Sesiones persistentes: Guarda la sesión para evitar logins y CAPTCHAs repetidos
- 🔁 Reintentos automáticos: Si falla, reintenta cada 1 minuto (solo en el minuto programado)
- 🌅 Mañana: Solo hace clic si el botón es "Iniciar" (entrada)
- 🌆 Tarde: Solo hace clic si el botón es "Finalizar" (salida)
- ⏭️ Acciones saltadas: Si el botón no coincide con lo esperado, se registra pero no hace clic
- 📝 Trazabilidad: Todas las acciones (tomadas, saltadas, fallidas) se registran en logs
- Reintentos limitados al minuto programado: Si falla a las 08:47 y la red se recupera a las 08:50, NO reintenta (espera al día siguiente)
- Requiere PC encendido: El bot solo funciona si el PC está encendido durante las ventanas horarias
- CAPTCHA manual: Si aparece reCAPTCHA, requiere resolución manual (el bot espera hasta 3 minutos)
- No detecta cambios en Bizneo: Si Bizneo cambia los selectores HTML, el bot puede dejar de funcionar (requiere actualización)
- Python 3.8+: Lenguaje de programación
- Playwright: Automatización de navegador Chromium
- schedule: Programación de tareas
- pytz: Manejo de zonas horarias
- pywin32: Integración con servicios de Windows (solo para servicio Windows)
- FUNCIONAMIENTO.md: Guía detallada del funcionamiento interno con ejemplos de logs
- config.json.sample: Plantilla con todos los parámetros disponibles
- requirements.txt: Lista completa de dependencias con versiones
- ✅ Revisa logs:
logs/chrono_bot.log - ✅ Revisa capturas:
screenshots/ - ✅ Consulta esta documentación: Especialmente sección "Solución de Problemas"
- ✅ Intenta modo manual:
python run_manual.pyconheadless: false
Si necesitas ayuda, incluye:
- 📋 Versión de Python:
python --version - 📋 Sistema operativo:
ver(Windows) - 📋 Últimas líneas del log (sin credenciales)
- 📋 Capturas de pantalla del problema
- 📋 Configuración (sin contraseña)
Para reportar problemas, sugerencias o mejoras:
- 📧 Contacta con el equipo de IT de Rock Internet
- 📝 Describe el problema con el máximo detalle posible
- 📎 Adjunta logs y capturas relevantes
Licencia: Uso interno de Rock Internet SL
Restricciones:
⚠️ Esta herramienta es para uso exclusivo de empleados de Rock Internet⚠️ No distribuir fuera de la organización⚠️ No modificar sin autorización del equipo de IT⚠️ Usar de acuerdo con las políticas de la empresa
Esta herramienta está diseñada para automatizar tareas repetitivas de fichaje horario. Es responsabilidad del usuario:
- ✅ Verificar que los fichajes se registren correctamente en Bizneo
- ✅ Tener un sistema de respaldo manual en caso de fallo
- ✅ Mantener la confidencialidad de las credenciales
- ✅ Usar conforme a las políticas empresariales y legislación vigente
El sistema NO garantiza fichajes 100% exitosos. Siempre verifica en Bizneo que el registro se completó correctamente.
- Líneas de código: ~1000 líneas (Python)
- Archivos fuente: 3 módulos principales (scraper, scheduler, utils)
- Scripts auxiliares: 5 (manual, service, install, clear, update)
- Dependencias: 5 principales (playwright, schedule, pytz, python-dateutil, pywin32)
- Documentación: README (1200+ líneas), FUNCIONAMIENTO.md
- Reintentos continuos durante toda la ventana (no solo en minuto programado)
- Rotación automática de logs (evitar crecimiento indefinido)
- Notificaciones por email en caso de fallos persistentes
- Dashboard web para monitoreo del estado
- Configuración de múltiples usuarios (para gestores)
- Tests automatizados para CI/CD
- Detección automática de cambios en selectores de Bizneo
- Modo de simulación (dry-run) sin hacer clic real
Si tienes ideas para mejorar el sistema, contacta con el equipo de IT.
ChronoBot v1.0 - Rock Internet SL © 2025 Automatización inteligente de fichaje horario con Bizneo HR