from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.support.ui import WebDriverWait from selenium.common.exceptions import TimeoutException, WebDriverException from dotenv import load_dotenv from email.message import EmailMessage from urllib.parse import urlparse import time import os import smtplib import requests # Umbrales por red (en segundos) UMBRAL_POR_RED = { "3G": 4, "4G": 3, "WiFi": 2, "sin_limitaciones": 2 } # Perfiles de red con latencia, descarga, subida y tipo conexión PERFILES_RED = { "3G": {"latency": 150, "download": 3, "upload": 3, "type": "cellular3g"}, "4G": {"latency": 50, "download": 40, "upload": 40, "type": "cellular4g"}, "WiFi": {"latency": 20, "download": 150, "upload": 150, "type": "wifi"}, "sin_limitaciones": {"latency": 0, "download": 0, "upload": 0, "type": "sin_limitaciones"} } URL_TEST = "https://www.gugler.com.ar" logs = [] resumen_tabla = [] def enviar_email(contenido, asunto="Reporte de performance web - Selenium", destinatario="exequiel84@gmail.com"): load_dotenv() remitente = os.getenv("EMAIL") password = os.getenv("PASSWORD") if not remitente or not password: log("❌ ERROR: EMAIL o PASSWORD no definidos en el archivo .env") return if not destinatario: destinatario = remitente msg = EmailMessage() msg['Subject'] = asunto msg['From'] = remitente msg['To'] = destinatario msg.set_content(contenido) try: log("\n📤 Enviando correo ...") with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp: smtp.login(remitente, password) smtp.send_message(msg) log("✅ Correo enviado exitosamente.") except Exception as e: log(f"❌ Error al enviar el correo: {e}") def log(msg): print(msg) logs.append(msg) def limpiar_cache(driver): driver.execute_cdp_cmd('Network.clearBrowserCache', {}) driver.execute_cdp_cmd('Network.clearBrowserCookies', {}) log("🧹 Caché y cookies limpiadas.") time.sleep(4) def emular_red(driver, latencia_ms, descarga_mbps, subida_mbps, tipo_conexion): if tipo_conexion == "sin_limitaciones": driver.execute_cdp_cmd("Network.disable", {}) return driver.execute_cdp_cmd("Network.enable", {}) driver.execute_cdp_cmd("Network.emulateNetworkConditions", { "offline": False, "latency": latencia_ms, "downloadThroughput": descarga_mbps * 1_000_000, "uploadThroughput": subida_mbps * 1_000_000, "connectionType": tipo_conexion, }) def medir_carga(driver, umbral_total, nombre_red): try: driver.execute_cdp_cmd("Network.setExtraHTTPHeaders", {"headers": {"Cache-Control": "no-store"}}) driver.get(URL_TEST) WebDriverWait(driver, 60).until(lambda d: d.execute_script("return document.readyState") == "complete") WebDriverWait(driver, 10).until(lambda d: d.execute_script( "return window.performance.getEntriesByType('resource').filter(e => e.responseEnd == 0).length == 0")) timing = driver.execute_script("return window.performance.timing") tiempo_total = (timing.get('loadEventEnd', 0) - timing.get('navigationStart', 0)) / 1000 log(f"\n⏱ Tiempo de carga total: {tiempo_total:.2f} s") log("✅ Dentro del umbral total" if tiempo_total <= umbral_total else f"⚠️ Superó el umbral total de {umbral_total}s") recursos = driver.execute_script("return window.performance.getEntriesByType('resource')") recursos_rotos = 0 url_base = urlparse(URL_TEST).netloc recursos_filtrados = [] for r in recursos: url_recurso = r.get('name', '') host_recurso = urlparse(url_recurso).netloc recurso_url = urlparse(url_recurso).path if host_recurso == url_base else url_recurso recursos_filtrados.append({ "duracion": r.get('duration', 0), "url": recurso_url, "tipo": r.get('initiatorType', 'desconocido') }) log(f"\n📦 {len(recursos)} Recursos individuales (ordenados por duración):") for r in sorted(recursos_filtrados, key=lambda x: x['duracion'], reverse=True): dur_segundos = r['duracion'] / 1000 url_recurso = r['url'] if url_recurso.startswith("/"): url_completa = URL_TEST.rstrip("/") + url_recurso elif url_recurso.startswith("http"): url_completa = url_recurso else: continue try: resp = requests.head(url_completa, timeout=5, allow_redirects=True) status = resp.status_code ok = status in [200, 304] except Exception: status = "ERR" ok = False if not ok: recursos_rotos += 1 icono = "✅" if ok and dur_segundos <= 1 else "⚠️" estado_http = f"HTTP {status}" log(f" {icono} {dur_segundos:.2f}s [{r['tipo']}] - {url_recurso} → {estado_http}") resumen_tabla.append({ "red": nombre_red, "tiempo_total": tiempo_total, "umbral": umbral_total, "recursos": len(recursos), "rotos": recursos_rotos, "supero_umbral": tiempo_total > umbral_total }) except TimeoutException: log("⏰ Timeout esperando que el DOM termine de cargar.") except WebDriverException as e: log(f"❌ Error durante la prueba: {e}") def mostrar_tabla_resumen(): log("\n📊 Tabla resumen final:") header = f"{'Red':<25} {'Tiempo (s)':<12} {'Umbral (s)':<12} {'Recursos':<10} {'Rotos':<8} {'Estado'}" log(header) log("-" * len(header)) for fila in resumen_tabla: estado = "⚠️ Lento" if fila["supero_umbral"] else "✅ Ok" log(f"{fila['red']:<25} {fila['tiempo_total']:<12.2f} {fila['umbral']:<12} {fila['recursos']:<10} {fila['rotos']:<8} {estado}") def main(): options = Options() # options.add_argument("--headless") options.add_argument("--incognito") options.add_argument("--disable-gpu") options.add_argument("--enable-logging") driver = webdriver.Remote( command_executor='http://localhost:4444/wd/hub', options=options ) driver.set_page_load_timeout(60) try: for nombre_red, params in PERFILES_RED.items(): if nombre_red in UMBRAL_POR_RED: log(f"\n=== 🌐 Probando conexión: {nombre_red} ===") try: driver.get("https://www.google.com") limpiar_cache(driver) emular_red(driver, params['latency'], params['download'], params['upload'], params['type']) medir_carga(driver, UMBRAL_POR_RED[nombre_red], nombre_red) except Exception as e: log(f"❌ Error durante la prueba con {nombre_red}: {str(e)}") mostrar_tabla_resumen() finally: driver.quit() if __name__ == "__main__": main() contenido_email = "\n".join(logs) enviar_email(contenido_email)