木偶:屏幕快照惰性图像不起作用

时间:2019-04-04 02:22:50

标签: puppeteer

我似乎无法成功捕获https://today.line.me/HK/pc的屏幕截图。

在我的Puppeteer脚本中,我还启动了滚动到页面底部并再次向上滚动以确保加载了图像。但是由于某种原因,它似乎在上面的行URL上不起作用。

function wait (ms) {
 return new Promise(resolve => setTimeout(() => resolve(), ms));
}

const puppeteer = require('puppeteer');

async function run() {
let browser = await puppeteer.launch({headless: false});
let page = await browser.newPage();
await page.goto('https://today.line.me/HK/pc', {waitUntil: 'load'});
//https://today.line.me/HK/pc
// Get the height of the rendered page
  const bodyHandle = await page.$('body');
  const { height } = await bodyHandle.boundingBox();
  await bodyHandle.dispose();

  // Scroll one viewport at a time, pausing to let content load
  const viewportHeight = page.viewport().height+200;
  let viewportIncr = 0;
  while (viewportIncr + viewportHeight < height) {
    await page.evaluate(_viewportHeight => {
      window.scrollBy(0, _viewportHeight);
    }, viewportHeight);
    await wait(4000);
    viewportIncr = viewportIncr + viewportHeight;
  }

  // Scroll back to top
  await page.evaluate(_ => {
    window.scrollTo(0, 0);

  });

 // Some extra delay to let images load
 await wait(2000);

await page.setViewport({ width: 1366, height: 768});
await page.screenshot({ path: './image.png', fullPage: true });
}

run();

Puppeteer Line Screenshot Fails

3 个答案:

答案 0 :(得分:1)

我已通过更改有关如何滚动页面并等待延迟的逻辑来解决此问题。

答案 1 :(得分:0)

对于任何想知道的人,有很多策略可以在Puppeteer中渲染延迟加载的图像或资产,但并不是所有方法都能很好地发挥作用。您尝试截取屏幕截图的网站上的一些小的实现细节可能会改变最终结果,因此,如果您希望实现一种在很多情况下都能很好运行的实现,则需要隔离每个通用案例并分别解决。

我之所以知道这一点,是因为我运行了一个小的“作为服务的屏幕截图”项目(https://getscreenshot.rasterwise.com/),并且不得不分别处理许多情况。这是该项目的一项重要任务,因为似乎总是需要每天使用新的库和UI技术来解决一些新问题。

话虽如此,我认为有些渲染策略具有很好的覆盖率。最好的选择可能是像在OP中那样等待和滚动页面,但同时还要考虑到操作的顺序。这是OP原始代码的略微修改版本。

//Scroll and Wait Strategy

function waitFor (ms) {
  return new Promise(resolve => setTimeout(() => resolve(), ms));
}

async function capturePage(browser, url) {
  // Load the page that you're trying to screenshot.
  const page = await browser.newPage();
  await page.goto(url, {waitUntil: 'load'}); // Wait until networkidle2 could work better.


  // Set the viewport before scrolling
  await page.setViewport({ width: 1366, height: 768});

  // Get the height of the page after navigating to it.
  // This strategy to calculate height doesn't work always though. 
  const bodyHandle = await page.$('body');
  const { height } = await bodyHandle.boundingBox();
  await bodyHandle.dispose();

  // Scroll viewport by viewport, allow the content to load
  const calculatedVh = page.viewport().height;
  let vhIncrease = 0;
  while (vhIncrease + calculatedVh < height) {
    // Here we pass the calculated viewport height to the context
    // of the page and we scroll by that amount
    await page.evaluate(_calculatedVh => {
      window.scrollBy(0, _calculatedVh);
    }, calculatedVh);
    await waitFor(300);
    vhIncrease = vhIncrease + calculatedVh;
  }

  // Setting the viewport to the full height might reveal extra elements
  await page.setViewport({ width: 1366, height: calculatedVh});

  // Wait for a little bit more
  await waitFor(1000);

  // Scroll back to the top of the page by using evaluate again.
  await page.evaluate(_ => {
    window.scrollTo(0, 0);
  });

  return await page.screenshot({type: 'png'});
}

此处的一些主要区别是: -您想从头开始设置视口并使用该固定视口进行操作。 -您可以更改等待时间并引入任意等待以进行实验。有时,这会导致隐藏在网络事件背后的元素暴露出来。 -将视口更改为页面的整个高度也可以像滚动一样显示元素。您可以使用垂直监视器在真实的浏览器中对此进行测试。但是,请确保返回到原始视口高度,因为视口还会影响预期的渲染。

这里要了解的一件事是,单独等待不一定会触发惰性资产的加载。滚动浏览文档的高度可使视口显示需要在视口内才能加载的那些元素。

另一个警告是,有时您需要等待较长时间才能加载资产,因此在上面的示例中,您可能需要尝试每次滚动之后要等待的时间。同样,正如我提到的那样,在一般执行中任意等待有时会影响资产负载与否。

通常,使用Puppeteer截屏时,您需要确保逻辑类似于真实的用户行为。您的目标是重现出租场景,就像有人在计算机上启动Chrome并导航到该网站一样。

答案 2 :(得分:0)

对我有用的解决方案:

调整我的测试运行器 (mocha) 的超时限制。

// package.json
"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build",
  "eject": "react-scripts eject",
  "test": "mocha --timeout=5000" <--- set timeout to something higher than 2 seconds
},

x 处等待 x ~ half of what you set above 秒,然后拍摄 srcreenshot。

var path = require("path"); // built in with NodeJS
await new Promise((resolve) => setTimeout(() => resolve(), 2000));
var file_path = path.join(__dirname, "__screenshots__/initial.png");
await page.screenshot({ path: file_path });