Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Puppeteer wait for all images to load then take screenshot

I am using Puppeteer to try to take a screenshot of a website after all images have loaded but can't get it to work.

Here is the code I've got so far, I am using https://www.digg.com as the example website:

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(); })(); 
like image 853
Petar Vasilev Avatar asked Sep 11 '17 17:09

Petar Vasilev


2 Answers

There is a built-in option for that:

await page.goto('https://www.digg.com/', {"waitUntil" : "networkidle0"}); 

networkidle0 - consider navigation to be finished when there are no more than 0 network connections for at least 500 ms

networkidle2 - consider navigation to be finished when there are no more than 2 network connections for at least 500 ms.

P.S. Of course it won't work if you're working with endless-scrolling-single-page-applications like Twitter.

like image 137
Vaviloff Avatar answered Sep 26 '22 04:09

Vaviloff


Another option, actually evaluate to get callback when all images were loaded

This option will also work with setContent that doesn't support the wait networkidle0 option

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);     });   })); }) 
like image 34
Daniel Krom Avatar answered Sep 22 '22 04:09

Daniel Krom