javascript - 一旦用户从登录移动到主页,我如何在 puppeteer 中引用当前页面对象?

标签 javascript puppeteer

所以我尝试使用 puppeteer 来自动化 Oracle 云应用程序中的一些数据输入功能。

截至目前,我可以启动云应用程序登录页面,输入用户名和密码凭据,然后单击登录按钮。登录成功后,Oracle 会为用户打开一个主页。一旦发生这种情况,如果我截图或执行页面。内容截图和内容 html 来自登录页面而不是主页。

如何始终引用用户所在的当前页面?

这是到目前为止的基本代码。

const puppeteer = require('puppeteer');
const fs = require('fs');

(async () => {
  const browser = await puppeteer.launch({headless: false});
  let page = await browser.newPage();
  await page.goto('oraclecloudloginurl', {waitUntil: 'networkidle2'});
  await page.type('#userid', 'USERNAME', {delay : 10});
  await page.type('#password', 'PASSWORD', {delay : 10});
  await page.waitForSelector('#btnActive', {enabled : true});
  page.click('#btnActive', {delay : 1000}).then(() => console.log('Login Button Clicked'));

  await page.waitForNavigation();
  await page.screenshot({path: 'home.png'});
  const html = await page.content();
  await fs.writeFileSync('home.html', html);
  await page.waitFor(10000);
  await browser.close();
})();

有了这个,用户可以正常登录并显示主页。但是之后当我尝试截取主页并呈现 html 内容时出现错误。好像是页面变了,我指的是旧页面。如何引用当前页面的上下文?

错误如下:

(node:14393) UnhandledPromiseRejectionWarning: Error: Protocol error (Runtime.callFunctionOn): Cannot find context with specified id undefined

最佳答案

这段代码看起来有问题有两个原因:

page.click('#btnActive', {delay : 1000}).then(() => console.log('Login Button Clicked'));

await page.waitForNavigation();

第一个问题是 page.click().then() 分离出一个完全独立的 promise 链:

page.click() --> .then(...)
     |
     v
page.waitForNavigation()
     |
     v
page.screenshot(...)
     |
     v
    ...

这意味着触发导航的点击和导航是并行运行的,永远不能重新加入同一个 promise 链。这里通常的解决方案是将它们绑定(bind)到同一个 promise 链中:

// Note: this code is still broken; keep reading!
await page.click('#btnActive', {delay : 1000});
console.log('Login Button Clicked');
await page.waitForNavigation();

这遵循了不混合使用 thenawait 的原则,除非你有充分的理由这样做。

但是上面的代码仍然是错误的,因为 Puppeteer 要求在触发导航的事件被触发之前设置 waitForNavigation() promise 。修复是:

await Promise.all([
  page.waitForNavigation(),
  page.click('#btnActive', {delay : 1000}),
]);

const navPromise = page.waitForNavigation(); // no await
await page.click('#btnActive', {delay : 1000});
await navPromise;

遵循这种模式,Puppeteer 不应再对其上下文感到困惑。


小笔记:

  • 'networkidle2' 很慢而且可能没有必要,尤其是对于您即将离开的页面。我会默认为 'domcontentloaded'
  • await page.waitFor(10000);page.waitForTimeout() 一起被弃用,尽管我意识到这是一篇较旧的帖子。

关于javascript - 一旦用户从登录移动到主页,我如何在 puppeteer 中引用当前页面对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50658786/

相关文章:

javascript - 如何查找选定元素或 ElementHandle 的后代元素?

javascript - 自动滚动javascript

javascript - 如何展平聚合输出的 JSON 结果

javascript - 将 jquery 升级到 1.9.1 后,Ajax.Actionlink onsuccess 脚本停止工作

node.js - Puppeteer 错误 : Protocol error (Page. captureScreenshot):目标已关闭

javascript - 如何使用 Puppeteer 暂停并等待用户输入?

javascript - 如何使用 javascript 或 jquery 将变量值传递给 href 属性?

javascript - 如何从 HtmlUnit 中的特定 url 过滤 javascript

javascript - 用 Jest 测试回调函数

node.js - 如何处理 Puppeteer "Error: Page crashed!"