Tengo el siguiente código:
urls tienen 5000 direcciones URL diferentes, cuando intento obtener y raspar estas urls , me encuentro con un error 500 , así que decido agregar un poco de retraso entre cada solicitud, agrego {concurrency: 1} pero nada cambió.
const requestPromise = require('request-promise'); const Promise = require('bluebird'); const cheerio = require('cheerio'); for (var i=1; i<=250; i++) { p="https://mywebsite.com/" + i.toString() urls[i-1]= p } Promise.map(urls, requestPromise) .map((htmlOnePage, index) => { const $ = cheerio.load(htmlOnePage); $('.txtSearch1').each(function () { var h=""; h=$(this).text() h= h.replace(/(\r\n|\n|\r)/gm, "") html44.push (h) }) shareTuple[urls[index]] = html44; html44=[] fs.writeFileSync( "data.json", JSON.stringify( shareTuple ) ) }, {concurrency: 1}) .then () .catch((e) => console.log('We encountered an error' + e));¿Cómo puedo agregar un retraso aleatorio entre cada solicitud aquí? Debería usar mi código, así que necesito una solución o modificación en mi código.
Actualizar:
Aprendo de las respuestas, pero solo queda un punto en esta pregunta. ¿Cómo puedo detectar qué URL causa 500 errores y omitirlos? ¿Cómo puedo saber si la URL se encontró con el error 500?
Parece que tiene un pequeño problema con los parámetros que está pasando a qué función. Actualmente haces lo siguiente
Promise.map(urls, requestPromise) .map((htmlOnePage, index) => { ...}, { concurrency: 1}) .then(...)que tiene múltiples problemas, así que me pregunto cómo funcionaría eso sin arrojar errores de sintaxis ...
no está pasando sus opciones { concurrency: 1} a Promise.map sino a este último Array.map (donde se ignoran)
Promise.map devuelve una Promesa, que no tiene un .map()
Array.map no devuelve una promesa, por lo que no puede llamar a then() ...
Está escribiendo (sincrónicamente) en el mismo archivo data.json para cada uno de los valores devueltos. Probablemente desee revisar primero los resultados y luego simplemente escribir el archivo una vez que todo esté terminado.
El código correcto sería algo como esto
import { promises as fs } from "fs"; //provides promise based fs operations Promise.map(urls, requestPromise, { concurrency: 1}) .then(values => { values.map((htmlOnePage, index) => { const $ = cheerio.load(htmlOnePage); ... html44.push (h) }) let sharetuple = html44; return fs.writeFile("data.json", JSON.stringify(sharetuple)); }) .catch((e) => console.log('We encountered an error' + e)); No sé, si cheerio es algo asíncrono. Supongo que no. Si es así, tienes que manejar eso en consecuencia ...
EDITAR
Si aún cree que necesita un retraso, puede agregarlo de la siguiente manera (pero creo que debe abordar el problema en el backend, si tiene acceso a él)
function delayedRequest(url) { return new Promise(res => setTimeout(res, 100)) .then(() => requestPromise(url)); }y luego llamar
Promise.map(urls, delayedRequest, { concurrency: 1}) .then(values => { values.map((htmlOnePage, index) => { const $ = cheerio.load(htmlOnePage); ... html44.push (h) }) let sharetuple = html44; return fs.writeFile("data.json", JSON.stringify(sharetuple)); }) .catch((e) => console.log('We encountered an error' + e)); Pero también puede deshacerse de Bluebird por completo y hacerlo con la async await incorporada de JS
async function scraper(urls) { for (let u of urls) { await new Promise(res => setTimeout(res, 100)); let res = await requestPromise(url); ... html44.push(h) } await fs.writeFile("data.json", JSON.stringify(html44)); }Lo que hace su segunda llamada .map es esperar hasta que se resuelvan todas las solicitudes, que se envían en paralelo, y luego hacer otra ronda de mapeo con su html processing.callback
Aunque creo que la sugerencia de derpirscher debería funcionar, aquí doy la mía.
Promise.map( urls, (url, index) => { return requestPromise(url).then((htmlOnePage) => { const $ = cheerio.load(htmlOnePage); const html44 = []; $(".txtSearch1").each(function () { var h = ""; h = $(this).text(); h = h.replace(/(\r\n|\n|\r)/gm, ""); html44.push(h); }); shareTuple = html44; fs.writeFileSync("data.json", JSON.stringify(shareTuple)); // delay 5s return new Promise((resolve) => setTimeout(resolve, 5e3)); }); }, { concurrency: 1, } ).catch((e) => console.log("We encountered an error" + e));