import puppeteer from 'puppeteer'; import fs from 'fs'; import path from 'path'; const BASE_URL = 'https://manhwaweb.com'; // Configuración de Puppeteer const PUPPETEER_OPTIONS = { headless: 'new', args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-accelerated-2d-canvas', '--disable-gpu' ] }; /** * Obtiene los capítulos de un manga */ async function getChapters(mangaSlug) { console.log(`\n📚 Obteniendo capítulos de ${mangaSlug}...`); const browser = await puppeteer.launch(PUPPETEER_OPTIONS); const page = await browser.newPage(); await page.setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15'); const url = `${BASE_URL}/manga/${mangaSlug}`; console.log(`🔗 Cargando: ${url}`); await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45000 }); // Esperar más tiempo para que JavaScript cargue el contenido console.log('⏳ Esperando a que cargue el contenido dinámico...'); await new Promise(resolve => setTimeout(resolve, 8000)); const chapters = await page.evaluate(() => { const chapters = []; const links = document.querySelectorAll('a[href*="/leer/"]'); links.forEach(link => { const href = link.getAttribute('href'); const text = link.textContent?.trim(); if (href && text && href.includes('/leer/')) { const match = href.match(/(\d+)(?:\/|\?|\s*$)/); const chapterNumber = match ? parseInt(match[1]) : null; if (chapterNumber && !isNaN(chapterNumber)) { chapters.push({ number: chapterNumber, title: text, url: href.startsWith('http') ? href : `https://manhwaweb.com${href}`, slug: href.replace('/leer/', '').replace(/^\//, '') }); } } }); return chapters.sort((a, b) => b.number - a.number); }); await browser.close(); console.log(`✅ Encontrados ${chapters.length} capítulos`); return chapters; } /** * Obtiene las imágenes de un capítulo */ async function getChapterImages(chapterSlug) { console.log(`\n📖 Obteniendo imágenes del capítulo ${chapterSlug}...`); const browser = await puppeteer.launch(PUPPETEER_OPTIONS); const page = await browser.newPage(); await page.setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15'); const url = `${BASE_URL}/leer/${chapterSlug}`; console.log(`🔗 Cargando: ${url}`); await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45000 }); console.log('⏳ Esperando a que carguen las imágenes...'); await new Promise(resolve => setTimeout(resolve, 8000)); const images = await page.evaluate(() => { const imageUrls = []; const imgs = document.querySelectorAll('img'); imgs.forEach(img => { let src = img.src || img.getAttribute('data-src'); if (src) { if (!src.startsWith('http')) { if (src.startsWith('//')) { src = 'https:' + src; } else if (src.startsWith('/')) { src = 'https://manhwaweb.com' + src; } } const alt = (img.alt || '').toLowerCase(); const className = (img.className || '').toLowerCase(); const isUIElement = src.includes('avatar') || src.includes('icon') || src.includes('logo') || src.includes('button') || alt.includes('avatar') || className.includes('avatar') || className.includes('icon'); if (!isUIElement && src.includes('http')) { imageUrls.push(src); } } }); return [...new Set(imageUrls)]; }); await browser.close(); console.log(`✅ Encontradas ${images.length} imágenes`); return images; } /** * Descarga una imagen */ async function downloadImage(url, filepath) { const response = await fetch(url); const arrayBuffer = await response.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); fs.writeFileSync(filepath, buffer); console.log(` ✓ Descargada: ${path.basename(filepath)}`); } /** * Función principal */ async function main() { const MANGA_SLUG = 'one-piece_1695365223767'; const CHAPTER_NUMBER = 789; console.log('='.repeat(60)); console.log('🎯 PRUEBA: Descargar Capítulo 789 de One Piece'); console.log('='.repeat(60)); try { // 1. Obtener todos los capítulos const chapters = await getChapters(MANGA_SLUG); // 2. Buscar el capítulo 789 console.log(`\n🔍 Buscando capítulo ${CHAPTER_NUMBER}...`); const chapter = chapters.find(c => c.number === CHAPTER_NUMBER); if (!chapter) { console.log(`❌ No se encontró el capítulo ${CHAPTER_NUMBER}`); console.log(`\n📋 Capítulos disponibles: ${chapters.slice(0, 20).map(c => c.number).join(', ')}...`); return; } console.log(`✅ Capítulo encontrado: ${chapter.title}`); console.log(` URL: ${chapter.url}`); console.log(` Slug: ${chapter.slug}`); // 3. Obtener las imágenes del capítulo const images = await getChapterImages(chapter.slug); if (images.length === 0) { console.log('❌ No se encontraron imágenes'); return; } console.log(`\n📊 Resumen:`); console.log(` - Total de imágenes: ${images.length}`); console.log(` - Primera imagen: ${images[0]}`); console.log(` - Última imagen: ${images[images.length - 1]}`); // 4. Crear directorio para descarga const downloadDir = path.join(process.cwd(), 'test_download', `chapter_${CHAPTER_NUMBER}`); fs.mkdirSync(downloadDir, { recursive: true }); console.log(`\n💾 Directorio de descarga: ${downloadDir}`); // 5. Descargar las primeras 5 imágenes como muestra console.log(`\n📥 Descargando primeras 5 imágenes de ${images.length}...`); const sampleSize = Math.min(5, images.length); const downloaded = []; for (let i = 0; i < sampleSize; i++) { const imageUrl = images[i]; const filename = `page_${String(i + 1).padStart(3, '0')}.jpg`; const filepath = path.join(downloadDir, filename); try { await downloadImage(imageUrl, filepath); downloaded.push({ page: i + 1, filename, url: imageUrl, size: fs.statSync(filepath).size }); } catch (error) { console.log(` ✗ Error descargando página ${i + 1}: ${error.message}`); } } // 6. Verificar descargas console.log(`\n✅ Verificación de descargas:`); console.log(' Página | Tamaño | Estado'); console.log(' ' + '-'.repeat(40)); downloaded.forEach(img => { const sizeKB = (img.size / 1024).toFixed(2); console.log(` ${String(img.page).padStart(6)} | ${sizeKB.padStart(6)} KB | ✓ OK`); }); // 7. Guardar lista de todas las URLs const manifestPath = path.join(downloadDir, 'manifest.json'); const manifest = { manga: 'One Piece', chapter: CHAPTER_NUMBER, total_pages: images.length, images: images.map((url, index) => ({ page: index + 1, url: url })) }; fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); console.log(`\n📄 Manifest guardado: ${manifestPath}`); console.log(`\n` + '='.repeat(60)); console.log('🎉 PRUEBA COMPLETADA CON ÉXITO'); console.log('='.repeat(60)); console.log(`\n📊 Resultados:`); console.log(` ✓ Capítulo ${CHAPTER_NUMBER} encontrado`); console.log(` ✓ ${images.length} páginas/imágenes detectadas`); console.log(` ✓ ${downloaded.length} imágenes descargadas (muestra)`); console.log(` ✓ Todas las URLs son válidas`); console.log(` \n 📁 Archivos guardados en: ${downloadDir}`); console.log(` 📄 Manifest con ${images.length} URLs completo`); console.log(`\n💡 Nota: Solo se descargaron ${sampleSize} imágenes como muestra.`); console.log(` Para descargar todas, descomenta el bucle completo en el código.`); } catch (error) { console.error('\n❌ Error en la prueba:', error.message); console.error(error.stack); } } // Ejutar main().catch(console.error);