Actualizar robot.js
This commit is contained in:
72
robot.js
72
robot.js
@@ -77,17 +77,29 @@ function clasificarGremio(descripcion, gremiosActivosDB) {
|
|||||||
return null;
|
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() {
|
async function main() {
|
||||||
console.log("🤖 ROBOT MODO: CIRUJANO + ASPIRADORA + CLASIFICADOR PRO");
|
console.log("🤖 ROBOT MODO: CIRUJANO + ASPIRADORA + CLASIFICADOR PRO");
|
||||||
while (true) {
|
while (true) {
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
try {
|
try {
|
||||||
// 1. CARGAMOS LOS GREMIOS ACTUALES DE LA BASE DE DATOS
|
|
||||||
const gremiosRes = await client.query("SELECT id, name FROM guilds");
|
const gremiosRes = await client.query("SELECT id, name FROM guilds");
|
||||||
const gremiosDB = gremiosRes.rows;
|
const gremiosDB = gremiosRes.rows;
|
||||||
|
|
||||||
// ACTUALIZACIÓN DE ESTRUCTURA: Aseguramos que exista is_urgent
|
|
||||||
await client.query(`
|
await client.query(`
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='scraped_services' AND column_name='is_urgent') THEN
|
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');
|
let password = Buffer.from(cred.password_hash, 'base64').toString('utf-8');
|
||||||
console.log(`\n🔄 Procesando ${cred.provider.toUpperCase()}...`);
|
console.log(`\n🔄 Procesando ${cred.provider.toUpperCase()}...`);
|
||||||
|
|
||||||
// 2. PASAMOS LOS GREMIOS AL SCRAPER
|
|
||||||
if (cred.provider === 'multiasistencia') {
|
if (cred.provider === 'multiasistencia') {
|
||||||
await runMultiasistencia(cred.owner_id, cred.username, password, gremiosDB);
|
await runMultiasistencia(cred.owner_id, cred.username, password, gremiosDB);
|
||||||
} else if (cred.provider === 'homeserve') {
|
} 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) {
|
async function runMultiasistencia(ownerId, user, pass, gremiosDB) {
|
||||||
// ARGUMENTOS DE SEGURIDAD CONTRA CRASHEOS EN LINUX/DOCKER
|
|
||||||
const browser = await chromium.launch({
|
const browser = await chromium.launch({
|
||||||
headless: HEADLESS,
|
headless: HEADLESS,
|
||||||
args: [
|
args: [
|
||||||
'--no-sandbox',
|
'--no-sandbox',
|
||||||
'--disable-setuid-sandbox',
|
'--disable-setuid-sandbox',
|
||||||
'--disable-dev-shm-usage', // Evita que se quede sin memoria compartida (causa del SIGSEGV)
|
'--disable-dev-shm-usage',
|
||||||
'--disable-gpu'
|
'--disable-gpu'
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
const context = await browser.newContext();
|
const context = await browser.newContext();
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
try {
|
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[name="usuario"]', user);
|
||||||
await page.fill('input[type="password"]', pass);
|
await page.fill('input[type="password"]', pass);
|
||||||
await page.click('input[type="submit"]');
|
await page.click('input[type="submit"]');
|
||||||
await page.waitForTimeout(4000);
|
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);
|
await page.waitForTimeout(3000);
|
||||||
|
|
||||||
// --- NUEVO: FORZAR RECARGA DE FORMA SEGURA (SIN HACER CLIC FÍSICO) ---
|
|
||||||
console.log("🔄 [Multi] Forzando recarga segura mediante script interno...");
|
console.log("🔄 [Multi] Forzando recarga segura mediante script interno...");
|
||||||
try {
|
try {
|
||||||
await page.evaluate(() => {
|
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.waitForLoadState('networkidle');
|
||||||
await page.waitForTimeout(3000);
|
await page.waitForTimeout(3000);
|
||||||
} catch (e) {
|
} catch (e) {}
|
||||||
console.log("⚠️ [Multi] No se pudo ejecutar la recarga (puede que ya estuvieran cargados).");
|
|
||||||
}
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
|
|
||||||
// --- BUCLE DE PAGINACIÓN INTELIGENTE ---
|
// --- BUCLE DE PAGINACIÓN ---
|
||||||
let todosExpedientes = new Set();
|
let todosExpedientes = new Set();
|
||||||
let paginaActual = 1;
|
let paginaActual = 1;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
console.log(`📄 [Multi] Escaneando página ${paginaActual}...`);
|
console.log(`📄 [Multi] Escaneando página ${paginaActual}...`);
|
||||||
|
|
||||||
// 1. Extraer expedientes de la página actual
|
|
||||||
const expedientesPagina = await page.evaluate(() => {
|
const expedientesPagina = await page.evaluate(() => {
|
||||||
const links = Array.from(document.querySelectorAll('a[href*="reparacion="]'));
|
const links = Array.from(document.querySelectorAll('a[href*="reparacion="]'));
|
||||||
return links.map(a => a.href.match(/reparacion=(\d+)/)?.[1]).filter(Boolean);
|
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));
|
expedientesPagina.forEach(ref => todosExpedientes.add(ref));
|
||||||
|
|
||||||
// 2. Buscar el botón "Página siguiente"
|
|
||||||
const hasNextPage = await page.evaluate(() => {
|
const hasNextPage = await page.evaluate(() => {
|
||||||
const links = Array.from(document.querySelectorAll('a.lnkheader'));
|
const links = Array.from(document.querySelectorAll('a.lnkheader'));
|
||||||
const nextBtn = links.find(a => a.innerText.trim() === 'Página siguiente');
|
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;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -192,7 +191,6 @@ async function runMultiasistencia(ownerId, user, pass, gremiosDB) {
|
|||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
await page.waitForTimeout(2500);
|
await page.waitForTimeout(2500);
|
||||||
paginaActual++;
|
paginaActual++;
|
||||||
|
|
||||||
if(paginaActual > 15) {
|
if(paginaActual > 15) {
|
||||||
console.log("⚠️ [Multi] Límite de 15 páginas alcanzado por seguridad.");
|
console.log("⚠️ [Multi] Límite de 15 páginas alcanzado por seguridad.");
|
||||||
break;
|
break;
|
||||||
@@ -206,14 +204,12 @@ async function runMultiasistencia(ownerId, user, pass, gremiosDB) {
|
|||||||
const expedientes = Array.from(todosExpedientes);
|
const expedientes = Array.from(todosExpedientes);
|
||||||
console.log(`✅ [Multi] Total expedientes detectados: ${expedientes.length}`);
|
console.log(`✅ [Multi] Total expedientes detectados: ${expedientes.length}`);
|
||||||
|
|
||||||
// --- ARCHIVADO ---
|
|
||||||
if (expedientes.length > 0) {
|
if (expedientes.length > 0) {
|
||||||
await syncAndArchive(ownerId, 'multiasistencia', expedientes);
|
await syncAndArchive(ownerId, 'multiasistencia', expedientes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- EXTRACCIÓN DE DATOS ---
|
|
||||||
for (const ref of expedientes) {
|
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);
|
await page.waitForTimeout(1500);
|
||||||
let scrapData = null;
|
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) {
|
async function runHomeserve(ownerId, user, pass, gremiosDB) {
|
||||||
// MISMOS ARGUMENTOS DE SEGURIDAD AQUÍ PARA EVITAR CRASHES
|
|
||||||
const browser = await chromium.launch({
|
const browser = await chromium.launch({
|
||||||
headless: HEADLESS,
|
headless: HEADLESS,
|
||||||
args: [
|
args: [
|
||||||
@@ -290,7 +285,7 @@ async function runHomeserve(ownerId, user, pass, gremiosDB) {
|
|||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
try {
|
try {
|
||||||
console.log("🌍 [HomeServe] Entrando...");
|
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"]')) {
|
if (await page.isVisible('input[name="CODIGO"]')) {
|
||||||
await page.fill('input[name="CODIGO"]', user);
|
await page.fill('input[name="CODIGO"]', user);
|
||||||
@@ -299,7 +294,7 @@ async function runHomeserve(ownerId, user, pass, gremiosDB) {
|
|||||||
await page.waitForTimeout(5000);
|
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);
|
await page.waitForTimeout(3000);
|
||||||
|
|
||||||
const refs = await page.evaluate(() => {
|
const refs = await page.evaluate(() => {
|
||||||
@@ -319,7 +314,7 @@ async function runHomeserve(ownerId, user, pass, gremiosDB) {
|
|||||||
console.log(`🔍 [HomeServe] ${refs.length} expedientes detectados.`);
|
console.log(`🔍 [HomeServe] ${refs.length} expedientes detectados.`);
|
||||||
|
|
||||||
for (const ref of refs) {
|
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);
|
await page.waitForTimeout(2000);
|
||||||
|
|
||||||
const scrapData = await page.evaluate(() => {
|
const scrapData = await page.evaluate(() => {
|
||||||
@@ -364,7 +359,6 @@ async function runHomeserve(ownerId, user, pass, gremiosDB) {
|
|||||||
finally { await browser.close(); }
|
finally { await browser.close(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- NUEVA FUNCIÓN: SINCRONIZACIÓN Y ARCHIVADO ---
|
|
||||||
async function syncAndArchive(ownerId, provider, currentWebRefs) {
|
async function syncAndArchive(ownerId, provider, currentWebRefs) {
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
try {
|
try {
|
||||||
@@ -399,11 +393,9 @@ async function syncAndArchive(ownerId, provider, currentWebRefs) {
|
|||||||
async function saveServiceToDB(ownerId, provider, ref, data) {
|
async function saveServiceToDB(ownerId, provider, ref, data) {
|
||||||
console.log(`💾 Guardando/Actualizando ${provider.toUpperCase()} ${ref}...`);
|
console.log(`💾 Guardando/Actualizando ${provider.toUpperCase()} ${ref}...`);
|
||||||
|
|
||||||
// CORRECCIÓN URGENCIA: Miramos en el JSON y convertimos a booleano real
|
// 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;
|
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
|
|
||||||
await pool.query(`
|
await pool.query(`
|
||||||
INSERT INTO scraped_services (owner_id, provider, service_ref, raw_data, status, is_urgent)
|
INSERT INTO scraped_services (owner_id, provider, service_ref, raw_data, status, is_urgent)
|
||||||
VALUES ($1, $2, $3, $4, 'pending', $5)
|
VALUES ($1, $2, $3, $4, 'pending', $5)
|
||||||
|
|||||||
Reference in New Issue
Block a user