From f49bc29b1c65b4621c06cec5bdbeecf9d67de9e0 Mon Sep 17 00:00:00 2001 From: marsalva Date: Fri, 20 Mar 2026 22:12:45 +0000 Subject: [PATCH] =?UTF-8?q?A=C3=B1adir=20robot=5Fauxiliar.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robot_auxiliar.js | 146 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 robot_auxiliar.js diff --git a/robot_auxiliar.js b/robot_auxiliar.js new file mode 100644 index 0000000..f2d9fbf --- /dev/null +++ b/robot_auxiliar.js @@ -0,0 +1,146 @@ +import { chromium } from 'playwright'; +import pg from 'pg'; + +const { DATABASE_URL } = process.env; +if (!DATABASE_URL) { console.error("❌ Error: No hay DATABASE_URL."); process.exit(1); } + +const pool = new pg.Pool({ connectionString: DATABASE_URL, ssl: false }); +const HEADLESS = true; + +// Función auxiliar para reintentar la navegación +async function gotoWithRetry(page, url, retries = 3) { + for (let i = 0; i < retries; i++) { + try { + await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45000 }); + return; + } catch (e) { + if (i === retries - 1) throw e; + console.log(`⚠️ Fallo de red. Reintentando (${i + 1}/${retries})...`); + await page.waitForTimeout(3000); + } + } +} + +async function main() { + console.log("🤖 INICIANDO ROBOT AUXILIAR (Buscador de Detalles)"); + + while (true) { + const client = await pool.connect(); + try { + // Obtenemos las credenciales activas + const res = await client.query("SELECT * FROM provider_credentials WHERE status = 'active' AND provider = 'homeserve'"); + + for (const cred of res.rows) { + let password = Buffer.from(cred.password_hash, 'base64').toString('utf-8'); + console.log(`\n🔄 [AUXILIAR] Procesando HOMESERVE para owner_id: ${cred.owner_id}...`); + await runHomeserveAux(cred.owner_id, cred.username, password); + } + } catch (e) { + console.error("❌ Error ciclo Auxiliar:", e.message); + } finally { + client.release(); + } + + console.log("\n💤 [AUXILIAR] Durmiendo 10 minutos..."); + await new Promise(r => setTimeout(r, 10 * 60 * 1000)); + } +} + +// ========================================== +// 🧹 HOMESERVE AUXILIAR (Caza-Iconos y Detalles) +// ========================================== +async function runHomeserveAux(ownerId, user, pass) { + const browser = await chromium.launch({ + headless: HEADLESS, + args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'] + }); + const page = await browser.newPage(); + + try { + console.log("🌍 [HomeServe AUX] Iniciando sesión..."); + 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); + await page.fill('input[type="password"]', pass); + await page.keyboard.press('Enter'); + await page.waitForTimeout(5000); + } + + // Vamos a la lista total de servicios + await gotoWithRetry(page, 'https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=lista_servicios_total'); + await page.waitForTimeout(3000); + + console.log("🔍 [HomeServe AUX] Escaneando iconos (Candados y Ojos)..."); + + // 🧠 LA MAGIA: Extraemos la referencia y verificamos si hay imágenes específicas junto a ella + const serviciosExtraidos = await page.evaluate(() => { + const results = []; + // Buscamos todas las filas de la tabla de expedientes + const rows = Array.from(document.querySelectorAll('table[bgcolor="#FCF4D6"] tr')); + + rows.forEach(tr => { + const firstTd = tr.querySelector('td'); + if (!firstTd) return; + + // Intentamos cazar el número de expediente (empieza por 15 y tiene 8 cifras) + const textMatch = firstTd.innerText.trim().match(/^15\d{6}$/); + const aMatch = firstTd.querySelector('a') ? firstTd.querySelector('a').innerText.trim().match(/^15\d{6}$/) : null; + + const ref = textMatch ? textMatch[0] : (aMatch ? aMatch[0] : null); + + if (ref) { + // Miramos si dentro de esa celda existe la imagen del candado o de los ojos + const hasLock = firstTd.querySelector('img[src*="candado.gif"]') !== null; + const hasEyes = firstTd.querySelector('img[src*="ojos.gif"]') !== null; + + results.push({ ref, hasLock, hasEyes }); + } + }); + return results; + }); + + console.log(`✅ [HomeServe AUX] Se han escaneado ${serviciosExtraidos.length} expedientes.`); + + // Guardamos los datos en la base de datos de forma segura + for (const data of serviciosExtraidos) { + await saveIconStatusToDB(ownerId, 'homeserve', data.ref, data.hasLock, data.hasEyes); + } + + console.log("🏁 [HomeServe AUX] Tarea completada."); + + } catch (e) { + console.error("❌ [HomeServe AUX] Error:", e.message); + } finally { + await browser.close(); + } +} + +// ========================================== +// 💾 GUARDADO SEGURO EN BD (Inyección en raw_data) +// ========================================== +async function saveIconStatusToDB(ownerId, provider, ref, hasLock, hasEyes) { + try { + // Actualizamos inyectando los valores booleanos dentro del JSON raw_data. + // Solo lo hacemos si el expediente existe. + await pool.query(` + UPDATE scraped_services + SET raw_data = jsonb_set( + jsonb_set(COALESCE(raw_data, '{}'::jsonb), '{has_lock}', $1::jsonb), + '{has_eyes}', $2::jsonb + ) + WHERE owner_id = $3 AND provider = $4 AND service_ref = $5 + `, [ + hasLock ? 'true' : 'false', + hasEyes ? 'true' : 'false', + ownerId, + provider, + ref + ]); + + } catch (e) { + console.error(`❌ Error inyectando iconos en ${ref}:`, e.message); + } +} + +main(); \ No newline at end of file