更改 HTML 内容并循环截屏(Node.js + Puppeteer / Playwright)

Change HTML content and take screenshots in loop (Node.js + Puppeteer / Playwright)

我想知道针对我的问题的最佳(最简单和最优雅)解决方案。

我有以下格式的数据:Box = {top: val, left: val, width: val, height: val, color: val}。它们的属性在循环中动态更改/重新计算。我想在网页上可视化这些结构,然后通过 Puppeteer 或 Playwright 打开网页,截图并继续循环。阻塞和执行时间将不是问题。

我的第一个(也是当前的)solution/idea 是:

  1. 创建新的 HTTP 服务器
  2. 在 SVG 中构建 HTML 数据表示
  3. 在Puppeteer/Playwright
  4. 中打开网页
  5. 截图
  6. 关闭浏览器和服务器
  7. 继续循环 1。

我很确定有多种解决方法。请给我一些建议。

其他一些相关问题和想法:

  1. 我的解决方案不起作用,因为我不知道如何等待 HTTP 服务器关闭。它有很多开销,但这不是问题。另一个问题是 EADDRINUSE: address already in use :::8090,那是因为我循环打开新的 HTTP 服务器,而不是等待上一个服务器关闭。有什么办法吗?
  2. 一个想法是打开 HTTP 服务器一次并循环:以某种方式更改 HTML 内容并从 Puppeteer 打开网页并截取屏幕截图。可能吗?
  3. 还有其他选择吗?如果是这样,我很乐意讨论它们。谢谢。

目前创建HTTP服务器,构建HTML并截图的解决方案:

function createSvgRepresentation(data) {

  // Create new http server
  const server = http.createServer((req, res) => {

    // Create box representation of webpage data
    var html = buildSvg(req, data);

    // Create http head
    res.writeHead(200, {
      'Content-Type': 'text/html',
      'Content-Length': html.length,
      'Expires': new Date().toUTCString()
    });
    res.end(html);

  }).listen(8090, async () => {

    // Launch Chromium browser
    const browser = await chromium.launch();
    const page = await browser.newPage();

    // Set size of viewport
    page.setViewportSize({
      width: 1000,
      height: 600
    });

    await page.goto('http://localhost:8090', {waitUntil: 'domcontentloaded'});

    // Take screenshot of rendered boxes
    await page.screenshot({path: './output/rendered.png', fullPage: true});

    browser.close();
    server.close();

  });
}

Page.setContent(html) 可能是一个选项。您可以轻松地循环您的数据(使用 Box 对象中准备好的 HTML 标记)并且您不必再处理 HTTP 服务器。

示例使用 Puppeteer:

const puppeteer = require('puppeteer')

const box = [
  { top: '0', left: '6rem', width: '5rem', height: '5rem', color: 'red' },
  { top: '3rem', left: '3rem', width: '5rem', height: '5rem', color: 'green' },
  { top: '6rem', left: '0', width: '5rem', height: '5rem', color: 'blue' }
]

const generateMarkup = async () => {
  const browser = await puppeteer.launch({ headless: false })
  const page = await browser.newPage()
  await page.setViewport({ width: 1000, height: 600 })

  for (const el of box) {
    const html = `<div style="top:${el.top};left:${el.left};width:${el.width};height:${el.height};color:${el.color};position:absolute;">
        This div has ${el.color} color.
      </div>`

    await page.goto('about:blank')
    await page.setContent(html)
    await page.waitForTimeout(1000)
    await page.screenshot({ path: `./output/rendered-${el.color}.png`, fullPage: true })
  }
  await browser.close()
}
generateMarkup()