【问题标题】:How to use setinterval in Puppeteer node js如何在 Puppeteer 节点 js 中使用 setinterval
【发布时间】:2019-05-14 20:34:02
【问题描述】:

我想停止我的脚本并等到结束然后返回数组。如果没有 puppeteer 节点 js 中的返回元素,它不应该向前移动。它不等待清除区间向前移动,所以我得到了未定义,这里如何等待数组的结果。

我得到未定义的结果。我想得到一个数组。

const puppeteer = require("puppeteer");
var page;
var browser;
async function getuser_data(callback) {
    browser = await puppeteer.launch({
        headless: false,
        args: ["--no-sandbox", "--disable-setuid-sandbox"]
    });
    page = await browser.newPage();
    await page.setViewport({
        width: 1068,
        height: 611
    });
    await page.goto(
        "https://www.instagram.com/accounts/login/?source=auth_switcher"
    );
    await page.waitForSelector('input[name="username"]');
    await page.type('input[name="username"]', "yourusername");
    await page.type('input[name="password"]', "yourpassword");
    await page.click("._0mzm-.sqdOP.L3NKy");

    await page.waitFor(3000);
    var y = "https://www.instagram.com/xyz/";
    await page.goto(y);
    await page.waitFor(2000);

    var c = await page.evaluate(async () => {
        await document
            .querySelector(
                "#react-root > section > main > div > header > section > ul > li:nth-child(2) > a"
            )
            .click();
        var i = 0;
        var timer = await setInterval(async () => {
            i = i + 1;
            console.log(i);
            await document.querySelector(".isgrP").scrollBy(0, window.innerHeight);
            var ele = await document.querySelectorAll(".FPmhX.notranslate._0imsa ")
                .length;
            console.log("Now length is :" + ele);
            console.log("Timer :" + i);

            if (ele > 10 && i > 20) {
                console.log("Break");
                clearInterval(timer);
                console.log("after break");
                var array = [];
                for (var count = 1; count < ele; count++) {
                    try {
                        var onlyuname = await document.querySelector(
                            `body > div.RnEpo.Yx5HN > div > div.isgrP > ul > div > li:nth-child(${count}) > div > div.t2ksc > div.enpQJ > div.d7ByH > a`
                        ).innerText;
                        console.log(onlyuname);
                        var obj = {
                            username: onlyuname
                        };
                        console.log(obj);
                        await array.push(obj);
                    } catch (error) {
                        console.log("Not found");
                    }
                }
                console.log(JSON.stringify(array));
                return array;   //Should Wait Till return , it should not move forward
            }
        }, 800);
    });
    console.log(c)  //IT should return me array, Instead of undefined
    callback(c)
}

getuser_data(users => {
    console.log(users)
    let treeusernamefile = JSON.stringify(users);
    fs.writeFileSync('tablebay.json', treeusernamefile);
})

【问题讨论】:

    标签: node.js web-scraping async-await instagram puppeteer


    【解决方案1】:

    问题是setInterval() 无法按预期工作。具体来说,它不会返回您可以使用awaitPromise。它同步创建间隔,然后您传递给page.evaluate() 的整个函数返回。

    您需要做的是自己创建一个Promise,并在准备好array 后告诉resolve

    //...
    
    return new Promise((resolve, reject) => {
        var timer = setInterval(async () => {
                i = i + 1;
                console.log(i);
                await document.querySelector(".isgrP").scrollBy(0, window.innerHeight);
                var ele = await document.querySelectorAll(".FPmhX.notranslate._0imsa ")
                    .length;
                console.log("Now length is :" + ele);
                console.log("Timer :" + i);
    
                if (ele > 10 && i > 20) {
                    console.log("Break");
                    clearInterval(timer);
                    console.log("after break");
                    var array = [];
                    for (var count = 1; count < ele; count++) {
                        try {
                            var onlyuname = await document.querySelector(
                                `body > div.RnEpo.Yx5HN > div > div.isgrP > ul > div > li:nth-child(${count}) > div > div.t2ksc > div.enpQJ > div.d7ByH > a`
                            ).innerText;
                            console.log(onlyuname);
                            var obj = {
                                username: onlyuname
                            };
                            console.log(obj);
                            await array.push(obj);
                        } catch (error) {
                            console.log("Not found");
                        }
                    }
                    console.log(JSON.stringify(array));
                    resolve(array);   // <-----------------
                }
            }, 800);
    })
    
    //...
    

    请注意,上面的示例不处理错误。如果您的setInterval 中的任何函数抛出,您需要捕获这些错误并使用reject 将它们传递给外部作用域。

    希望这会有所帮助。

    【讨论】:

    • +1 这看起来比我的更简单。只是返回一个承诺并稍后解决。我的是递归返回一个承诺。
    【解决方案2】:

    setTimeout,promise 和递归函数可能会有所帮助。

    // a normal delay function, you can call this with await
    const delay = d => new Promise(r => setTimeout(r, d))
    
    const data = [];
    
    async function timer(i = 0) {
      // Optionally set to wait 1000 ms and then continue
      await delay(1000)
    
      // click element, grab data etc.
      console.log(`Clicking element ${i}`);
      data.push(i);
    
      // check for condition fulfillment, you can basically put any limit here
      if (i >= 10) return data;
    
      // return another promise recursively here
      return timer(i + 1)
    }
    
    timer().then(console.log)

    运行代码 sn-p 以查看实际情况。它应该递归地显示控制台,直到达到某个限制。

    它的工作方式是,如果条件尚未满足,它将返回另一个承诺。您可以无限调用它并清除超时(也就是返回数据而不是另一个计时器承诺)。

    【讨论】:

      猜你喜欢
      • 2018-07-31
      • 2020-06-08
      • 2019-02-15
      • 1970-01-01
      • 2023-03-25
      • 2015-07-22
      • 2019-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多