Puppeteer 等待所有图像加载然后截图
Posted
技术标签:
【中文标题】Puppeteer 等待所有图像加载然后截图【英文标题】:Puppeteer wait for all images to load then take screenshot 【发布时间】:2018-02-20 00:05:46 【问题描述】:我正在使用Puppeteer 尝试在所有图像加载后截取网站的屏幕截图,但无法正常工作。
这是我目前得到的代码,我使用https://www.digg.com 作为示例网站:
const puppeteer = require('puppeteer');
(async () =>
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.digg.com/');
await page.setViewport(width: 1640, height: 800);
await page.evaluate(() =>
return Promise.resolve(window.scrollTo(0,document.body.scrollHeight));
);
await page.waitFor(1000);
await page.evaluate(() =>
var images = document.querySelectorAll('img');
function preLoad()
var promises = [];
function loadImage(img)
return new Promise(function(resolve,reject)
if (img.complete)
resolve(img)
img.onload = function()
resolve(img);
;
img.onerror = function(e)
resolve(img);
;
)
for (var i = 0; i < images.length; i++)
promises.push(loadImage(images[i]));
return Promise.all(promises);
return preLoad();
);
await page.screenshot(path: 'digg.png', fullPage: true);
browser.close();
)();
【问题讨论】:
【参考方案1】:为此有一个built-in option:
await page.goto('https://www.digg.com/', "waitUntil" : "networkidle0");
networkidle0 - 在至少 500 毫秒内没有超过 0 个网络连接时,考虑完成导航
networkidle2 - 在至少 500 毫秒内没有超过 2 个网络连接时考虑完成导航。
附:当然,如果您使用的是 Twitter 等无限滚动单页应用程序,则它不会工作。
【讨论】:
在digg.com的情况下,某些图像只有在您向下滚动时才会加载,您知道滚动后等待图像加载的方法吗? 我猜你的解决方案会起作用,但是 - 在研究了 digg 主页的工作原理之后 - 我会说你必须一点一点地滚动,而在你的代码中你几乎跳了一整页。查看源代码 - 有许多延迟加载图像,只有在视口中才会加载。 我认为应该是: waitUntil: "networkidle" 而不是 "waitUntil" : "networkidle" 在最新的 puppeteer 版本中,networkidle
已弃用并替换为 networkidle0
& networkidle2
github.com/GoogleChrome/puppeteer/blob/master/docs/…
嗨,每次我点击它都会加载东西,我怎么能等待下一个网络空闲,但是没有任何 goto 你看到因为它是一个按钮点击。【参考方案2】:
另一种选择,实际评估以在所有图像加载后获取回调
此选项也适用于不支持等待 networkidle0
选项的 setContent
await page.evaluate(async () =>
const selectors = Array.from(document.querySelectorAll("img"));
await Promise.all(selectors.map(img =>
if (img.complete) return;
return new Promise((resolve, reject) =>
img.addEventListener('load', resolve);
img.addEventListener('error', reject);
);
));
)
【讨论】:
注意***.com/questions/23803743/… @BenjaminGruenbaum 是的,但它是事件发射器,npm 承诺它不会完全一样?,+感谢编辑 据我所知,您还不能自动承诺EventTarget
s - 但其余的不需要new Promise
:)
请注意,与networkidle
不同,当调用evaluate
时,它将等待基于DOM 中存在的标签的所有图像。因此,如果脚本异步添加更多图像,这将不起作用(理论上您可以递归调用它,但是......嗯)。
仅供参考,此答案已过时。 setContent
现在支持waitUntil
,非常有用。【参考方案3】:
等待延迟加载图片
您可能需要考虑先使用Element.scrollIntoView()
等方法向下滚动以解决延迟加载图像的问题:
await page.goto('https://www.digg.com/',
waitUntil: 'networkidle0', // Wait for all non-lazy loaded images to load
);
await page.evaluate(async () =>
// Scroll down to bottom of page to activate lazy loading images
document.body.scrollIntoView(false);
// Wait for all remaining lazy loading images to load
await Promise.all(Array.from(document.getElementsByTagName('img'), image =>
if (image.complete)
return;
return new Promise((resolve, reject) =>
image.addEventListener('load', resolve);
image.addEventListener('error', reject);
);
));
);
【讨论】:
嗨,格兰特,这不会获取所有图像。例如,尝试使用给定的 URL insight.com/en_US/search.html?qtype=all&q=HP%20Printers【参考方案4】:我面临着完全相同的问题。 我觉得解决方案将涉及使用:
await page.setRequestInterceptionEnabled(true);
page.on('request', interceptedRequest =>
//some code here that adds this request to ...
//a list and checks whether all list items have ...
//been successfully completed!
);
https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagesetrequestinterceptionenabledvalue
【讨论】:
应该可以只使用promise来实现。【参考方案5】:我使用 page.setViewPort(...) 方法找到了适用于多个站点的解决方案,如下所示:
const puppeteer = require('puppeteer');
async(() =>
const browser = await puppeteer.launch(
headless: true, // Set to false while development
defaultViewport: null,
args: [
'--no-sandbox',
'--start-maximized', // Start in maximized state
],
);
const page = await = browser.newPage();
await page.goto('https://www.digg.com/',
waitUntil: 'networkidle0', timeout: 0
);
// Get scroll width and height of the rendered page and set viewport
const bodyWidth = await page.evaluate(() => document.body.scrollWidth);
const bodyHeight = await page.evaluate(() => document.body.scrollHeight);
await page.setViewport( width: bodyWidth, height: bodyHeight );
await page.waitFor(1000);
await page.screenshot(path: 'digg-example.png' );
)();
【讨论】:
waitFor
已弃用,将在未来版本中删除:有关详细信息,请参阅 github.com/puppeteer/puppeteer/issues/6214。以上是关于Puppeteer 等待所有图像加载然后截图的主要内容,如果未能解决你的问题,请参考以下文章