在Puppeter函数中使用等待/异步时出错

时间:2018-08-22 16:57:13

标签: node.js puppeteer

我试图放置一系列连续的步骤,这些步骤将在我的程序中重复多次,例如登录,以某种形式搜索某些数据条件或结束会话。

这是我将Puppeter的步骤放入函数中的方式

login: function (page, selector){
    (async () => {
        await page.goto(“localhost:8080/login”);
        await page.type(“#username”, “admin”);
        console.log("STEP 1 USERNAME”);
        await page.type(“#password”, “admin1”);
        console.log("STEP 2 PASSWORD”);
        await page.waitForSelector(“#submit”).then(() =>
            page.click(“#submit”)
        );
        console.log("STEP 3 - Login"); 
    })();
}

这是我的主要js程序(main.js

CASE1: function (req, res) {
        (async () => {
            const puppeteer = require('puppeteer');
            const browser = await puppeteer.launch();
            const page = await browser.newPage();
            try {
                console.log("STARTING CASE 1”);
                await page.setViewport({ "width": 1280, "height": 720 });
                login (page, selector);
                await page.waitForSelector(“#combobox_of_day”).then(() =>
                    page.click(“#combobox_of_day”)
                );
                console.log("SELECT combobox of day”);

await page.waitForSelector(“#combobox_of_month”).then(() =>
                    page.click(“#combobox_of_month”)
                );
                console.log("SELECT combobox of month”);
await page.waitForSelector(“#combobox_of_year”).then(() =>
                    page.click(“#combobox_of_ year”)
                );
                console.log("SELECT combobox of year”);
                await browser.close(); 
             console.log("ENDING navigation”);

            } catch (error) {
                console.log(error);

            }
        })();
    }

所以在NodeJS控制台上,我希望看到类似的东西

STARTING CASE 1
STEP 1 USERNAME
STEP 2 PASSWORD
STEP 3 Login
SELECT combobox of day
SELECT combobox of month
SELECT combobox of year
ENDING navigation

但是您在控制台上看到的是这样的

STARTING CASE 1
STEP 1 USERNAME
SELECT combobox of day
SELECT combobox of month
SELECT combobox of year
STEP 2 PASSWORD
STEP 3 Login
ENDING navigation

还有一条错误消息

{ TimeoutError: waiting for selector "#username" failed: timeout 30000ms exceeded
    at new WaitTask (Z:\Documents\AR-puppeter\node_modules\puppeteer\lib\FrameManager.js:864:28)
    at Frame._waitForSelectorOrXPath (Z:\Documents\AR-puppeter\node_modules\puppeteer\lib\FrameManager.js:755:12)
    at Frame.waitForSelector (Z:\Documents\AR-puppeter\node_modules\puppeteer\lib\FrameManager.js:713:17)
    at Page.waitForSelector (Z:\Documents\AR-puppeter\node_modules\puppeteer\lib\Page.js:1017:29)
    at Z:\Documents\AR-puppeter\pruebas-app-ar\modulos\escenarios\escenario.js:145:28
    at <anonymous> name: 'TimeoutError' }

由于似乎问题在于调用函数“ Login ()”并没有停止执行连续的行。

如何使程序(main.js)等待我的“ Login ()”功能的所有步骤继续执行?

使用async / awaitWaitForSelector不能解决这个问题吗?

从程序(Login ())调用“ main.js”函数时,我尝试使用不同的语法,但是出现相同的错误。

async login (page, selector); //Getting same error

await login (page, selector); //Getting same error

1 个答案:

答案 0 :(得分:1)

您对login的表述很奇怪:您使用IIFE来运行async函数,但是由于包装器不是async,因此您永远不必等待承诺。您也不必等待login中的CASE1,但是您不能那样做,因为它不会返回任何内容。您需要先通过使其login使Promise返回async(可以不使Promise返回async,但是随后您不需要能够在其中使用await

login: async (page, selector) => {
  await page.goto("localhost:8080/login");
  await page.type("#username", "admin");
  console.log("STEP 1 USERNAME");
  await page.type("#password", "admin1");
  console.log("STEP 2 PASSWORD");
  const submit = await page.waitForSelector("#submit");
  await submit.click();
  console.log("STEP 3 - Login");
}

waitForSelector returns the ElementHandle,因此您无需分别致电page.click,并且在任何情况下都不需要使用then。现在login返回一个Promise

接下来,您需要await中的Promise CASE1并删除IIFE,以便使函数本身async

CASE1: async (req, res) => {
    const puppeteer = require('puppeteer');
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    try {
      console.log("STARTING CASE 1");
      await page.setViewport({ "width": 1280, "height": 720 });
      await login(page, selector);

      for (const type of ["day", "month", "year"]) {
        const combobox = await page.waitForSelector(`#combobox_of_${type}`);
        await combobox.click();
        console.log(`SELECT combobox of ${type}`);
      }

      await browser.close(); 
      console.log("ENDING navigation");
    } catch (error) {
      console.log(error);
    }
}

我删除了一些重复内容。似乎没有selector变量,这与login会忽略它一样好,但是我还是把它留了下来以匹配您的代码。

顺便说一句,避免使用文字处理器来处理代码。我必须先花一些时间修复智能报价。