【问题标题】:Async/await - passing data to Puppeteer in a MySQL callback异步/等待 - 在 MySQL 回调中将数据传递给 Puppeteer
【发布时间】:2021-05-22 06:37:41
【问题描述】:

我需要将每个客户端都放在一个表中,这样我就可以遍历它们,并使用 Puppeteer 来抓取一些数据。我需要 MySQL 查询,因为我必须通过查询字符串传递一些参数。

我正在使用 Puppeteer、Puppeteer-cluster(由于有数百行)和 MySQL 驱动程序。

const mysql = require('mysql');
const { Cluster } = require('puppeteer-cluster');

const sql = "select an.id_clientes, ano, c.nome, c.cpf, c.dt_nasc from clientes_anos an inner join clientes c on an.id_clientes = c.id limit 3";
db.query(sql, async (err, result) => {
    //console.log(result);

    const cluster = await Cluster.launch({
        concurrency: Cluster.CONCURRENCY_CONTEXT,
        maxConcurrency: 2,
        puppeteerOptions: {
            headless: false
        },
        //monitor: true,
        timeout: 90000,
    });

    for (const elem of result){
        const cpf = elem.cpf;
        const dt = elem.dt_nasc.toLocaleDateString();

        const url = `https://servicos.receita.fazenda.gov.br/Servicos/ConsRest/Atual.app/paginas/index.asp?cpf=${cpf}&dtnasc=${dt}`;
        console.log(url);


        (async()=>{

            cluster.on('taskerror', (err, data) => {
                //console.log(`Error crawling ${data}: ${err.message}`);
            });
            
            await cluster.task(async ({ page, data: url }) => {
                console.log(dt, cpf);
                await page.goto(url);
                await page.type('#data_nascimento', dt);
                await page.type('input[name=CPF]', cpf);
                await page.waitForNavigation();

                try{
                    const msg = await page.$eval(
                    `#rfb-main-container table tbody tr:nth-of-type(1) td:nth-of-type(1)`, divs => divs.innerText.trim()
                    );
            
                    if(msg.includes('Resultado encontrado: Saldo inexistente de imposto a pagar ou a restituir.')){
                        console.log('situação: '+ msg);
                    }else{
                        console.log('0');
                    }
            
                }catch(exception){
                    console.log('Error');
                }

            });
            
            await cluster.queue(url);
            
            await cluster.idle();
            await cluster.close();

        })();
    }

});

我遇到的问题是,当页面加载时,await page.type('#data_nascimento', dt); await page.type('input[name=CPF]', cpf); 没有返回正确的值(来自查询的值是正确的),它们正在返回最后一行的值。我打赌它是异步的,但我无法弄清楚。

有什么办法可以解决这个问题吗?

【问题讨论】:

    标签: javascript node.js asynchronous async-await puppeteer


    【解决方案1】:

    该死的男孩,我有话要说:)

    1. 我认为您的问题的主要原因是循环/回调/集群之间的交互 这是一个例子来阐明我对循环的观点
    for (var i = 0; i<3; i++) {
      setTimeout(function() {
        console.log(i);
      }, 1000);
    }
    // shows : 3 3 3
    // because when console is finally executed "i" has been fully looped
    

    如果您使用 const 或 let 而不是 var,则代码可以正常工作并显示 0 1 2。

    如果你不使用回调而只等待这种情况会更清楚。

    async function wait(ms) {
      return new Promise(resolve => {
        setTimeout(resolve, ms);
      });
    }
    
    for (var i = 0; i<3; i++) {
      await wait(1000);
      console.log(i);
    }
    

    您可以将此应用到您的 mysql 调用中以扁平化您的代码。

    function query(sql) {
      return new Promise((resolve, reject) => {
        db.query(sql, function(err, result) {
          if (err) return reject(err);
    
          resolve(result);
        })
      });
    }
    
    //then you call it like this
    const sql = "select an.id_clientes, ano, c.nome, c.cpf, c.dt_nasc from clientes_anos an inner join clientes c on an.id_clientes = c.id limit 3";
    const result = await query(sql)
    
    1. 本着扁平化代码的精神,你能去掉异步自动执行功能吗?它看起来非常不必要。 “(异步()=>{” ... "})();"

    2. 最后是集群部分:它没有写出来,但是从阅读文档中我猜想你想在集群功能中使用的任何数据都需要被推送到队列中(XXX)。

    cluster.queue(XXX)
    => 
    await cluster.task(async ({ page, data: XXX}) ...)
    

    如果您需要许多不同的数据,您不仅应该推送您的网址,还应该推送整个对象。

    cluster.queue({cpf, dt, url})
    => 
    await cluster.task(async ({ page, data: {cpf, dt, url}}) ...)
    

    我从未尝试过使用这个模块,但它对我来说很有意义。 可以试试吗?

    PS:另外,完全不使用集群可以大大简化事情。

    【讨论】:

    • 太棒了!它解决了这个问题,让我接近了我想要的地方。我现在面临的问题是(node:10012) MaxListenersExceededWarning: Possible EventEmitter memory leak detected.。我认为使用 Puppeteer-cluster 排队可以避免内存问题,因为它会等待一个完成,以便可以开始另一个页面。至少我是这么认为的。怎么可能简化?请记住,我有将近一千行要迭代。
    • Cluster.on 和 cluster.task 不应在循环中声明。例如,将它们放在前面。
    • cluster.close 也是如此 :)您不应该在每次循环迭代时关闭集群。
    • 哦,当然。我真笨。从来没有意识到处于循环中是一个问题。你是救生员,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 2021-06-30
    • 1970-01-01
    • 2020-08-07
    • 2023-03-15
    • 1970-01-01
    • 2021-05-25
    相关资源
    最近更新 更多