Webページのスクリーンショットを大量に取りたいという時に、便利なのがヘッドレス Chrome。
ヘッドレスとは、GUIからではなくCUIからChromeを使用するモードのことで、Chrome 59以降から搭載されました。
ヘッドレス Chromeを使うと、ブラウザで行う様々な操作をコマンドラインから行い、自動化することもできるようになります。
今回はこのヘッドレス ChromeをNode.jsのプログラムで制御するためのライブラリであるPuppeteerを使って、Webページ全体のスクロールショットを撮る方法を模索してみました。
まずはPuppeteerをインストール
npm i puppeteer
Puppeteerをインストールする際、自動でChromiumもインストールされますが、ローカルにあるChromeを使いたい場合には、puppeteer-coreのみでインストールすることもできます。
npm i puppeteer-core
puppeteer-coreを使用する場合、puppeteer.launchでブラウザを起動するときに、channel: 'chrome'というオプションを渡します。
const browser = await puppeteer.launch({
//ローカルのChromeを使う
channel: 'chrome',
//ヘッドレスモードで起動
headless: true,
//言語は日本語に
args: ['--lang=ja']
});
ブラウザでスクリーンショットを撮りたいページへ移動します。
スクリーンショットを撮りたいサイズでviewportを指定することもでき、deviceScaleFactorに2を指定することで、Retinaのスクリーンショットを撮ることも可能です。
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 800, deviceScaleFactor: 2 });
await page.goto('https://qiita.com/');
スクリーンショットを撮る時には、fullPageをtrueにしておくと、Webサイト全体のスクリーンショットが撮れます。
await page.screenshot({ path: './screenshot.png', fullPage: true });
が、これだけだと少し問題があって・・・・
スクロールに応じてコンテンツを読み込むlazyloadの部分があったりだとか、アニメーションなどが付いているときに、その部分がうまくスクリーンショットに反映されないという問題があります。
これに対処するためには、Webページに移動した後に、一旦ページの下までスクロールさせることが必要です。
少しややこしいので、今回はpuppeteer-autoscroll-downというライブラリの力を借ります。
npm i puppeteer-autoscroll-down
まずは念の為、スクロール位置を一番上に。
page.evaluateは、引数に実行したいスクリプトを渡すと、そのスクリプトをページ上で実行してくれます。
await page.evaluate(_ => {
window.scrollTo(0, 0);
});
そして、puppeteer-autoscroll-downを使って、ページの下までスクロールします。
渡せるオプションは、
size: 一回のスクロール量
delay: スクロールを実行する間隔
stepsLimit: スクロールする回数の最大値
です。
無限スクロールが実装されているページなどはかなり長くなってしまうので、stepsLimitを設定して、よい塩梅にしておくと良いと思います。
const lastPosition = await scrollPageToBottom(page, {
size: 400,
delay: 250,
stepsLimit: 50
})
最後にブラウザを閉じます。
await browser.close();
コードの全体はこちら
const puppeteer = require('puppeteer-core');
const { scrollPageToBottom } = require('puppeteer-autoscroll-down');
(async () => {
const browser = await puppeteer.launch({
channel: 'chrome',
headless: true,
args: ['--lang=ja']
});
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 800, deviceScaleFactor: 2 });
await page.goto('https://qiita.com/');
await page.evaluate(_ => {
window.scrollTo(0, 0);
});
const lastPosition = await scrollPageToBottom(page, {
size: 400,
delay: 250,
stepsLimit: 50
})
await page.screenshot({ path: './screenshot.png', fullPage: true });
await browser.close();
})();
参考にさせていただいた記事
puppeteerで始めるブラウザ操作の自動化
puppeteer-coreとMacにインストール済みのChromeを使って自動操作
Puppeteer with lazy loading images
puppeteerで言語を日本語に設定する方法