Escribí un rastreador web con nodejs para enviar solicitudes de obtención a unas 300 direcciones URL. Aquí está el bucle principal:
for (let i = 1; i <= 300; i++) { let page= `https://xxxxxxxxx/forum-103-${i}.html` await getPage(page,(arr)=>{ console.log(`page ${i}`) }) }
Aquí está la función getPage (url, devolución de llamada):
export default async function getPage(url, callback) { await https.get(url, (res) => { let html = "" res.on("data", data => { html += data }) res.on("end", () => { const $ = cheerio.load(html) let obj = {} let arr = [] obj = $("#threadlisttableid tbody") for (let i in obj) { if (obj[i].attribs?.id?.substr(0, 6) === 'normal') { arr.push(`https://xxxxxxx/${obj[i].attribs.id.substr(6).split("_").join("-")}-1-1.html`) } } callback(arr) console.log("success!") }) }) .on('error', (e) => { console.log(`Got error: ${e.message}`); }) }
Uso cheerio para analizar HTML y pongo toda la información que necesito en la variable llamada 'arr'. El programa informará un error después de ejecutarse normalmente durante un período de tiempo, así:
... success! page 121 success! page 113 success! page 115 success! Got error: connect ETIMEDOUT 172.67.139.206:443 Got error: connect ETIMEDOUT 172.67.139.206:443 Got error: connect ETIMEDOUT 172.67.139.206:443 Got error: connect ETIMEDOUT 172.67.139.206:443 Got error: connect ETIMEDOUT 172.67.139.206:443 Got error: connect ETIMEDOUT 172.67.139.206:443
Tengo dos preguntas:
1.¿Cuál es el motivo del error? ¿Es porque estoy enviando demasiadas solicitudes de obtención? ¿Cómo puedo limitar la frecuencia de las solicitudes?
2.Como puede ver, el orden en que se accede a las páginas es caótico, ¿cómo controlarlas?
Intenté usar otros módulos para enviar una solicitud de obtención (como Axios) pero no funcionó.
Como puedes ver, el orden en el que se accede a las páginas es caótico, ¿cómo controlarlas?
await
no tiene sentido a menos que coloque una promesa en el lado derecho. http.get
no trata con promesas.
Puede envolverlo en una promesa , pero sería más fácil usar una API que admita de forma nativa, como node-fetch , axios o la búsqueda nativa de Node.js. (Todos tienen API que son, en mi opinión, más fáciles de usar que http.get en general ni solo con respecto al control de flujo).
¿Cuál es la razón del error?
No está claro.
¿Es porque estoy enviando demasiadas solicitudes de obtención?
Esa es una hipótesis probable.
¿Cómo puedo limitar la frecuencia de las solicitudes?
Una vez que tenga su ciclo for
trabajando con promesas para que las solicitudes se envíen en serie en lugar de en paralelo, puede insertar una suspensión entre cada solicitud.
Las solicitudes http se activan simultáneamente porque el ciclo no está esperando la solicitud anterior debido al uso incorrecto de await
. El control adecuado del bucle limitará la frecuencia de la solicitud.
for (let i = 1; i <= 300; i++) { let page= `https://xxxxxxxxx/forum-103-${i}.html` var arr = await getPage(page); // use arr in the way you want console.log(`page ${i}`); } export default async function getPage(url) { // Declare a new promise, wait for the promise to resolve and return its value. return await new Promise((reso, rej) => { https.get(url, (res) => { let html = "" res.on("data", data => { html += data }) res.on("end", () => { const $ = cheerio.load(html) let obj = {} let arr = [] obj = $("#threadlisttableid tbody") for (let i in obj) { if (obj[i].attribs?.id?.substr(0, 6) === 'normal') { arr.push(`https://xxxxxxx/${obj[i].attribs.id.substr(6).split("_").join("-")}-1-1.html`) } } reso(arr) // Resolve with arr console.log("success!") }) }) .on('error', (e) => { console.log(`Got error: ${e.message}`); throw e; }) }) }