【问题标题】:How to handle shadow DOM inside iframe with Puppeteer如何使用 Puppeteer 处理 iframe 中的影子 DOM
【发布时间】:2023-02-05 00:04:38
【问题描述】:

我想单击 iframe 内影子 DOM 中的按钮。有没有办法做到这一点?

<html>
  <head></head>
  <body>
    <iframe class="iframe_1">
      #document    
        <div class="shadow-root">
          #shadow-root (open)
          <div>
            <button id="btn_1"></button>
            <button id="btn_2"></button>
          </div>
    </iframe>
  </body>
  </body>

我这样做了:

const frameHandle = await page.$("iframe.iframe_1");
const frame = await frameHandle.contentFrame();
var button = await frame.querySelector(".shadow-root").shadowRoot.querySelector("button[id='btn_1']");
await button.click();

但是得到以下错误:

Uncaught TypeError TypeError: frame.querySelector is not a function

我知道为什么会出现这个错误,但我想不出其他的想法。请教我。

【问题讨论】:

    标签: javascript iframe puppeteer shadow-dom


    【解决方案1】:

    该错误告诉您您正在尝试调用frame.querySelector,但querySelector 不是frame 上存在的函数。 DOMElement#querySelector 仅在浏览器中定义,您可以使用 evaluate-family 调用通过框架访问它。

    例如,如果要返回一个元素,可以使用evaluateHandle

    const button = await frame.evaluateHandle(() =>
      document.querySelector(".shadow-root")
        .shadowRoot
        .querySelector("#btn_1")
    );
    

    这是一个最小的完整示例,您可以在提供的 DOM 结构上运行并查看实际效果:

    index.html:

    <!DOCTYPE html>
    <html><body>
      <iframe class="iframe_1"></iframe>
    <script>
    const html = `<!DOCTYPE html>
      <div class="shadow-root"></div>
    <script>
      const el = document.querySelector(".shadow-root");
      const root = el.attachShadow({mode: "open"});
      el.shadowRoot.innerHTML = `
        <button id="btn_1">A</button>
        <button id="btn_2">B</button>
      `;
      el.shadowRoot.querySelector("#btn_1").addEventListener("click", event => {
        event.target.textContent = "clicked";
      });
    </script>
    `;
    const doc = document.querySelector("iframe").contentWindow.document;
    doc.open();
    doc.write(html);
    doc.close();
    </script>
    </body></html>
    

    index.js:

    const fs = require("node:fs/promises");
    const puppeteer = require("puppeteer"); // ^19.6.3
    
    let browser;
    (async () => {
      browser = await puppeteer.launch();
      const [page] = await browser.pages();
      const html = (await fs.readFile("index.html")).toString();
      await page.setContent(html);
      const frameHandle = await page.$("iframe.iframe_1");
      const frame = await frameHandle.contentFrame();
      const button = await frame.evaluateHandle(() =>
        document.querySelector(".shadow-root")
          .shadowRoot
          .querySelector("#btn_1")
      );
      await button.click();
      const result = await button.evaluate(el => el.textContent);
      console.log(result); // => clicked
    })()
      .catch(err => console.error(err))
      .finally(() => browser?.close());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-13
      • 1970-01-01
      • 1970-01-01
      • 2015-03-31
      • 2022-07-01
      • 2019-08-01
      • 2015-07-10
      • 1970-01-01
      相关资源
      最近更新 更多