Scrapy / app.js
Lukeetah's picture
Upload 12 files
dff33ce verified
// Web Scraper Ultra Robusto - JavaScript
document.addEventListener('DOMContentLoaded', function() {
// Elementos del DOM
const form = document.getElementById('scraper-form');
const urlInput = document.getElementById('url-input');
const nameInput = document.getElementById('name-input');
const formatRadios = document.querySelectorAll('input[name="formato"]');
const exampleItems = document.querySelectorAll('.example-item');
const statusContainer = document.getElementById('status-container');
const statusText = document.getElementById('status-text');
const resultsSection = document.getElementById('results-section');
const resultsContainer = document.getElementById('results-container');
const pdfFilename = document.getElementById('pdf-filename');
const txtFilename = document.getElementById('txt-filename');
const processBtn = form.querySelector('.btn-process');
// Estado de la aplicación
let isProcessing = false;
// Inicialización
init();
function init() {
// Configurar event listeners
form.addEventListener('submit', handleFormSubmit);
exampleItems.forEach(item => {
item.addEventListener('click', handleExampleClick);
});
// Configurar botones de descarga
const downloadButtons = document.querySelectorAll('.btn-download');
downloadButtons.forEach(btn => {
btn.addEventListener('click', handleDownload);
});
console.log('🚀 Web Scraper Ultra Robusto inicializado correctamente');
}
// Manejar envío del formulario
function handleFormSubmit(e) {
e.preventDefault();
if (isProcessing) return;
const formData = getFormData();
if (!validateForm(formData)) {
showError('Por favor, ingresa una URL válida');
return;
}
startProcessing(formData);
}
// Obtener datos del formulario
function getFormData() {
const selectedFormat = document.querySelector('input[name="formato"]:checked');
return {
url: urlInput.value.trim(),
formato: selectedFormat ? selectedFormat.value : 'Ambos',
nombre: nameInput.value.trim() || generateDefaultName()
};
}
// Validar formulario
function validateForm(data) {
if (!data.url) return false;
// Agregar protocolo si no existe
if (!data.url.startsWith('http://') && !data.url.startsWith('https://')) {
data.url = 'https://' + data.url;
urlInput.value = data.url;
}
try {
new URL(data.url);
return true;
} catch {
return false;
}
}
// Generar nombre por defecto
function generateDefaultName() {
const timestamp = new Date().toISOString().slice(0, 19).replace(/[:\-]/g, '').replace('T', '_');
return `scraping_${timestamp}`;
}
// Manejar clic en ejemplos
function handleExampleClick(e) {
if (isProcessing) return;
const item = e.currentTarget;
const url = item.dataset.url;
const formato = item.dataset.formato;
const nombre = item.dataset.nombre;
// Llenar campos del formulario
urlInput.value = url;
nameInput.value = nombre;
// Seleccionar radio button correspondiente
const formatRadio = document.getElementById(`format-${formato.toLowerCase()}`);
if (formatRadio) {
formatRadio.checked = true;
}
// Efecto visual
item.style.transform = 'scale(0.98)';
setTimeout(() => {
item.style.transform = '';
}, 150);
// Feedback visual
showStatus('success', `✅ Ejemplo cargado: ${nombre}`);
setTimeout(() => {
showStatus('ready', 'Listo para procesar');
}, 2000);
}
// Iniciar procesamiento
async function startProcessing(data) {
isProcessing = true;
processBtn.disabled = true;
processBtn.textContent = '⏳ Procesando...';
try {
// Fase 1: Conectando
showStatus('processing', '🔄 Conectando con el servidor...');
await delay(800);
// Fase 2: Analizando URL
showStatus('processing', '🔍 Analizando URL y contenido...');
await delay(1200);
// Fase 3: Extrayendo contenido
showStatus('processing', '📥 Extrayendo contenido de la página...');
await delay(1000);
// Fase 4: Generando archivos
if (data.formato === 'PDF' || data.formato === 'Ambos') {
showStatus('processing', '📄 Generando archivo PDF...');
await delay(1500);
}
if (data.formato === 'Texto' || data.formato === 'Ambos') {
showStatus('processing', '📝 Generando archivo de texto...');
await delay(1000);
}
// Fase 5: Finalizando
showStatus('processing', '✨ Finalizando procesamiento...');
await delay(600);
// Éxito
showProcessingSuccess(data);
} catch (error) {
showError('❌ Error durante el procesamiento: ' + error.message);
} finally {
isProcessing = false;
processBtn.disabled = false;
processBtn.textContent = '🚀 Procesar Página Web';
}
}
// Mostrar éxito del procesamiento
function showProcessingSuccess(data) {
showStatus('success', '🎉 ¡Procesamiento completado exitosamente!');
// Mostrar resultados
updateResults(data);
resultsContainer.style.display = 'block';
// Scroll suave a resultados
resultsSection.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
// Efecto de aparición
resultsContainer.style.opacity = '0';
resultsContainer.style.transform = 'translateY(20px)';
setTimeout(() => {
resultsContainer.style.transition = 'all 0.5s ease';
resultsContainer.style.opacity = '1';
resultsContainer.style.transform = 'translateY(0)';
}, 100);
}
// Actualizar resultados
function updateResults(data) {
const cleanName = sanitizeFilename(data.nombre);
// Actualizar nombres de archivos
pdfFilename.textContent = `${cleanName}.pdf`;
txtFilename.textContent = `${cleanName}.txt`;
// Mostrar/ocultar archivos según formato
const resultItems = document.querySelectorAll('.result-item');
if (data.formato === 'PDF') {
resultItems[0].style.display = 'block'; // PDF
resultItems[1].style.display = 'none'; // Texto
} else if (data.formato === 'Texto') {
resultItems[0].style.display = 'none'; // PDF
resultItems[1].style.display = 'block'; // Texto
} else {
resultItems[0].style.display = 'block'; // Ambos
resultItems[1].style.display = 'block';
}
// Simular tamaños de archivo aleatorios pero realistas
const pdfSize = generateFileSize(1.5, 5.0, 'MB');
const txtSize = generateFileSize(20, 150, 'KB');
document.querySelector('.result-item:nth-child(1) .file-size').textContent = pdfSize;
document.querySelector('.result-item:nth-child(2) .file-size').textContent = txtSize;
}
// Generar tamaño de archivo simulado
function generateFileSize(min, max, unit) {
const size = (Math.random() * (max - min) + min).toFixed(1);
return `${size} ${unit}`;
}
// Limpiar nombre de archivo
function sanitizeFilename(name) {
return name.replace(/[^a-zA-Z0-9_\-]/g, '_').toLowerCase();
}
// Manejar descarga
function handleDownload(e) {
const button = e.currentTarget;
const originalText = button.textContent;
// Simular descarga
button.textContent = '⬇️ Descargando...';
button.disabled = true;
setTimeout(() => {
button.textContent = '✅ Descargado';
setTimeout(() => {
button.textContent = originalText;
button.disabled = false;
}, 2000);
}, 1500);
// Mostrar mensaje de éxito
showStatus('success', '✅ Archivo descargado correctamente');
setTimeout(() => {
showStatus('ready', 'Listo para procesar');
}, 3000);
}
// Mostrar estado
function showStatus(type, message) {
const statusIcon = statusContainer.querySelector('.status-icon');
// Remover clases de estado anteriores
statusContainer.classList.remove('status-processing', 'status-success', 'status-error');
switch (type) {
case 'processing':
statusContainer.classList.add('status-processing');
statusIcon.textContent = '⏳';
break;
case 'success':
statusContainer.classList.add('status-success');
statusIcon.textContent = '✅';
break;
case 'error':
statusContainer.classList.add('status-error');
statusIcon.textContent = '❌';
break;
default:
statusIcon.textContent = '⏳';
}
statusText.textContent = message;
// Efecto de pulso
statusContainer.style.transform = 'scale(1.02)';
setTimeout(() => {
statusContainer.style.transform = '';
}, 200);
}
// Mostrar error
function showError(message) {
showStatus('error', message);
// Auto-ocultar después de 5 segundos
setTimeout(() => {
showStatus('ready', 'Listo para procesar');
}, 5000);
}
// Función de delay para simular procesamiento
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Validación en tiempo real de URL
urlInput.addEventListener('input', function() {
const url = this.value.trim();
if (url.length > 0) {
try {
// Agregar protocolo si no existe para validación
let testUrl = url;
if (!testUrl.startsWith('http://') && !testUrl.startsWith('https://')) {
testUrl = 'https://' + testUrl;
}
new URL(testUrl);
this.style.borderColor = 'var(--verde-exito)';
} catch {
this.style.borderColor = 'var(--rojo-principal)';
}
} else {
this.style.borderColor = '';
}
});
// Efectos hover mejorados para botones principales
processBtn.addEventListener('mouseenter', function() {
if (!this.disabled) {
this.style.transform = 'translateY(-2px)';
}
});
processBtn.addEventListener('mouseleave', function() {
this.style.transform = '';
});
// Easter egg - Konami code
let konamiCode = [];
const konamiSequence = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65]; // ↑↑↓↓←→←→BA
document.addEventListener('keydown', function(e) {
konamiCode.push(e.keyCode);
if (konamiCode.length > konamiSequence.length) {
konamiCode.shift();
}
if (JSON.stringify(konamiCode) === JSON.stringify(konamiSequence)) {
showStatus('success', '🎮 ¡Código Konami activado! Ultra modo desbloqueado 🚀');
document.body.style.animation = 'rainbow 2s ease-in-out';
setTimeout(() => {
document.body.style.animation = '';
}, 2000);
}
});
// Animación rainbow para easter egg
const style = document.createElement('style');
style.textContent = `
@keyframes rainbow {
0% { filter: hue-rotate(0deg); }
25% { filter: hue-rotate(90deg); }
50% { filter: hue-rotate(180deg); }
75% { filter: hue-rotate(270deg); }
100% { filter: hue-rotate(360deg); }
}
`;
document.head.appendChild(style);
console.log('🎯 Todas las funcionalidades cargadas correctamente');
console.log('💡 Tip: Prueba el código Konami para un easter egg');
});