From 054b7529df28a4287d61f384b08ebe39441af0a1 Mon Sep 17 00:00:00 2001 From: marsalva Date: Thu, 19 Feb 2026 22:14:25 +0000 Subject: [PATCH] Actualizar robot.js --- robot.js | 76 +++++++++++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 42 deletions(-) diff --git a/robot.js b/robot.js index c0833d4..8bbedb5 100644 --- a/robot.js +++ b/robot.js @@ -77,17 +77,29 @@ function clasificarGremio(descripcion, gremiosActivosDB) { return null; } +// Función auxiliar para reintentar la navegación si hay fallo de red +async function gotoWithRetry(page, url, retries = 3) { + for (let i = 0; i < retries; i++) { + try { + // Usamos domcontentloaded para que no se quede colgado esperando imágenes o scripts pesados + await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45000 }); + return; // Si funciona, salimos de la función + } catch (e) { + if (i === retries - 1) throw e; // Si es el último intento, lanza el error + console.log(`⚠️ Fallo de red detectado al ir a ${url}. Reintentando (${i + 1}/${retries})...`); + await page.waitForTimeout(3000); // Esperamos 3 segundos antes de volver a intentar + } + } +} async function main() { console.log("🤖 ROBOT MODO: CIRUJANO + ASPIRADORA + CLASIFICADOR PRO"); while (true) { const client = await pool.connect(); try { - // 1. CARGAMOS LOS GREMIOS ACTUALES DE LA BASE DE DATOS const gremiosRes = await client.query("SELECT id, name FROM guilds"); const gremiosDB = gremiosRes.rows; - // ACTUALIZACIÓN DE ESTRUCTURA: Aseguramos que exista is_urgent await client.query(` DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='scraped_services' AND column_name='is_urgent') THEN @@ -101,7 +113,6 @@ async function main() { let password = Buffer.from(cred.password_hash, 'base64').toString('utf-8'); console.log(`\n🔄 Procesando ${cred.provider.toUpperCase()}...`); - // 2. PASAMOS LOS GREMIOS AL SCRAPER if (cred.provider === 'multiasistencia') { await runMultiasistencia(cred.owner_id, cred.username, password, gremiosDB); } else if (cred.provider === 'homeserve') { @@ -119,56 +130,49 @@ async function main() { } // ========================================== -// 🏥 MULTIASISTENCIA (CON INTELIGENCIA Y PAGINACIÓN REAL) +// 🏥 MULTIASISTENCIA (CON REINTENTOS ANTI-CAÍDAS) // ========================================== async function runMultiasistencia(ownerId, user, pass, gremiosDB) { - // ARGUMENTOS DE SEGURIDAD CONTRA CRASHEOS EN LINUX/DOCKER const browser = await chromium.launch({ headless: HEADLESS, args: [ '--no-sandbox', '--disable-setuid-sandbox', - '--disable-dev-shm-usage', // Evita que se quede sin memoria compartida (causa del SIGSEGV) + '--disable-dev-shm-usage', '--disable-gpu' ] }); - const context = await browser.newContext(); const page = await context.newPage(); try { - await page.goto('https://web.multiasistencia.com/w3multi/acceso.php', { timeout: 60000 }); + // INICIO DE SESIÓN CON REINTENTOS + await gotoWithRetry(page, 'https://web.multiasistencia.com/w3multi/acceso.php'); + await page.fill('input[name="usuario"]', user); await page.fill('input[type="password"]', pass); await page.click('input[type="submit"]'); await page.waitForTimeout(4000); - await page.goto('https://web.multiasistencia.com/w3multi/frepasos_new.php?refresh=1'); + + // ENTRAR AL BUZÓN CON REINTENTOS + await gotoWithRetry(page, 'https://web.multiasistencia.com/w3multi/frepasos_new.php?refresh=1'); await page.waitForTimeout(3000); - // --- NUEVO: FORZAR RECARGA DE FORMA SEGURA (SIN HACER CLIC FÍSICO) --- console.log("🔄 [Multi] Forzando recarga segura mediante script interno..."); try { await page.evaluate(() => { - // Llamamos a la función nativa de la web para recargar sin reventar el motor gráfico - if (typeof refrescar === 'function') { - refrescar(); - } + if (typeof refrescar === 'function') refrescar(); }); - // Esperamos a que la red deje de cargar datos await page.waitForLoadState('networkidle'); await page.waitForTimeout(3000); - } catch (e) { - console.log("⚠️ [Multi] No se pudo ejecutar la recarga (puede que ya estuvieran cargados)."); - } - // ---------------------------------------------------------- + } catch (e) {} - // --- BUCLE DE PAGINACIÓN INTELIGENTE --- + // --- BUCLE DE PAGINACIÓN --- let todosExpedientes = new Set(); let paginaActual = 1; while (true) { console.log(`📄 [Multi] Escaneando página ${paginaActual}...`); - // 1. Extraer expedientes de la página actual const expedientesPagina = await page.evaluate(() => { const links = Array.from(document.querySelectorAll('a[href*="reparacion="]')); return links.map(a => a.href.match(/reparacion=(\d+)/)?.[1]).filter(Boolean); @@ -176,15 +180,10 @@ async function runMultiasistencia(ownerId, user, pass, gremiosDB) { expedientesPagina.forEach(ref => todosExpedientes.add(ref)); - // 2. Buscar el botón "Página siguiente" const hasNextPage = await page.evaluate(() => { const links = Array.from(document.querySelectorAll('a.lnkheader')); const nextBtn = links.find(a => a.innerText.trim() === 'Página siguiente'); - - if (nextBtn) { - nextBtn.click(); - return true; - } + if (nextBtn) { nextBtn.click(); return true; } return false; }); @@ -192,7 +191,6 @@ async function runMultiasistencia(ownerId, user, pass, gremiosDB) { await page.waitForLoadState('networkidle'); await page.waitForTimeout(2500); paginaActual++; - if(paginaActual > 15) { console.log("⚠️ [Multi] Límite de 15 páginas alcanzado por seguridad."); break; @@ -206,14 +204,12 @@ async function runMultiasistencia(ownerId, user, pass, gremiosDB) { const expedientes = Array.from(todosExpedientes); console.log(`✅ [Multi] Total expedientes detectados: ${expedientes.length}`); - // --- ARCHIVADO --- if (expedientes.length > 0) { await syncAndArchive(ownerId, 'multiasistencia', expedientes); } - // --- EXTRACCIÓN DE DATOS --- for (const ref of expedientes) { - await page.goto(`https://web.multiasistencia.com/w3multi/repasos1.php?reparacion=${ref}`, { waitUntil: 'domcontentloaded' }); + await gotoWithRetry(page, `https://web.multiasistencia.com/w3multi/repasos1.php?reparacion=${ref}`); await page.waitForTimeout(1500); let scrapData = null; @@ -274,10 +270,9 @@ async function runMultiasistencia(ownerId, user, pass, gremiosDB) { } // ========================================== -// 🧹 HOMESERVE (CON INTELIGENCIA) +// 🧹 HOMESERVE // ========================================== async function runHomeserve(ownerId, user, pass, gremiosDB) { - // MISMOS ARGUMENTOS DE SEGURIDAD AQUÍ PARA EVITAR CRASHES const browser = await chromium.launch({ headless: HEADLESS, args: [ @@ -290,7 +285,7 @@ async function runHomeserve(ownerId, user, pass, gremiosDB) { const page = await browser.newPage(); try { console.log("🌍 [HomeServe] Entrando..."); - await page.goto('https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=PROF_PASS', { timeout: 60000 }); + await gotoWithRetry(page, 'https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=PROF_PASS'); if (await page.isVisible('input[name="CODIGO"]')) { await page.fill('input[name="CODIGO"]', user); @@ -299,7 +294,7 @@ async function runHomeserve(ownerId, user, pass, gremiosDB) { await page.waitForTimeout(5000); } - await page.goto('https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=lista_servicios_total'); + await gotoWithRetry(page, 'https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=lista_servicios_total'); await page.waitForTimeout(3000); const refs = await page.evaluate(() => { @@ -319,7 +314,7 @@ async function runHomeserve(ownerId, user, pass, gremiosDB) { console.log(`🔍 [HomeServe] ${refs.length} expedientes detectados.`); for (const ref of refs) { - await page.goto(`https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=ver_servicioencurso&Servicio=${ref}`); + await gotoWithRetry(page, `https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=ver_servicioencurso&Servicio=${ref}`); await page.waitForTimeout(2000); const scrapData = await page.evaluate(() => { @@ -364,7 +359,6 @@ async function runHomeserve(ownerId, user, pass, gremiosDB) { finally { await browser.close(); } } -// --- NUEVA FUNCIÓN: SINCRONIZACIÓN Y ARCHIVADO --- async function syncAndArchive(ownerId, provider, currentWebRefs) { const client = await pool.connect(); try { @@ -399,11 +393,9 @@ async function syncAndArchive(ownerId, provider, currentWebRefs) { async function saveServiceToDB(ownerId, provider, ref, data) { console.log(`💾 Guardando/Actualizando ${provider.toUpperCase()} ${ref}...`); - // CORRECCIÓN URGENCIA: Miramos en el JSON y convertimos a booleano real -const isUrgent = (data['Urgente'] && (data['Urgente'].toLowerCase().trim() === 'sí' || data['Urgente'].toLowerCase().trim() === 'si')) ? true : false; - - - // Al añadir is_urgent en la consulta, sincronizamos la columna física de la base de datos + // Aquí está la solución al problema del tilde ("sí" vs "si") que te comenté antes + const isUrgent = (data['Urgente'] && (data['Urgente'].toLowerCase().trim() === 'sí' || data['Urgente'].toLowerCase().trim() === 'si')) ? true : false; + await pool.query(` INSERT INTO scraped_services (owner_id, provider, service_ref, raw_data, status, is_urgent) VALUES ($1, $2, $3, $4, 'pending', $5)