from fastapi import FastAPI from contextlib import asynccontextmanager from database import Base, engine from routes import router from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.triggers.cron import CronTrigger from webscrapper import search_from_keywords_file, search_indice import csv from datetime import datetime, time import logging LOG_FILE = "app.log" logging.basicConfig( filename=LOG_FILE, # Archivo de logs level=logging.INFO, # Nivel de logging (DEBUG, INFO, WARNING, ERROR, CRITICAL) format="%(asctime)s - %(levelname)s - %(message)s", # Formato de los logs ) # Crear las tablas en MySQL si no existen Base.metadata.create_all(bind=engine) # Configurar el scheduler (solo una instancia) scheduler = BackgroundScheduler() # Agregar tareas fijas scheduler.add_job(search_from_keywords_file, "cron", hour=11, minute=0, day="*") # Ejecutar a las 11:00 AM scheduler.add_job(search_from_keywords_file, "cron", hour=18, minute=0, day="*") # Ejecutar a las 6:00 PM def cargar_tareas_desde_csv(indices): """Lee el CSV y agrega tareas al scheduler""" logging.info("📌 Cargando tareas desde CSV...") try: with open(indices, mode='r', encoding='utf-8') as file: reader = csv.reader(file, delimiter=';') for row in reader: logging.info(f"📌 Leyendo fila: {row}") if len(row) < 4: logging.warning(f"❌ Línea incorrecta en CSV: {row}") continue url, nombre, horaInicio, horaFin = row try: horaInicio = datetime.strptime(horaInicio.strip(), "%H:%M").time() horaFin = datetime.strptime(horaFin.strip(), "%H:%M").time() except ValueError: logging.error(f"❌ Formato de hora incorrecto en línea: {row}") continue obj = {"url": url.strip(), "nombre": nombre.strip(), "horaInicio": horaInicio, "horaFin": horaFin} # Agregar tareas para cada hora en el rango for hora in range(horaInicio.hour, horaFin.hour + 1): scheduler.add_job( search_indice, trigger=CronTrigger(hour=hora, minute=0, day_of_week="0-4"), args=[obj] ) logging.info(f"✅ Tarea agregada para {nombre} a las {hora}:00") logging.info("✅ Todas las tareas fueron programadas.") except Exception as e: logging.error(f"❌ Error al leer el archivo CSV: {e}") @asynccontextmanager async def lifespan(app: FastAPI): scheduler.start(paused=False) yield scheduler.shutdown() # Inicializar FastAPI con lifespan app = FastAPI(lifespan=lifespan) # Incluir rutas app.include_router(router) # Cargar tareas desde el CSV al iniciar cargar_tareas_desde_csv("/app/indices.csv")