当前位置: 首页 > 知识库问答 >
问题:

如何从Google Cloud函数(Cheerio,node.js)发出多个http请求

公孙慎之
2023-03-14

我的问题:

我正在构建一个包含Cheerio、Node.js和Google Cloud功能的Web刮板。

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

我的代码需要两个循环:第一个循环使用我db中的URL,每个URL都发出一个单独的请求。第二个循环是Cheerio使用.each从DOM中刮取多行表数据,并对每一行进行单独的写操作。

我试过的:

我尝试将每个请求推送到一组承诺中,然后在调用res.send()之前等待所有承诺都用promission.all()解决,但我对promissions还是有点不确定,不确定这是正确的方法。(我已经通过这种方式获得了适用于较小数据集的代码,但仍然不一致。)

我还尝试将每个请求创建为一个新的承诺,并使用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 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?有没有办法用承诺来让这变得优雅?

非常感谢,

共有1个答案

夹谷英奕
2023-03-14

也许看看像这样的东西。它使用Bluebird promises和request-promise库

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();
 类似资料:
  • 问题内容: 如何在node.js中使用数据发出出站HTTP POST请求? 问题答案: 这是一个使用node.js向Google Compiler API发出POST请求的示例: 我已经更新了代码,以显示如何从文件而不是硬编码的字符串发布数据。它使用async 命令来实现此目的,并在成功读取后发布实际代码。如果有错误,则抛出该错误,如果没有数据,则该过程以负值退出以指示失败。

  • 问题内容: 问题很简单。我想使用Node.js服务器作为代理,以记录,认证HTTP查询并将其转发到后端HTTP服务器(PUT,GET和DELETE请求)。 我应该为此使用哪个库?恐怕找不到。 问题答案: NodeJS支持将http.request作为标准模块:http ://nodejs.org/docs/v0.4.11/api/http.html#http.request

  • 问题内容: 如何使用 java.net.URLConnection发出一个http请求? 问题答案: 首先先声明一下:发布的代码段都是基本示例。您需要处理琐碎的和,然后自己整理。 准备中 我们首先至少需要知道URL和字符集。参数是可选的,取决于功能要求。 查询参数的格式必须为,并由串联&。通常,您还可以使用指定的字符集对查询参数进行网址编码。 该只是为方便起见。当我需要String串联运算符+两次

  • 问题内容: 我正在尝试让我的函数返回http get请求,但是,无论如何,它似乎在?scope中丢失了。我对Node.js不熟悉,因此不胜感激 问题答案: 当然,您的日志会返回:您在完成请求之前先进行日志。问题不是范围,而是 异步性 。 是异步的,这就是为什么它将回调作为参数的原因。做您在回调中要做的事情(传递给的):

  • 问题内容: 我在iBooks中阅读了Apple的The Programming Language Swift ,但无法弄清楚如何在Swift中发出HTTP请求(例如cURL)。我需要导入Obj- C类还是只需要导入默认库?还是无法基于本机Swift代码发出HTTP请求? 问题答案: 您可以使用,而且还是因为你通常在Objective- C做。请注意,对于iOS 7.0和更高版本,它是首选。 使用

  • 我在iBooks上读过Apple的编程语言Swift,但不知道如何在Swift中发出HTTP请求(类似于cURL)。我需要导入Obj-C类还是只需要导入默认库?或者不可能基于本机Swift代码发出HTTP请求?