如何从Google Cloud Function(Cheerio,Node.js)发出多个http请求
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何从Google Cloud Function(Cheerio,Node.js)发出多个http请求相关的知识,希望对你有一定的参考价值。
我的问题:
我正在使用Cheerio,Node.js和Google Cloud Functions构建一个Web抓取器。
问题是我需要发出多个请求,然后在调用response.send()之前将每个请求中的数据写入Firestore数据库,从而终止该函数。
我的代码需要两个循环:第一个循环是来自我的数据库的url,每个循环都发出一个单独的请求。第二个循环是Cheerio使用.each从DOM中抓取多行表数据,并为每一行单独写入。
我做了什么:
我已经尝试将每个请求推送到一个promises数组,然后在调用res.send()之前等待所有Promises.all()解决的promises,但我对promises仍然有点不稳定而且不确定是正确的方法。 (我已经让代码适用于较小的数据集,但仍然不一致。)
我还尝试将每个请求创建为新的承诺,并使用async / await等待来自forEach循环的每个函数调用,以便为每个请求留出时间并写入完全完成,这样我之后可以调用res.send(),但我发现了forEach不支持Async / await。
我尝试用p-iteration模块解决这个问题,但因为它实际上不是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 webscrapper 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我不明白?有没有办法使用promises来使这个优雅?
非常感谢,
也许看看这样的事情。它使用Bluebird promises和request-promise library
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(`${'\n\n\n'}${url}:${'\n'}${response}`);
return;
}).catch(async (err) => {
console.log(err);
return;
})
}, {
concurrency: 10
}); //end Promise.map
}
getList();
以上是关于如何从Google Cloud Function(Cheerio,Node.js)发出多个http请求的主要内容,如果未能解决你的问题,请参考以下文章
Google Cloud Function - ImportError:无法从“google.cloud”(未知位置)导入名称“pubsub”
从 Google Cloud Function (Python) 将新文件写入 Google Cloud Storage 存储桶
从 Cloud Function (python) 写入 Google Cloud Storage
无法从 GCP 调度程序调用 Google Cloud Function
从 Firebase Cloud Function 调用 Google Books API 时出现 HttpsError