无法使用 Puppeteer 输入字段
Unable to type into an input field with Puppeteer
我正在尝试使用 Puppeteer 在输入字段中输入文本。
async function reddit() {
const broswer = await puppeteer.launch({
headless: false
})
const page = await broswer.newPage();
const navPromise = page.waitForNavigation({
waitUntil: 'domcontentloaded'
})
await page.goto('https://www.reddit.com/r/place/?cx=352&cy=522&px=69')
await navPromise;
console.log('did i get this far? 1');
await page.click('a._3Wg53T10KuuPmyWOMWsY2F:nth-child(2)')
await navPromise;
console.log('did i get this far?2 ');
await page.keyboard.type('#loginUsername', 'hjello')
console.log('did i get this far?3');
}
reddit()
我在运行时获得了所有三个控制台日志。我可以看到它单击用户名登录,但没有输入任何内容。我查看了多个 Whosebug 问题并尝试了答案,但其中 none 将输入输入。
await page.click('a._3Wg53T10KuuPmyWOMWsY2F:nth-child(2)')
触发 DOM 更改,但随后立即在可能尚未准备好的元素上触发 .click()
,因此这看起来像是竞争条件。我建议使用 waitForSelector
(如果导航被触发,则使用 waitForNavigation
,这里似乎不是这种情况)。
const navPromise = page.waitForNavigation({waitUntil: 'domcontentloaded'})
位于已经等待导航的 goto
上方的一个奇怪位置,然后 await
ed 两次,这没有意义。一旦一个承诺被解决,它就永远不会再被解决,所以你唯一想要这样做的时候是你需要再次访问已解决的值,这在这里不适用。等待额外的导航可能会在未触发时导致超时。
不过,主要问题似乎是您尝试输入的选择器位于 iframe 中。 是可能的,但直接导航到登录页面框架 URL 更容易,然后使用 goto
导航到您所在的任何页面试图到达。
例如:
const puppeteer = require("puppeteer"); // ^13.5.1
let browser;
(async () => {
browser = await puppeteer.launch({headless: false});
const [page] = await browser.pages();
const url = "https://www.reddit.com/login/";
await page.goto(url, {waitUntil: "domcontentloaded"});
await page.waitForSelector("#loginUsername");
await page.type("#loginUsername", "hjello");
await page.type("#loginPassword", "foobar");
await Promise.all([
page.waitForNavigation(),
page.click(".AnimatedForm__submitButton"),
]);
// navigate to wherever you want with page.goto
})()
.catch(err => console.error(err))
.finally(() => browser?.close())
;
请注意,当您在浏览器控制台中手动选择元素以准备脚本时,document.querySelector
和类似功能可能会在框架上运行,因为在控制台中聚焦时框架会变为活动状态,但从脚本的角度来看,情况并非如此,这会导致很多潜在的混乱。
我正在尝试使用 Puppeteer 在输入字段中输入文本。
async function reddit() {
const broswer = await puppeteer.launch({
headless: false
})
const page = await broswer.newPage();
const navPromise = page.waitForNavigation({
waitUntil: 'domcontentloaded'
})
await page.goto('https://www.reddit.com/r/place/?cx=352&cy=522&px=69')
await navPromise;
console.log('did i get this far? 1');
await page.click('a._3Wg53T10KuuPmyWOMWsY2F:nth-child(2)')
await navPromise;
console.log('did i get this far?2 ');
await page.keyboard.type('#loginUsername', 'hjello')
console.log('did i get this far?3');
}
reddit()
我在运行时获得了所有三个控制台日志。我可以看到它单击用户名登录,但没有输入任何内容。我查看了多个 Whosebug 问题并尝试了答案,但其中 none 将输入输入。
await page.click('a._3Wg53T10KuuPmyWOMWsY2F:nth-child(2)')
触发 DOM 更改,但随后立即在可能尚未准备好的元素上触发 .click()
,因此这看起来像是竞争条件。我建议使用 waitForSelector
(如果导航被触发,则使用 waitForNavigation
,这里似乎不是这种情况)。
const navPromise = page.waitForNavigation({waitUntil: 'domcontentloaded'})
位于已经等待导航的 goto
上方的一个奇怪位置,然后 await
ed 两次,这没有意义。一旦一个承诺被解决,它就永远不会再被解决,所以你唯一想要这样做的时候是你需要再次访问已解决的值,这在这里不适用。等待额外的导航可能会在未触发时导致超时。
不过,主要问题似乎是您尝试输入的选择器位于 iframe 中。 goto
导航到您所在的任何页面试图到达。
例如:
const puppeteer = require("puppeteer"); // ^13.5.1
let browser;
(async () => {
browser = await puppeteer.launch({headless: false});
const [page] = await browser.pages();
const url = "https://www.reddit.com/login/";
await page.goto(url, {waitUntil: "domcontentloaded"});
await page.waitForSelector("#loginUsername");
await page.type("#loginUsername", "hjello");
await page.type("#loginPassword", "foobar");
await Promise.all([
page.waitForNavigation(),
page.click(".AnimatedForm__submitButton"),
]);
// navigate to wherever you want with page.goto
})()
.catch(err => console.error(err))
.finally(() => browser?.close())
;
请注意,当您在浏览器控制台中手动选择元素以准备脚本时,document.querySelector
和类似功能可能会在框架上运行,因为在控制台中聚焦时框架会变为活动状态,但从脚本的角度来看,情况并非如此,这会导致很多潜在的混乱。