browserless 对于延迟加载图片的处理
日常中大家为了提高web的性能基于可见区的图片加载基本常见,但是对于基于puppeteer的快照以及pdf生成就不太方便了,以下是一个解决方法,核心是过去内容的高度,基于代码进行滚动,模拟人的操作实现资源的加载
参考实现
const express = require("express");
const puppeteer = require("puppeteer-core");
const app = express();
const browserWSEndpoint = process.env.ENDPOINT || "ws://localhost:3000";
const getBrowser = async () => puppeteer.connect({ browserWSEndpoint });
app.get("/image", async (req, res) => {
let browser = null;
const website = req.query.website;
await getBrowser()
.then(async (browser) => {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 1024 });
await page.goto(website, {
waitUntil: ["load", "networkidle0"],
});
const bodyHandle = await page.$("body");
const { height } = await bodyHandle.boundingBox();
console.log("height", height);
await bodyHandle.dispose();
// Scroll one viewport at a time, pausing to let content load
const viewportHeight = page.viewport().height;
console.log("viewportHeight", viewportHeight);
let viewportIncr = 0;
while (viewportIncr + viewportHeight < height) {
await page.evaluate((_viewportHeight) => {
console.log("scrolling", _viewportHeight);
window.scrollBy(0, _viewportHeight);
}, viewportHeight);
await wait(20);
viewportIncr = viewportIncr + viewportHeight;
}
// Scroll back to top
await page.evaluate((_) => {
window.scrollTo(0, 0);
});
await wait(100)
const screenshot = await page.screenshot({
fullPage: true,
captureBeyondViewport: true,
});
res.end(screenshot, "binary");
})
.catch((error) => {
if (!res.headersSent) {
res.status(400).send(error.message);
}
})
.finally(() => browser && browser.close());
});
function wait (ms) {
return new Promise(resolve => setTimeout(() => resolve(), ms));
}
app.get("/pdf", async (req, res) => {
let browser = null;
const website = req.query.website;
await getBrowser()
.then(async (browser) => {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 1024 });
await page.goto(website, {
waitUntil: ["load", "networkidle0"],
});
const bodyHandle = await page.$("body");
const { height } = await bodyHandle.boundingBox();
console.log("height", height);
await bodyHandle.dispose();
// Scroll one viewport at a time, pausing to let content load
const viewportHeight = page.viewport().height;
console.log("viewportHeight", viewportHeight);
let viewportIncr = 0;
while (viewportIncr + viewportHeight < height) {
await page.evaluate((_viewportHeight) => {
console.log("scrolling", _viewportHeight);
window.scrollBy(0, _viewportHeight);
}, viewportHeight);
await wait(20);
viewportIncr = viewportIncr + viewportHeight;
}
// Scroll back to top
await page.evaluate((_) => {
window.scrollTo(0, 0);
});
await wait(100);
const screenshot = await page.pdf({
displayHeaderFooter: true,
format: "A4",
printBackground: true,
});
res.end(screenshot, "binary");
})
.catch((error) => {
if (!res.headersSent) {
res.status(400).send(error.message);
}
})
.finally(() => browser && browser.close());
});
app.listen(8080, () => console.log("Listening on PORT: 8080"));
说明
以上是基于滚动,以及延迟处理的,实际可能还需要结合实际调整,不能确保没问题
参考资料
https://wiki.zegnat.net/cache/?md5=f7ce4fd73de0ac41f15ea708b4c8f20f