I'm using puppeteer to automate access to a specific newspaper. The problem is that to enter the email and password it is necessary to click on the sign in button and wait for a popup to open.
However, when waiting for a selector that is in the login popup, the following error is reported:
UnhandledPromiseRejectionWarning: TimeoutError: Waiting for selector `input[fieldloginemail]` failed: Waiting failed: 30000ms exceeded.
Could anyone help me in this case? I'm using puppeteer 19.8.5.
My code:
const puppeteer = require("puppeteer");
puppeteer
.launch({ headless: false, defaultViewport: null })
.then(async (browser) => {
const page = await browser.newPage();
await page.goto("https://pressreader.df.cl/diario-financiero");
await page.waitForSelector(".btn-login, .toolbar-button-signin", {
visible: true,
});
await page.click(".btn-login, .toolbar-button-signin");
const emailSelector = 'input[fieldloginemail]'
const passwordSelector = 'input[fieldloginpassword]'
await page.waitForSelector(emailSelector)
await page.waitForSelector(passwordSelector)
await page.type(emailSelector, 'foo@bar.com')
await page.type(passwordSelector, 'myPassword')
await page.click('button[actionlogin]')
await browser.close();
});
The main problem is that the auth modal is inside an iframe. Here's how I'd go about this:
const puppeteer = require("puppeteer"); // ^19.7.2
const url = "<Your URL>";
let browser;
(async () => {
browser = await puppeteer.launch();
const [page] = await browser.pages();
await page.goto(url, {waitUntil: "domcontentloaded"});
const btn = await page.waitForSelector(".btn-login, .toolbar-button-signin");
await btn.evaluate(el => el.click());
const frameEl = await page.waitForSelector('iframe[id^="piano-id"]');
const frame = await frameEl.contentFrame();
const email = await frame.waitForSelector("input[fieldloginemail]");
await email.focus();
await email.type("foo@bar.com");
const pw = await frame.waitForSelector("input[fieldloginpassword]");
await pw.focus();
await pw.type("myPassword");
await frame.click("button[actionlogin]");
await page.screenshot({path: "login.png"});
})()
.catch(err => console.error(err))
.finally(() => browser?.close());
The .focus()
seems to be necessary because some asynchronous event seems to take focus away from the input, causing characters to be missed. I haven't tested it extensively, so keep an eye on it.
I'm also using .evaluate(el => el.click())
for the main button since visibility seems spotty and it triggers fine with an untrusted event.
In general, the site is a slow, fussy, heavily-animated modern site. Blocking CSS and images might help speed and reliability.
Minor point, but you can use the return value of waitForSelector
.
Disclosure: I'm the author of the linked blog post.