提问人: 提问时间:7/16/2022 更新时间:7/18/2022 访问量:253
使用 Cheerio 和 NodeJS 在 Promis.map 中的请求之间添加一些延迟?
add some delays between request in promis.map using cheerio and nodejs?
问:
我有以下代码:
urls
有不同的 url,当我尝试抓取和抓取这些时,我遇到了一个错误,所以我决定在每个请求之间添加一些延迟,我添加了但没有改变。5000
urls
500
{concurrency: 1}
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));
如何在此处的每个请求之间添加一些随机延迟?我应该使用我的代码,所以我需要对我的代码进行解决方案或修改。
更新:
我从答案中学习,但这个问题只剩下一点。如何检测哪个 URL 导致 500 错误并跳过它?如何找到有关 URL 遇到 500 错误的信息?
答:
您似乎对将哪些参数传递给哪个函数有点问题。目前,您可以执行以下操作
Promise.map(urls, requestPromise)
.map((htmlOnePage, index) => { ...}, { concurrency: 1})
.then(...)
它有多个问题,所以我很想知道它如何在不抛出语法错误的情况下运行......
你不是把你的选择传递给后者,而是传递给后者(它们被忽略)
{ concurrency: 1}
Promise.map
Array.map
Promise.map
返回一个 Promise,它没有.map()
Array.map
不返回承诺,所以你不能调用它......then()
您正在(同步)将每个返回值写入同一个文件。您可能希望先浏览结果,然后在所有操作完成后编写文件。
data.json
正确的代码是这样的
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));
我不知道,是否也是异步的。我想不是。如果是,您必须相应地处理它......cheerio
编辑
如果你仍然认为,你需要一个延迟,你可以按如下方式添加它(但我认为,如果你可以访问它,你应该在后端解决这个问题)
function delayedRequest(url) {
return new Promise(res => setTimeout(res, 100))
.then(() => requestPromise(url));
}
然后调用
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));
但你也可以完全抛弃 Bluebird,用内置的 JS 来做async await
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));
}
第二次调用的作用是等到所有请求都解析完毕,并行发送,然后使用 html processing.callback 进行另一轮映射.map
虽然我认为 derpirscher 的建议应该有效,但我在这里给出我的建议
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));
评论
index
.map
requestPromise(...).then(...).catch(e=> do_wharever_you_want_just_not_to_throw_error)
评论
Bluebird
Promise.map
concurrecy