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

时间:2018-02-02 06:40:45

标签: javascript puppeteer

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

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

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

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

2 个答案:

答案 0 :(得分:6)

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

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

    以下是您可疑示例的可视化:

    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

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

    溶液

    (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

答案 1 :(得分:0)

您可以将脚本标记移动到body而不是head。然后使用document onload事件,您可以执行脚本。根据MDN,此事件在加载对象时触发。以下是示例代码

&#13;
&#13;
function removeAlt(){
  document.querySelectorAll('img[alt]').forEach((e)=>{
    e.removeAttribute('alt');
  });
}
&#13;
<body onload="removeAlt()">
  <img src="http://placehold.it/64x64" alt="1">
  <img src="http://placehold.it/64x64" alt="2">
</body>
&#13;
&#13;
&#13;

让我知道这是否符合您的要求,我测试过并且功能是从图像中移除alt标签