所以我尝试使用 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();
这遵循了不混合使用 then
和 await
的原则,除非你有充分的理由这样做。
但是上面的代码仍然是错误的,因为 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/