我需要等待一个元素改变类。
问题是当我使用
waitForSelector
函数时,它不起作用,因为没有新元素添加到 DOM 中。然而,<div>
元素改变了它的类名。
等待元素直到其类名更改,或等到某个类名出现的正确方法是什么?
我当前的代码:
import type { NextApiRequest, NextApiResponse } from "next";
const puppeteer = require("puppeteer");
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const browser = await puppeteer.launch({
executablePath:
"../../../../../../Program Files (x86)/Google/Chrome/Application/chrome.exe",
headless: false,
});
const page = await browser.newPage();
await page.goto("https://www.craiyon.com/", {
timeout: 0,
waitUntil: "domcontentloaded",
});
await page.waitForTimeout(1000);
await page.type(".svelte-1g6bo9g", "sausage");
await page.click("#generateButton");
const test = await page.waitForSelector(
".h-full.w-full.cursor-pointer.rounded-lg.border.border-medium-blue.object-cover.object-center.transition-all.duration-200.hover:scale-[0.97].hover:border-2.hover:border-grey",
{
timeout: 0,
}
);
await browser.close();
console.log(test);
res.status(200).json({ test: "test" });
}
这是稍后更改的类名:
.h-full.w-full.cursor-pointer.rounded-lg.border.border-medium-blue.object-cover.object-center.transition-all.duration-200.hover:scale-[0.97].hover:border-2.hover:border-grey
最后,这是我想要获取的类名:
.grid.grid-cols-3.gap-1.sm:gap-2
。
我相信你误解了
waitForSelector
。它不关心元素是新创建的还是已经存在并且有新的类修改。两者都是 DOM 突变,并且将注册为匹配项。
您可以等待您想要存在的选择器,而不是使用等待消失的旧选择器。一旦选择器准备好,
waitForSelector
就会立即解析,无论它如何进入 DOM 或位于哪个元素上。
waitForFunction
,这是waitForSelector
的更通用版本。
此外,
:
表示伪选择器——它在技术上是有效的,但与.sm:gap-2
不匹配。您可以将该类排除在外,或者使用建议的属性样式选择器在此评论中,但需要注意的是,这些选择器可能过于挑剔——如果顺序发生变化,它将失败。
暂时忽略这一部分似乎没问题,我们可以从响应中获取 URL,我猜这是我们最关心的:
const puppeteer = require("puppeteer"); // ^19.6.3
const url = "<Your URL>";
let browser;
(async () => {
browser = await puppeteer.launch();
const [page] = await browser.pages();
await page.goto(url, {waitUntil: "domcontentloaded"});
await page.type("#prompt", "sausage");
const imgUrls = new Set();
const responsesArrived = Promise.all(
[...Array(9)].map(() =>
page.waitForResponse(
res => {
if (
res.request().resourceType() === "image" &&
res.url().startsWith("https://img.craiyon.com") &&
res.url().endsWith(".webp") &&
!imgUrls.has(res.url())
) {
imgUrls.add(res.url());
return true;
}
},
{timeout: 120_000}
)
)
);
await page.click("#generateButton");
const responses = await responsesArrived;
console.log([...imgUrls]);
const grid = await page.waitForSelector(
".grid.grid-cols-3.gap-1"
);
await grid.screenshot({path: "test.png"});
})()
.catch(err => console.error(err))
.finally(() => browser?.close());
建议:
waitForTimeout
。它已被弃用并导致竞争条件,要么减慢脚本速度,要么使其随机失败。 Puppeteer 的文档建议不要使用它。timeout: 0
,尤其是在调试脚本时。没有理由永远阻止。如果选择器失败,并且您的脚本从未报告失败发生的位置,而是挂起,那么您会错过重要的诊断信息。如果您确实必须等待某些事情,否则您的计算机会爆炸,请将等待时间设置为 10 分钟、一天或一周(如果您确实希望某件事需要那么长时间),但不要无限期。如果是关键任务,您可以接住投掷并重试该操作。page.on("request", req => console.log(req.url())
查看所有 URL,然后系统地阻止与获取结果无关的 URL。
披露:我是链接博客文章的作者。