该元素位于影子根中。请访问我的回答Puppeteer 没有为带有影子根的页面提供准确的 HTML 代码 https://stackoverflow.com/questions/68525115/puppeteer-not-giving-accurate-html-code-for-page-with-shadow-roots/68540701#68540701有关 Shadow DOM 的更多信息。
此代码深入到影子根,等待按钮出现,然后单击它。或者,它等待元素被删除,然后截取屏幕截图。
const puppeteer = require("puppeteer"); // ^19.11.1
let browser;
(async () => {
browser = await puppeteer.launch();
const [page] = await browser.pages();
const url = "https://www.bauhaus.info/";
await page.goto(url, {waitUntil: "domcontentloaded"});
const el = await page.waitForSelector("#usercentrics-root");
const sel = '[data-testid="uc-accept-all-button"]';
await page.waitForFunction((el, sel) =>
el.shadowRoot.querySelector(sel),
{},
el,
sel,
);
await el.evaluate((el, sel) =>
el.shadowRoot.querySelector(sel).click(),
sel
);
// to prove it worked, wait for the popup
// to disappear, then take a screenshot
const root = await page.waitForSelector("#usercentrics-root");
await page.waitForFunction((root, sel) =>
!root.shadowRoot.querySelector(sel), {}, root, sel
);
await page.screenshot({path: "clicked.png"});
})()
.catch(err => console.error(err))
.finally(() => browser?.close());
自原始帖子发布以来,Puppeteer 有一种更简单的方法来遍历影子 DOM,>>>
:
// ...
await page.goto(url, {waitUntil: "domcontentloaded"});
const sel = '[data-testid="uc-accept-all-button"]';
const btn = await page.waitForSelector(">>> " + sel);
await btn.click();
// ...
跳出框框思考,如果您并不真正需要单击按钮,而只需要尽可能快速轻松地摆脱模式,则可以炸掉整个外部容器、影子根和所有内容:
// ...
await page.goto(url, {waitUntil: "domcontentloaded"});
const el = await page.waitForSelector("#usercentrics-root");
await el.evaluate(el => el.remove());
// ...
这是一种被低估的技术:如果页面的一部分妨碍您并且与您的目标无关,请将其撕掉并忘记它!这与阻止不需要的资源的精神类似。您不必按预期使用该网站。
进一步突破框框:根据您在网站上真正要完成的任务,您通常可以使用本机不受信任的 DOM 方法来完成它,例如.click()
inside evaluate
块,不关心可见性。这意味着您可以完全忽略模式。
也可以看看:无法找到并单击条件条款按钮 https://stackoverflow.com/questions/74057130/cant-locate-and-click-on-a-terms-of-conditions-button/74057427#74057427它使用相同的#usercentrics-root
.