【问题标题】:How can I consistently fill out input fields?如何始终如一地填写输入字段?
【发布时间】:2019-05-23 20:34:01
【问题描述】:

我不知道为什么,但似乎有些字段不适合我。

这对我来说在一个站点上运行良好:

await page.click(USERNAME_SELECTOR);
await page.keyboard.type(CREDS.username);
await page.click(PASSWORD_SELECTOR);
await page.keyboard.type(CREDS.password);
await page.click(LOGIN_BUTTON_SELECTOR);
await page.waitForNavigation();

但是,在 https://app.member.virginpulse.com/ 上,它似乎对我不起作用。它应该很简单,因为输入字段都有 ID(#username$password)......但是,它似乎没有正确填写。

const puppeteer = require('puppeteer');
const email = "foo@bar.com";
const password = "foopass";
const emailInputSel = "#username";
const passwordInputSel = "#password";
const signInButtonSel = ".login-submit input";
const homeUrl = "https://app.member.virginpulse.com";

async function run() {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(homeUrl, {waitUntil: 'domcontentloaded'});
    //----from here---
    await page.waitFor(emailInputSel);
    await page.$eval(emailInputSel, (e,v) => e.value = v, email);
    await page.$eval(passwordInputSel, (e,v) => e.value = v, password);
    //----to here----- i've tried several things
    await page.screenshot({path: 'screenshot.png'});
    ...

我尝试过的其他事情:

await page.evaluate((sel, val) => {
    const ele = document.querySelector(sel);
    if (!ele) {
        return;
    }
    ele.value = val;
}, sel, val);

await page.evaluate((sel) => {
    const ele = document.querySelector(sel);
    if (!ele) {
        return;
    }
    ele.click(); ele.focus();
}, sel);
await page.keyboard.type(val);

似乎没有正确填写数据。有谁知道发生了什么以及如何让它发挥作用?

【问题讨论】:

  • 嗨,您能否在 it doesn't seem to work 上解释更多,任何表明它不起作用的标志或指标`或其似乎不起作用的原因?
  • 实际填写部分的代码对我来说看起来是正确的,你可以尝试更改{waitUntil: 'domcontentloaded'} 部分吗,因为有时会触发domcontentloaded 事件,但是页面需要一些时间来加载js文件并运行脚本
  • 我注意到的另一件事是,当我导航到https://app.member.virginpulse.com/ 时,它会重定向到https://iam.virginpulse.com/auth/realms/virginpulse/protocol/openid-connect/auth?... 之类的东西以输入实际密码,您是否尝试过 waitForNavigation 或其他逻辑来处理这种行为?
  • 其他可能的行为是您登录一次后浏览器已经设置了cookie,当您再次导航到https://app.member.virginpulse.com/时,cookie显示您已经登录,因为浏览器重定向了其他页面,因此有不是电子邮件或密码输入
  • @plat123456789 - 由于不工作,屏幕截图通常显示登录字段完全为空......我遇到过一些奇怪的情况,其中部分输入存在而部分不存在。如果您自己插入运行,您可以看到屏幕截图可能只是空的。除了domcontentloaded,我还尝试过networkidle0。我还使用waitFor等待选择器可用。我还输入了代码来获取页面和控制台的标题在尝试输入之前记录它......正如我所期望的那样,它是“登录到 Virgin Pulse”。

标签: node.js puppeteer


【解决方案1】:

修复 1:等到元素可见

仅仅等待选择器是行不通的,我们必须等到元素在视口上正确可见并完成导航请求。

// wait until all requests are done
await page.goto(homeUrl, { waitUntil: "networkidle0" });

// wait until the email selector is visible on viewport
await page.waitForSelector(emailInputSel, { visible: true }); 

只需在您当前的代码上添加上述更改,我就得到了这个结果,

请注意上面的结果屏幕截图如何在提交按钮上没有任何内容,您的其他选择器也是如此。

修复 2:正确传递数据

这是可选的,以防第一次修复没有改变任何东西。

步骤 1

不要传递两个参数,而是传递一个带大括号的参数。

await page.evaluate((sel, val) => {
    const ele = document.querySelector(sel);
    if (!ele) {
        return;
    }
    ele.value = val;
}, (sel, val)); // <-- Look here

第二步

如果上述步骤 1 不起作用,请尝试trigger the change。所以如果是angular app,应该知道元素发生了变化,把上面改成这个,

await page.evaluate((sel, val) => {
  const ele = document.querySelector(sel);
  if (!ele) {
    return;
  }
  ele.value = val;

  // Trigger the change here
  var event = new Event('input', {
    'bubbles': true,
    'cancelable': true
  });

  ele.dispatchEvent(event);

}, (sel, val));

可选

如果你想多次重复使用同一个东西,你可以这样重写,

const fillInput = (sel, val) => {
  await page.waitForSelector(sel, { visible: true });
  await page.evaluate((sel, val)=>{}) // the code from above function should be here
}

然后这样调用,

await fillInput(emailInputSel, email)

【讨论】:

  • 我还发现即使填写了表单也无法单击提交按钮(因为它认为这些字段没有更新)...我发现在 page.click()这些元素也解决了这个问题(类似于你对输入事件所做的)......但我现在可能可以使用原来的page.click(), page.keyboard.type() 和你的visible:true...waitFor 上的visible:true 似乎是我真的需要(对于一般的角度形式来说可能是正确的?)
  • 是的,任何类似的框架/库都应该如此。由于反应,角度有不同的方式来检测“变化”,你可能应该让它知道某些东西已经改变了。直接使用keyboard.type 键入“模拟”实际键入,因此角度知道某些东西已经改变。 :)
猜你喜欢
  • 2018-07-13
  • 1970-01-01
  • 2017-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多