【问题标题】:How do I use puppeteer to take full screenshots of several websites?如何使用 puppeteer 截取多个网站的完整截图?
【发布时间】:2019-11-09 23:24:13
【问题描述】:

我正在尝试使用带有puppeteer 的 Node.js 截屏。我没有使用page.screenshot(),因为屏幕截图需要包含整个桌面。相反,我使用 ImageMagick 的 import 命令截屏。

我当前的代码大部分时间都有效。但其他时候,它会以奇怪的结果失败,例如:

  • 选项卡已切换,但屏幕截图包含旧页面的一半。
  • 页面已切换但空白。
  • 添加延迟有效,但并不理想,因为有时页面加载速度很慢。

问题似乎是page.bringToFront() 没有等待页面完全加载。

我是 Node 和 puppeteer 的新手。请提出一种方法:

  1. 在 Chrome 中加载页面。
  2. 加载后切换到页面。
  3. 通过执行命令行工具截取桌面截图。

在代码中添加延迟似乎不是最好的解决方案。

任何关于代码改进的建议都会有所帮助。

const puppeteer = require('puppeteer');
const execSync = require('child_process').execSync;
const sleep = require('sleep'); 

(async () => {
    const browser = await puppeteer.launch({
        headless: false,
        args: [
            '--ignore-certificate-errors',
            '--no-sandbox',
            '--disable-infobars',
            '--disable-setuid-sandbox',
            '--incognito',
            '--window-size=1600,1200',
            '--start-maximized',
            "--disable-gpu"],
        // slowMo: 250, // slow down by 1550ms
    });

    await browser.newPage();
    await browser.newPage();
    const pages = await browser.pages();
    await Promise.all([
        grabpage(pages[0], 'https://www.cnn.com', 'cnn'),
        grabpage(pages[1], 'https://www.bbc.com', 'bbc'),
        grabpage(pages[2], 'https://www.rediff.com', 'rediff'),
    ]);
    // Someday we will close the browser also.
})();

async function grabpage(page, url, path) {
    await page.goto(url);
    var infront =page.bringToFront();
    infront.then(
        sleep.sleep(5),
        execSync('import -window root ' + path +'.jpg'),
    );
    console.log('took Screenshot: '+path+'.jpg')
}

Rediff page not loaded fully without sleep

【问题讨论】:

    标签: javascript node.js puppeteer browser-automation


    【解决方案1】:

    您尝试与Promise.all 并行运行所有内容,这让一切变得混乱。因为你只有一个browser的实例,当你并行运行grabpage 3次时,它们都在争夺对浏览器的控制权,并且可以在彼此的awaits之间进行。

    我还建议您打开和关闭 grabpage 中的各个页面。您必须将其切换为传递 browser 并执行 const page = await browser.newPage();

    所以你最终得到了

    (async () => {
        const browser = await puppeteer.launch({
          headless: false,
          args: [
                '--ignore-certificate-errors',
                '--no-sandbox',
                '--disable-infobars',
                '--disable-setuid-sandbox',
                '--incognito',
                '--window-size=1600,1200',
                '--start-maximized',
                "--disable-gpu"],
          //      slowMo: 250, // slow down by 1550ms
        });
    
        await grabpage(browser, 'https://www.cnn.com', 'cnn'),
        await grabpage(browser, 'https://www.bbc.com', 'bbc'),
        await grabpage(browser, 'https://www.rediff.com', 'rediff'),
    })();
    
    async function grabpage(browser, url, path) {
      const page = await browser.newPage();
      await page.goto(url);
      execSync('import -window root ' + path +'.jpg')
      // await page.screenshot({path: `${path}.png`}); //if you just need to take a screenshot, not the whole desktop
      await page.close();
    }
    

    不知道为什么你需要使用完整的桌面,但如果你 start-maximized。我猜你关心你在屏幕截图中得到的一点点 OS chrome。

    【讨论】:

    • OP 在问题“我没有使用page.screenshot(),因为屏幕截图必须包含完整的桌面。屏幕是使用可以截图的imagemagick import 命令拍摄的。”
    • 是的,我的错,我错过了 OP 说他不想要 page.screenshot 的部分,但建议的方法也应该适用于 imagemagic。他的困惑是由于一次加载所有页面然后不得不在它们之间切换造成的。
    • 更新了@MultiplyByZer0 发表的地址评论的答案
    • 他做的比这差很多。还有一个事实是,他使用了一个名为sleep 的hacky C++ npm 模块而不是setTimeout(),他在异步函数中使用了child_process.execSync(),并且他忘记了将代码包装到箭头函数中的infront.then()。而且您的更新答案看起来不错。
    • @Anderi R,感谢您的回复。我应该提到的几件事是每页加载一个 URL 会减慢这个过程。所以我想同时加载所有标签。我运行了几次代码,但页面没有完全加载。 imgur.com/9F3q8GY imgur.com/3qMwchc imgur.com/aS2PK7N .. 我添加Hacky sleep的原因:)
    猜你喜欢
    • 1970-01-01
    • 2023-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-12
    相关资源
    最近更新 更多