Files
RPAInmigracion/uscis.mjs
T
2025-08-08 14:35:41 -05:00

221 lines
7.3 KiB
JavaScript

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';
import os from 'os';
console.log(app.getAppPath());
let url_cred = app.getAppPath().replace('app.asar', '');
url_cred = url_cred + '\\credenciales.json';
console.log(url_cred);
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'
}
}
};
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 });
async function listarArchivosEnCarpeta(folderId) {
const res = await drive.files.list({
q: `'${folderId}' in parents and mimeType='application/vnd.google-apps.spreadsheet' and name='base_pruebas'`,
fields: '*'
});
return res.data.files;
}
async function obtenerDatosHoja(spreadsheetId) {
const response = await sheets.spreadsheets.values.get({
spreadsheetId,
range: 'A:H',
});
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;
}
}
async function cerrarChromeDebugging() {
return new Promise((resolve) => {
if (process.platform === 'win32') {
exec('wmic process where "commandline like \'%--remote-debugging-port=%\'" call terminate', () => resolve());
} else {
exec("pkill -f 'chrome.*--remote-debugging-port='", () => resolve());
}
});
}
async function iniciarChromeConPuerto(url, port, userDir) {
return new Promise((resolve) => {
const chromeProcess = exec(
`start chrome ` +
`--remote-debugging-port=${port} ` +
`--no-sandbox ` +
`--disable-setuid-sandbox ` +
`--user-data-dir="${userDir}" ` +
`"${url}"`,
() => resolve()
);
});
}
async function getWebSocketUrl(port) {
const maxRetries = 15;
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(`http://localhost:${port}/json/version`);
const json = await response.json();
if (json.webSocketDebuggerUrl) return json.webSocketDebuggerUrl;
} catch {}
await new Promise(res => setTimeout(res, 2000));
}
throw new Error(`No se pudo conectar a Chrome en el puerto ${port}`);
}
async function initBrowserEnPuerto(url, port, userDir) {
await cerrarChromeDebugging();
await new Promise(resolve => setTimeout(resolve, 2000));
await iniciarChromeConPuerto(url, port, userDir);
await new Promise(resolve => setTimeout(resolve, 8000));
const webSocketDebuggerUrl = await getWebSocketUrl(port);
return await puppeteer.connect({
browserWSEndpoint: webSocketDebuggerUrl,
defaultViewport: null
});
}
async function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function procesarCasoUSCIS(page, element, spreadsheetId, intentos = 1) {
const MAX_INTENTOS = 3;
try {
await page.goto(CONFIG.PLATFORMS.USCIS.URL, { waitUntil: 'domcontentloaded', timeout: 20000 });
await page.waitForSelector('#receipt_number', { timeout: 10000 });
await page.type('#receipt_number', element.valor);
await delay(1000);
await page.click('::-p-text(Verifique Estatus)');
await delay(2000);
const errorMessage = await page.$('.errorMessage');
if (errorMessage) {
await actualizarCelda(spreadsheetId, `G${element.fila}`, ['El número de recibo ingresado no es válido']);
} else {
const [titulo, descripcion] = await Promise.all([
page.$eval('.conditionalLanding h2', el => el.innerText),
page.$eval('.conditionalLanding p', el => el.innerText)
]);
await actualizarCelda(spreadsheetId, `G${element.fila}:H${element.fila}`, [titulo, descripcion]);
}
return true;
} catch (error) {
if (intentos < MAX_INTENTOS) {
return await procesarCasoUSCIS(page, element, spreadsheetId, intentos + 1);
} else {
await actualizarCelda(spreadsheetId, `G${element.fila}`, ['Error al procesar el caso']);
return false;
}
}
}
async function procesarArchivoEnGrupo(filas, archivo, port, userDir) {
const browser = await initBrowserEnPuerto(CONFIG.PLATFORMS.USCIS.URL, port, userDir);
const page = (await browser.pages())[0];
for (const element of filas) {
const fechaHoraActual = new Date().toLocaleString('es-ES', {
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit'
});
await Promise.all([
actualizarCelda(archivo.id, `F${element.fila}`, [fechaHoraActual]),
actualizarCelda(archivo.id, `G${element.fila}:H${element.fila}`, ['', ''])
]);
await procesarCasoUSCIS(page, element, archivo.id);
}
await browser.close();
}
async function procesarArchivo(archivo) {
const datos = await obtenerDatosHoja(archivo.id);
const filas = datos.slice(1).map((row, index) => ({
valor: row[4], fila: index + 2,
ultimaConsulta: row[5], resultado: row[6]
})).filter(row => !row.resultado || !row.ultimaConsulta || ((new Date() - new Date(row.ultimaConsulta)) / 3600000 > 1));
if (!filas.length) return;
const numProcesos = 4;
const chunkSize = Math.ceil(filas.length / numProcesos);
const grupos = Array.from({ length: numProcesos }, (_, i) => filas.slice(i * chunkSize, (i + 1) * chunkSize));
await Promise.all(grupos.map((grupo, i) => {
if (grupo.length === 0) return;
const port = 9224 + i;
const userDir = `C:/temp/chrome_debug_temp_migracion_${i}`;
return procesarArchivoEnGrupo(grupo, archivo, port, userDir);
}));
}
async function cerrarTodo() {
await cerrarChromeDebugging();
process.exit();
app.quit();
}
process.on('SIGINT', async () => {
console.log('Ctrl + C detectado');
await cerrarTodo();
});
async function procesarArchivos() {
const archivos = await listarArchivosEnCarpeta(CONFIG.DRIVE.FOLDER_ID);
for (const archivo of archivos) {
await procesarArchivo(archivo);
}
await cerrarTodo();
}
app.on('ready', () => {
procesarArchivos();
});