Necesito descargar unos 300 archivos desde un enlace de descarga directa. Cuando el enlace se abre directamente en el navegador, se activa una descarga automática de pdf. El archivo se descarga y el navegador no va a ninguna parte. Los enlaces son los siguientes:
www.link.com/store/item/123En el enlace, la parte 123 se cambiaría en cada ciclo.
Estaba pensando en usar titiritero (con goto), pero supongo que dado que visitar el enlace activa automáticamente la descarga del pdf y en realidad no va a la página, falla.
Esto es lo que probé, pero no funciona en absoluto:
const links = ['123', '456']; (async () => { const browser = await puppeteer.launch({ headless: false //preferably would run with true }); links.forEach( async link => { const page = await browser.newPage(); await page.goto( linkBeginning + link ); await browser.close(); }) })();Busqué, pero realmente no pude encontrar este caso específico, todos los demás casos están más enfocados en el lado del usuario o tienen el archivo de destino en el enlace real (como xx/store/doc.pdf). Sin embargo, no estoy muy seguro de si eso hace una diferencia. Solo necesitaría un script que me proporcione los archivos pdf para una sola ejecución.
Si alguien tiene una solución en php/python, eso también funcionaría, ya que esto es solo algo único.
editar: terminé haciéndolo en html
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="sku.js"></script> <script> const linkStart = 'https://www.sols-europe.com/gb/pdfpublication/pdf/product/sku/'; sku.forEach(element => { document.write('<a target = "_blank" class="click" href="' + linkStart + element.id +'">'+ element.id +'</a></br>') }); </script> </head> <body></body> </html> <script> const clickInterval = setInterval(function () { const el = document.querySelector('.click:not(.clicked)'); if(el){ el.classList.add('clicked'); el.click() } else { clearInterval(clickInterval); } }, 2000); </script>Su ubicación para browser.close() dentro del bucle no es algo bueno.
Así que lo moví fuera de forEach y lo cambié a page.close() en su lugar.
const links = ['123', '456'] const linkBeginning = 'https://www.link.com/store/item/' ;(async () => { const browser = await puppeteer.launch({ headless: false //preferably would run with true }) links.forEach( async link => { const page = await browser.newPage() const session = await page.target().createCDPSession() await session.send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath: './pdf/' }) await page.goto(linkBeginning + link) await page.close() // Don't use browser.close() inside loop }) await browser.close() // Use here instead })()No necesita titiritero para hacer esto, y puede lograrlo con bastante facilidad en NodeJS:
import http from "https"; import fs from "fs"; (async () => { const skus = ["00548", "03575"]; const filesPromiseArray = skus.map( (sku) => new Promise((resolve, reject) => { const file = fs.createWriteStream(`${sku}.pdf`); const request = http.get(`https://www.sols-europe.com/gb/pdfpublication/pdf/product/sku/${sku}`, (response) => response.pipe(file) ); file.on("finish", resolve); file.on("error", reject); }) ); try { await Promise.all(filesPromiseArray); } catch { console.log("There was an error downloading one of the files"); } })();skus , estamos usando .map() para transformarlos en una matriz de solicitudes..map() estamos creando una Promise que será exitosa ( resolve ) cuando el archivo termine de descargarse, o fallida ( reject ) si la descarga falla.await todas las solicitudes que acabamos de crear. Si uno de ellos falla, se registrará. Si está utilizando CommonJS ( "type":"commonjs", en su package.json ), reemplace las dos importaciones con:
const http = require('https'); const fs = require('fs');