使用 Puppeteer ,在页面内 JS 执行之前,如何在页面上下文中运行脚本,并提供完整的 DOM?
例如,在运行任何页面 JS 之前,如何运行以下脚本从 img
元素中删除 alt
属性?
document.querySelectorAll('img[alt]').forEach(
e => e.removeAttribute('alt')
)
(page.evaluateOnNewDocument
看起来很有用,但它似乎是在页面内容可用之前执行的——在它运行时,页面是空白的。)
最佳答案
我认为实现目标的方法是执行:
- 设置
page.setJavaScriptEnabled(false)
- 进入页面
- 提取所有脚本和没有脚本的HTML
- 设置
page.setJavaScriptEnabled(true)
- 使用第 3 步中的 HTML 输入
page.goto(`data:text/html,${HTMLWithoutScript}`)
- 执行你的脚本
- 从步骤 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();
})();
这段代码产生:
所以删除替代在这里不起作用。
解决方案
(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();
})();
这将产生您在问题中预期的结果:
关于javascript - 如何在执行页内脚本之前操作 DOM?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48577053/