如何从谷歌云功能(Cheerio,Node.js)发出多个http请求



我的问题:

我正在用Cheerio、Node.js和谷歌云功能构建一个网络抓取器。

问题是,我需要发出多个请求,然后在调用response.send()并终止函数之前,将每个请求中的数据写入Firestore数据库。

我的代码需要两个循环:第一个循环是来自我的数据库的url,每个url发出一个单独的请求。第二个循环是Cheerio使用.each从DOM中抓取多行表数据,并对每行进行单独写入。

我尝试过的:

我尝试过将每个请求推送到一系列promise中,然后在调用res.send()之前等待所有promise用promise.all()解决,但我对promise仍然有点不确定,也不确定这是正确的方法。(我已经用这种方式让代码适用于较小的数据集,但仍然不一致。)

我还尝试将每个请求创建为一个新的promise,并使用async/await来等待来自forEach循环的每个函数调用,以便为每个请求留出时间并完全完成写入,这样我就可以在之后调用res.send(),但我发现forEach不支持async/await。

我试着用p迭代模块来绕过这个问题,但因为它实际上不是forEach,而是查询上的一个方法(doc.forEach()),我认为它不是这样工作的。

这是我的代码。

注:

如前所述,这并不是我尝试的一切(我取消了我的承诺尝试),但这应该表明我正在努力实现什么。

export const getCurrentLogs = functions.https.onRequest((req, response) => {

//First, I make a query from my db to get the urls 
// that I want the webscraper to loop through. 
const ref = scheduleRef.get()
.then((snapshot) => {
snapshot.docs.forEach((doc) => {
const scheduleGame = doc.data()
const boxScoreUrl = scheduleGame.boxScoreURL
//Inside the forEach I call the request 
// as a function with the url passed in
updatePlayerLogs("https://" + boxScoreUrl + "/");

});
})
.catch(err => {
console.log('Error getting schedule', err);
});

function updatePlayerLogs (url){

//Here I'm not sure on how to set these options 
// to make sure the request stays open but I have tried 
// lots of different things. 
const options = {
uri: url,
Connection: 'keep-alive',
transform: function (body) {
return cheerio.load(body);
}
};
request(options)
.then(($) => {

//Below I loop through some table data 
// on the dom with cheerio. Every loop 
// in here needs to be written to firebase individually. 

$('.stats-rows').find('tbody').children('tr').each(function(i, element){

const playerPage = $(element).children('td').eq(0).find('a').attr('href');

const pts = replaceDash($(element).children('td').eq(1).text());
const reb =  replaceDash($(element).children('td').eq(2).text());
const ast =  replaceDash($(element).children('td').eq(3).text());
const fg =  replaceDash($(element).children('td').eq(4).text());
const _3pt =  replaceDash($(element).children('td').eq(5).text());
const stl =  replaceDash($(element).children('td').eq(9).text());
const blk =  replaceDash($(element).children('td').eq(10).text());
const to =  replaceDash($(element).children('td').eq(11).text());

const currentLog = {
'pts': + pts,
'reb': + reb,
'ast': + ast,
'fg':  fgPer,
'3pt': + _3ptMade,
'stl': + stl,
'blk':  + blk,
'to':  + to
}
//here is the write
playersRef.doc(playerPage).update({
'currentLog': currentLog
}) 
.catch(error => 
console.error("Error adding document: ", error + " : " + url)
);
});
})
.catch((err) => {
console.log(err); 
});
};
//Here I call response.send() to finish the function. 
// I have tried doing this lots of different ways but 
// whatever I try the response is being sent before all 
// docs are written.
response.send("finished writing logs")
});

我所尝试的一切要么导致超过最后期限的错误(可能是因为我已经研究过配额限制,但我认为我不应该超过配额限制),要么是一些无法解释的错误,代码没有完成执行,但在日志中什么都没有显示。

请帮忙,在我不理解的情况下,有没有一种方法可以使用async/await?有没有一种方法可以用承诺来让它变得优雅?

非常感谢,

也许可以看看这样的东西。它使用蓝鸟承诺和请求承诺库

const Promise = require('bluebird');
var rp = require('request-promise');
const urlList = ['http://www.google.com', 'http://example.com']
async function getList() {
await Promise.map(urlList, (url, index, length) => { 
return rp(url)
.then((response) => {
console.log(`${'nnn'}${url}:${'n'}${response}`);
return;
}).catch(async (err) => {
console.log(err);
return;
})

}, {
concurrency: 10
}); //end Promise.map
}
getList();

相关内容

  • 没有找到相关文章

最新更新