sammiwei
sammiwei

Reputation: 3200

how to scroll through multiple iframes in puppeteer

I am trying to generate pdf with multiple iframes using puppeteer. One issue I encounter is that if I embed something like google maps, google maps will do lazily load(it only loads when the element is in view point of the browser. One solution is to scroll through different iframes on the page and set a wait time for each iframe to load.

here is what I have so far (able to test in https://try-puppeteer.appspot.com/) puppeteer: version 1.9.0, I also tried in 1.12.0, could not make the scroll to work nor the timeout.

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({
  width: 1280,
  height: 750
});
await page.emulateMedia('screen');
const html = '<iframe src="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d12077.188806999058!2d-73.2243774!3d40.8214352!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x9e562057f79c0860!2sH+Lee+Dennison+Building!5e0!3m2!1sen!2sus!4v1547750310674" height="250" width="600" allowfullscreen=""></iframe><div><iframe src="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d12077.188806999058!2d-73.2243774!3d40.8214352!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x9e562057f79c0860!2sH+Lee+Dennison+Building!5e0!3m2!1sen!2sus!4v1547750310674" height="250" width="600" allowfullscreen=""></iframe></div><div><iframe src="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d12077.188806999058!2d-73.2243774!3d40.8214352!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x9e562057f79c0860!2sH+Lee+Dennison+Building!5e0!3m2!1sen!2sus!4v1547750310674" height="250" width="600" allowfullscreen=""></iframe></div><div><iframe src="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d12077.188806999058!2d-73.2243774!3d40.8214352!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x9e562057f79c0860!2sH+Lee+Dennison+Building!5e0!3m2!1sen!2sus!4v1547750310674" height="250" width="600" allowfullscreen=""></iframe></div>'

await page.setContent(html, { waitUntil: 'networkidle0' });
const frames = await page.mainFrame().childFrames(); // get all the iframes on that page. 
await page.evaluate((frames) => {
     // this part does not work
     for (let i=0, i<frames.length; i++){
        setTimeout(() => {
         document.querySelectorAll('iframe')[i].scrollIntoView();
        }, 2000)
     }
  }, frames)
const pdf = await page.pdf({
  scale: 1,
  printBackground: true,
  margin: { bottom: 0 },
  path: 'screenshot.pdf'
});

await browser.close();

Any help is appreciated!

Upvotes: 1

Views: 1540

Answers (1)

vsemozhebuty
vsemozhebuty

Reputation: 13772

This code has some issues:

  1. frames is a non-serializable object from Node.js context so it cannot be transferred in the browser context as is.
  2. All setTimeout() callbacks will be called at once after 2 sec so each frame will not have enough time to be loaded.
  3. These setTimeout() callbacks are not awaited: page.evaluate() returns before these 2 sec pass and pdf creation happens before iframe loading.

You can try this approach:

// page loaded

await page.evaluate(async () => {
  for (const iframe of Array.from(document.querySelectorAll('iframe'))) {
    iframe.scrollIntoView();
    await new Promise((resolve) => { setTimeout(resolve, 2000); });
  }
});

// pdf creation

Upvotes: 1

Related Questions