Ajustes
This commit is contained in:
@@ -0,0 +1,422 @@
|
||||
import path from 'path';
|
||||
import { exec } from 'child_process';
|
||||
import puppeteer from 'puppeteer-core';
|
||||
import fetch from 'node-fetch';
|
||||
import { google } from 'googleapis';
|
||||
import { createWriteStream } from 'fs';
|
||||
import fs from 'fs';
|
||||
import { app } from 'electron';
|
||||
|
||||
console.log(app.getAppPath());
|
||||
|
||||
let url_cred = app.getAppPath().replace('app.asar', '');
|
||||
url_cred = url_cred + '\\credenciales.json';
|
||||
console.log(url_cred);
|
||||
|
||||
// Configuración
|
||||
const CONFIG = {
|
||||
PATHS: {
|
||||
BASE_DIR: 'C:\\Users\\Drackxus\\Documents\\NODE\\migracion',
|
||||
ARCHIVOS: 'C:\\Users\\Drackxus\\Documents\\NODE\\migracion\\archivos',
|
||||
CREDENTIALS: url_cred
|
||||
},
|
||||
DRIVE: {
|
||||
FOLDER_ID: '1bjEaxLFkv4toUt0SeUz_HqrvIWAI2Xv5',
|
||||
SCOPES: [
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
'https://www.googleapis.com/auth/spreadsheets'
|
||||
]
|
||||
},
|
||||
PLATFORMS: {
|
||||
USCIS: {
|
||||
URL: 'https://egov.uscis.gov/es',
|
||||
TYPE: 'uscis'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Inicialización de Google APIs
|
||||
const auth = new google.auth.GoogleAuth({
|
||||
keyFile: CONFIG.PATHS.CREDENTIALS,
|
||||
scopes: CONFIG.DRIVE.SCOPES
|
||||
});
|
||||
|
||||
const sheets = google.sheets({ version: 'v4', auth });
|
||||
const drive = google.drive({ version: 'v3', auth });
|
||||
|
||||
let browser; // Variable global para el navegador
|
||||
|
||||
// Funciones de Google Sheets
|
||||
async function listarArchivosEnCarpeta(folderId) {
|
||||
const res = await drive.files.list({
|
||||
q: `'${folderId}' in parents and mimeType='application/vnd.google-apps.spreadsheet' and name='base_uscis'`,
|
||||
fields: '*'
|
||||
});
|
||||
|
||||
console.log(`${res.data.files.length} archivo(s) encontrados con el nombre "base_uscis"`);
|
||||
|
||||
return res.data.files;
|
||||
}
|
||||
|
||||
|
||||
async function obtenerDatosHoja(spreadsheetId) {
|
||||
const response = await sheets.spreadsheets.values.get({
|
||||
spreadsheetId,
|
||||
range: 'A:H', // Ajusta el rango según tus necesidades
|
||||
});
|
||||
return response.data.values;
|
||||
}
|
||||
|
||||
async function actualizarCelda(spreadsheetId, range, values) {
|
||||
try {
|
||||
await sheets.spreadsheets.values.update({
|
||||
spreadsheetId,
|
||||
range,
|
||||
valueInputOption: 'USER_ENTERED',
|
||||
requestBody: {
|
||||
values: [values]
|
||||
}
|
||||
});
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
} catch (error) {
|
||||
console.error('Error al actualizar celda:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Funciones de manejo del navegador
|
||||
async function cerrarChromeDebugging() {
|
||||
return new Promise((resolve) => {
|
||||
if (process.platform === 'win32') {
|
||||
exec('wmic process where "commandline like \'%--remote-debugging-port=9223%\'" call terminate', (error) => {
|
||||
if (error) {
|
||||
console.log('⚠️ No se encontraron instancias de Chrome debugging');
|
||||
} else {
|
||||
console.log('🔒 Chrome debugging cerrado correctamente');
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
exec("pkill -f 'chrome.*--remote-debugging-port=9223'", () => {
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function iniciarChrome(url) {
|
||||
return new Promise((resolve) => {
|
||||
const chromeProcess = exec(
|
||||
`start chrome `
|
||||
+ `--remote-debugging-port=9223 `
|
||||
+ `--no-sandbox `
|
||||
+ `--disable-setuid-sandbox `
|
||||
+ `--disable-background-timer-throttling `
|
||||
+ `--disable-renderer-backgrounding `
|
||||
+ `--disable-backgrounding-occluded-windows `
|
||||
+ `--user-data-dir="C:\\temp\\chrome_debug_temp_uscis" `
|
||||
+ `"${url}"`,
|
||||
(error) => {
|
||||
if (error) {
|
||||
console.log('⚠️ Error al iniciar Chrome:', error);
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async function initBrowser(url) {
|
||||
try {
|
||||
await cerrarChromeDebugging();
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
console.log('🌐 Iniciando Chrome con debugging...');
|
||||
await iniciarChrome(url);
|
||||
await new Promise(resolve => setTimeout(resolve, 8000)); // Aumentado a 8 segundos
|
||||
|
||||
console.log('🔍 Intentando conectar con Chrome...');
|
||||
const webSocketDebuggerUrl = await getWebSocketUrl();
|
||||
|
||||
console.log('✅ Conexión establecida con Chrome');
|
||||
return await puppeteer.connect({
|
||||
browserWSEndpoint: webSocketDebuggerUrl,
|
||||
defaultViewport: null
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('❌ Error al inicializar el navegador:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function getWebSocketUrl() {
|
||||
let retries = 10; // Aumentado a 15 intentos
|
||||
while (retries > 0) {
|
||||
try {
|
||||
const response = await fetch('http://localhost:9223/json/version');
|
||||
if (!response.ok) throw new Error('No se pudo obtener la versión del navegador');
|
||||
const json = await response.json();
|
||||
if (json.webSocketDebuggerUrl) {
|
||||
return json.webSocketDebuggerUrl;
|
||||
}
|
||||
throw new Error('URL de WebSocket no encontrada');
|
||||
} catch (err) {
|
||||
console.log(`🔄 Reintentando conexión a Chrome... (intentos restantes: ${retries})`);
|
||||
await new Promise(resolve => setTimeout(resolve, 2000)); // Aumentado a 4 segundos
|
||||
retries--;
|
||||
}
|
||||
}
|
||||
throw new Error('No se pudo conectar a Chrome después de varios intentos');
|
||||
}
|
||||
|
||||
// Funciones de utilidad
|
||||
async function delay(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
// Funciones de procesamiento USCIS
|
||||
async function procesarCasoUSCIS(page, element, spreadsheetId, intentos = 1) {
|
||||
const MAX_INTENTOS = 3;
|
||||
|
||||
try {
|
||||
console.log(`⌛ Consultando caso USCIS... (Intento ${intentos}/${MAX_INTENTOS})`);
|
||||
|
||||
try {
|
||||
await page.goto(CONFIG.PLATFORMS.USCIS.URL, {
|
||||
waitUntil: 'domcontentloaded',
|
||||
timeout: 20000
|
||||
});
|
||||
await page.waitForSelector('#receipt_number', { timeout: 10000 });
|
||||
} catch (navigationError) {
|
||||
console.log(' ⚠️ Error de navegación o campo no encontrado, reintentando...');
|
||||
if (intentos < MAX_INTENTOS) {
|
||||
return await procesarCasoUSCIS(page, element, spreadsheetId, intentos + 1);
|
||||
} else {
|
||||
throw new Error('No se pudo acceder a la página después de varios intentos');
|
||||
}
|
||||
}
|
||||
|
||||
// Intentar llenar el campo y hacer clic
|
||||
await page.type('#receipt_number', element.valor);
|
||||
await delay(1000);
|
||||
await page.click('::-p-text(Verifique Estatus)');
|
||||
await delay(2000);
|
||||
// Esperar a que se complete la acción
|
||||
|
||||
// page.waitForSelector('.errorMessage', { timeout: 5000 }),
|
||||
// page.waitForSelector('.conditionalLanding', { timeout: 5000 })
|
||||
|
||||
|
||||
// Verificar el resultado
|
||||
const errorMessage = await page.$('.errorMessage', { timeout: 5000 });
|
||||
if (errorMessage) {
|
||||
console.log(' ⚠️ Caso no válido');
|
||||
await actualizarCelda(
|
||||
spreadsheetId,
|
||||
`G${element.fila}`,
|
||||
['El número de recibo ingresado no es válido, intente nuevamente.']
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
const [titulo, descripcion] = await Promise.all([
|
||||
page.$eval('.conditionalLanding h2', el => el.innerText),
|
||||
page.$eval('.conditionalLanding p', el => el.innerText)
|
||||
]);
|
||||
|
||||
console.log(' ✅ Información obtenida');
|
||||
console.log(` 📌 Estado: ${titulo}`);
|
||||
|
||||
await actualizarCelda(
|
||||
spreadsheetId,
|
||||
`G${element.fila}:H${element.fila}`,
|
||||
[titulo, descripcion]
|
||||
);
|
||||
} catch (dataError) {
|
||||
console.error(' ❌ Error al obtener datos de la página:', dataError);
|
||||
throw dataError;
|
||||
}
|
||||
}
|
||||
|
||||
await delay(1000);
|
||||
return true; // Indica que el proceso fue exitoso
|
||||
|
||||
} catch (error) {
|
||||
console.error(' ❌ Error procesando caso USCIS:', error);
|
||||
|
||||
if (intentos < MAX_INTENTOS) {
|
||||
console.log(` 🔄 Reintentando... (${intentos}/${MAX_INTENTOS})`);
|
||||
return await procesarCasoUSCIS(page, element, spreadsheetId, intentos + 1);
|
||||
} else {
|
||||
console.log(' ⚠️ Se agotaron los intentos o error no recuperable');
|
||||
await actualizarCelda(
|
||||
spreadsheetId,
|
||||
`G${element.fila}`,
|
||||
['Error al procesar el caso. Por favor, intente más tarde.']
|
||||
);
|
||||
return false; // Indica que el proceso falló
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modificar la función procesarArchivo para manejar mejor la reconexión de Chrome
|
||||
async function procesarArchivo(archivo) {
|
||||
console.log('\n🔍 Analizando archivo:', archivo.name);
|
||||
const datos = await obtenerDatosHoja(archivo.id);
|
||||
const platform_type = 'uscis';
|
||||
const platform = CONFIG.PLATFORMS[platform_type.toUpperCase()].URL;
|
||||
|
||||
// const filasAProcesar = datos.slice(1).map((row, index) => ({
|
||||
// valor: row[4],
|
||||
// fila: index + 2,
|
||||
// tieneValor: !row[5],
|
||||
// ultimaConsulta: row[5] || ''
|
||||
// })).filter(row => {
|
||||
// if (!row.ultimaConsulta) return true;
|
||||
// const fechaUltimaConsulta = new Date(row.ultimaConsulta);
|
||||
// const ahora = new Date();
|
||||
// const diferenciaHoras = (ahora - fechaUltimaConsulta) / (1000 * 60 * 60);
|
||||
// return diferenciaHoras > 1;
|
||||
// });
|
||||
|
||||
const filasAProcesar = datos.slice(1)
|
||||
.map((row, index) => ({
|
||||
valor: row[4], // Columna 5 (Valor a consultar)
|
||||
fila: index + 2, // Número de fila real
|
||||
ultimaConsulta: row[5], // Columna 6 (Fecha de última consulta)
|
||||
resultado: row[6] // Columna 7 (Resultado)
|
||||
}))
|
||||
.filter(row => {
|
||||
// Priorizar si la columna G (resultado) está vacía
|
||||
if (!row.resultado) return true;
|
||||
|
||||
// Si la columna G no está vacía, verificar la fecha en la columna F
|
||||
if (!row.ultimaConsulta) return true; // Si no hay fecha en F, también se procesa (aunque G no esté vacía)
|
||||
|
||||
// Parse date in Spanish format DD/MM/YYYY
|
||||
const [date, time] = row.ultimaConsulta.split(', ');
|
||||
const [day, month, year] = date.split('/');
|
||||
const [hours, minutes, seconds] = time.split(':');
|
||||
|
||||
const fechaUltimaConsulta = new Date(year, month - 1, day, hours, minutes, seconds);
|
||||
const ahora = new Date();
|
||||
|
||||
// Calculate hours difference
|
||||
const diferenciaHoras = (ahora - fechaUltimaConsulta) / (1000 * 60 * 60);
|
||||
|
||||
// For future dates, return false to skip processing
|
||||
if (fechaUltimaConsulta > ahora) return false;
|
||||
|
||||
return diferenciaHoras > 1; // Process only if more than 1 hour has passed
|
||||
});
|
||||
|
||||
console.log(filasAProcesar);
|
||||
|
||||
|
||||
console.log(`📊 Total de filas a procesar: ${filasAProcesar.length}`);
|
||||
|
||||
if (filasAProcesar.length > 0) {
|
||||
console.log('🌐 Iniciando navegador...');
|
||||
let browser = await initBrowser(platform);
|
||||
let page = (await browser.pages())[0];
|
||||
let fallosConsecutivos = 0;
|
||||
const MAX_FALLOS_CONSECUTIVOS = 3;
|
||||
|
||||
let procesadas = 0;
|
||||
for (const element of filasAProcesar) {
|
||||
procesadas++;
|
||||
console.log(`\n⏳ Procesando fila ${element.fila} (${procesadas}/${filasAProcesar.length})`);
|
||||
console.log(`📝 Valor a consultar: ${element.valor}`);
|
||||
|
||||
// Guardar la fecha y hora actual
|
||||
const fechaHoraActual = new Date().toLocaleString('es-ES', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
});
|
||||
|
||||
// Actualizar la marca de tiempo en la columna F y limpiar las columnas G y H
|
||||
await Promise.all([
|
||||
actualizarCelda(
|
||||
archivo.id,
|
||||
`F${element.fila}`,
|
||||
[fechaHoraActual]
|
||||
),
|
||||
actualizarCelda(
|
||||
archivo.id,
|
||||
`G${element.fila}:H${element.fila}`,
|
||||
['', '']
|
||||
)
|
||||
]);
|
||||
|
||||
const resultado = await procesarCasoUSCIS(page, element, archivo.id);
|
||||
|
||||
if (!resultado) {
|
||||
fallosConsecutivos++;
|
||||
if (fallosConsecutivos >= MAX_FALLOS_CONSECUTIVOS) {
|
||||
console.log('🔄 Reiniciando navegador debido a fallos consecutivos...');
|
||||
await browser.close();
|
||||
await cerrarChromeDebugging();
|
||||
await delay(2000);
|
||||
|
||||
browser = await initBrowser(platform);
|
||||
page = (await browser.pages())[0];
|
||||
fallosConsecutivos = 0;
|
||||
}
|
||||
} else {
|
||||
fallosConsecutivos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n✅ Proceso completado para el archivo:', archivo.name);
|
||||
await browser.close();
|
||||
} else {
|
||||
console.log('ℹ️ No hay filas para procesar en este archivo');
|
||||
}
|
||||
}
|
||||
|
||||
// Función para cerrar el navegador y la aplicación
|
||||
async function cerrarTodo() {
|
||||
if (browser) {
|
||||
await browser.close(); // Cerrar el navegador si está abierto
|
||||
}
|
||||
console.log('🔄 Cerrando Chrome debugging y finalizando...');
|
||||
await cerrarChromeDebugging();
|
||||
process.exit();
|
||||
app.quit(); // Cerrar la aplicación Electron
|
||||
}
|
||||
|
||||
// Manejar la señal SIGINT (Ctrl + C)
|
||||
process.on('SIGINT', async () => {
|
||||
console.log('Recibida señal de interrupción (Ctrl + C)');
|
||||
await cerrarTodo();
|
||||
});
|
||||
|
||||
// Función principal
|
||||
async function procesarArchivos() {
|
||||
try {
|
||||
console.log('🚀 Iniciando proceso...');
|
||||
const archivos = await listarArchivosEnCarpeta(CONFIG.DRIVE.FOLDER_ID);
|
||||
console.log(`📁 Total de archivos encontrados: ${archivos.length}`);
|
||||
|
||||
let procesados = 0;
|
||||
for (const archivo of archivos) {
|
||||
procesados++;
|
||||
console.log(`\n📌 Procesando archivo ${procesados}/${archivos.length}: ${archivo.name}`);
|
||||
await procesarArchivo(archivo);
|
||||
}
|
||||
console.log('\n🎉 Proceso completado exitosamente!');
|
||||
} catch (error) {
|
||||
console.error('❌ Error en el proceso:', error);
|
||||
} finally {
|
||||
await cerrarTodo(); // Asegúrate de cerrar todo al final
|
||||
}
|
||||
}
|
||||
|
||||
// Ejecutar el proceso
|
||||
app.on('ready', () => {
|
||||
console.log('Aplicación Electron está lista y en ejecución sin ventana.');
|
||||
procesarArchivos();
|
||||
});
|
||||
Reference in New Issue
Block a user