巨大なスクリーンショットの撮影に失敗する問題を解決した
Puppeteerでは縦横いずれかが16384pxを超えるスクリーンショットを撮影できない。
これはChromiumの仕様によるものだ。
高さのあるサイトのスクリーンショットを撮ろうとすると画像の左のように、上部が繰り返されてしまう。
GitHubにイシューとして報告されており、問題が部分的に放置されたままcloseとなっていた。
そこで画像の右のように、下までちゃんとスクリーンショットが撮影できるようなコードを作成した。
解決策
次に示すコードにあるtakeFullPageScreenshot
関数を呼び出し、page.screenshot
の代わりに使う。
// Before
const defaultScreenshot = await page.screenshot({
fullPage: true,
});
// After
const screenshot = await takeFullPageScreenshot(page); // here!
takeFullPageScreenshotはこちら。
軽く説明すると、細かく画像を分割してスクリーンショットを撮影し、最後に結合することで、16384pxのリミットを超えないようにしている。
使用例
import fs from "fs";
import puppeteer from "puppeteer";
import takeFullPageScreenshot from "./index";
const url =
"https://nextjs.org/docs/app/building-your-application/routing/route-handlers";
const width = 1500;
const deviceScaleFactor = 2;
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(url, { waitUntil: "load" });
await page.setViewport({
width: width,
height: 500,
deviceScaleFactor,
});
await new Promise((resolve) => setTimeout(resolve, 500));
const screenshot = await takeFullPageScreenshot(page); // here!
browser.close();
fs.writeFileSync("./results/screenshot.png", screenshot);
})();
残りの問題
sharpというjavascriptの画像編集ライブラリを用いている。sharpに画像サイズのハードリミットが設定されているようで、これを超えると失敗する。
そうそう超えることはないだろうが、deviceScaleFactor
を大きくするとリミットを超えて失敗することある。