javascript - 如何在执行页内脚本之前操作 DOM?

标签 javascript puppeteer

使用 Puppeteer ,在页面内 JS 执行之前,如何在页面上下文中运行脚本,并提供完整的 DOM?

例如,在运行任何页面 JS 之前,如何运行以下脚本从 img 元素中删除 alt 属性?

document.querySelectorAll('img[alt]').forEach(
  e => e.removeAttribute('alt')
)

(page.evaluateOnNewDocument 看起来很有用,但它似乎是在页面内容可用之前执行的——在它运行时,页面是空白的。)

最佳答案

我认为实现目标的方法是执行:

  1. 设置page.setJavaScriptEnabled(false)
  2. 进入页面
  3. 提取所有脚本和没有脚本的HTML
  4. 设置page.setJavaScriptEnabled(true)
  5. 使用第 3 步中的 HTML 输入 page.goto(`data:text/html,${HTMLWithoutScript}`)
  6. 执行你的脚本
  7. 从步骤 3 中注入(inject)原始提取的脚本 page.addScriptTag({ content: script })

例子

这是您的问题示例的可视化:

const puppeteer = require('puppeteer');

const html = `
<html>
    <head></head>
    <body>
        <img src="https://picsum.photos/200/300?image=1062" alt="dog ">
        <img src="https://picsum.photos/200/300?image=1072" alt="car ">
        <div class="alts">List of alts: </div>
        <script>
            const images = document.querySelectorAll('img');
            const altsContainer = document.querySelector('.alts');
            images.forEach(image => {
                const alt = image.getAttribute('alt') || 'missing alt ';
                altsContainer.insertAdjacentHTML('beforeend', alt);
            })
        </script>
    </body>
</html>`;

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(`data:text/html,${html}`);
    await page.evaluate(() => {
        document.querySelectorAll('img[alt]').forEach(
            e => e.removeAttribute('alt')
        )
    });
    await page.screenshot({ path: 'image.png' });
    await browser.close();
})();

这段代码产生:

broken example

所以删除替代在这里不起作用。

解决方案

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    
    await page.setJavaScriptEnabled(false);
    await page.goto(`data:text/html,${html}`);
    const { script, HTMLWithoutScript } = await page.evaluate(() => {
        const script = document.querySelector('script').innerHTML;
        document.querySelector('script').innerHTML = '';
        const HTMLWithoutScript = document.body.innerHTML;
        return { script, HTMLWithoutScript }
    });
    
    await page.setJavaScriptEnabled(true);
    await page.goto(`data:text/html,${HTMLWithoutScript}`);
    await page.evaluate(() => {
        document.querySelectorAll('img[alt]').forEach(
            e => e.removeAttribute('alt')
        )
    });
    await page.addScriptTag({ content: script });
    await page.screenshot({ path: 'image.png' });
    await browser.close();
})();

这将产生您在问题中预期的结果:

working example

关于javascript - 如何在执行页内脚本之前操作 DOM?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48577053/

相关文章:

javascript - 粘贴文本时去除textarea中的字符

javascript - react 一个组件正在改变类型复选框的不受控制的输入以被控制

javascript - 在 puppeteer 中访问子元素

php - 使用 jquery 更新值

javascript - 尝试让 stylize() 使用 CSS 样式分别随机选择单元格 bgcolor 和文本样式

JavaScript 无法在移动设备上运行

node.js - Puppeteer - Chrome |无法打开 X 显示器 | Ubuntu 20.04

javascript - 如何将变量传递给 Puppeteer page.on?

javascript - 使用 puppeteer 从另一个文件导入 javascript 函数?

puppeteer - 如何设置当前 url,以便在 puppeteer 中注入(inject)自定义 html 时正确解析相对链接?