更改 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 是:
- 创建新的 HTTP 服务器
- 在 SVG 中构建 HTML 数据表示
- 在Puppeteer/Playwright
中打开网页
- 截图
- 关闭浏览器和服务器
- 继续循环 1。
我很确定有多种解决方法。请给我一些建议。
其他一些相关问题和想法:
- 我的解决方案不起作用,因为我不知道如何等待 HTTP 服务器关闭。它有很多开销,但这不是问题。另一个问题是
EADDRINUSE: address already in use :::8090
,那是因为我循环打开新的 HTTP 服务器,而不是等待上一个服务器关闭。有什么办法吗?
- 一个想法是打开 HTTP 服务器一次并循环:以某种方式更改 HTML 内容并从 Puppeteer 打开网页并截取屏幕截图。可能吗?
- 还有其他选择吗?如果是这样,我很乐意讨论它们。谢谢。
目前创建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()
我想知道针对我的问题的最佳(最简单和最优雅)解决方案。
我有以下格式的数据:Box = {top: val, left: val, width: val, height: val, color: val}
。它们的属性在循环中动态更改/重新计算。我想在网页上可视化这些结构,然后通过 Puppeteer 或 Playwright 打开网页,截图并继续循环。阻塞和执行时间将不是问题。
我的第一个(也是当前的)solution/idea 是:
- 创建新的 HTTP 服务器
- 在 SVG 中构建 HTML 数据表示
- 在Puppeteer/Playwright 中打开网页
- 截图
- 关闭浏览器和服务器
- 继续循环 1。
我很确定有多种解决方法。请给我一些建议。
其他一些相关问题和想法:
- 我的解决方案不起作用,因为我不知道如何等待 HTTP 服务器关闭。它有很多开销,但这不是问题。另一个问题是
EADDRINUSE: address already in use :::8090
,那是因为我循环打开新的 HTTP 服务器,而不是等待上一个服务器关闭。有什么办法吗? - 一个想法是打开 HTTP 服务器一次并循环:以某种方式更改 HTML 内容并从 Puppeteer 打开网页并截取屏幕截图。可能吗?
- 还有其他选择吗?如果是这样,我很乐意讨论它们。谢谢。
目前创建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()