在promise中添加一些请求之间的延迟.地图使用cheerio和nodejs?



我有以下代码:

urls5000不同的url,当我试图抓取和刮擦这些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(/(rn|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(...)

有多个问题,所以我很想知道如何在不抛出语法错误的情况下运行…

  1. 您没有将您的选项{ concurrency: 1}传递给Promise.map,而是传递给后者Array.map(在那里它们被忽略)

  2. Promise.map返回一个Promise,它没有.map()

  3. Array.map不返回承诺,所以你不能在它上调用then()

  4. 您正在(同步地)为每个返回值写入非常相同的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));
}

您的第二个.map调用所做的是等待,直到所有请求都被解决,这是并行发送的,然后与html processing.callback进行另一轮映射

虽然我认为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(/(rn|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));

相关内容

  • 没有找到相关文章

最新更新