[実例コードあり]Seleniumでページ全体のスクリーンショットを撮影する[JavaScript]

Web開発

お疲れ様です。すぺきよです。

今回はSeleniumとJavaScriptを使って、Webページ全体のスクリーンショットを撮影する必要があったので、その際に実装した内容を備忘録的にまとめます。

Seleniumというと、Pythonの方がサンプルがいっぱいあるので、Pythonで使っている方が多数派だと思いますが、私はあえてJavaScriptを使っています。

理由はWebアプリのフロントエンドでJavaScriptを使うことが多く、使い慣れているためです。

筆者の環境

まずは、筆者のこの記事を記述している時点での環境を書いておきます。

OS

macOS Ventura 13.5.2

Node.js

v18.17.1

必要なパッケージとインストール手順

JavaScriptで実装しますので、実行するためにはNode.jsが必要です。先にインストールしてください。

次に、コードなどを配置するためにお好きな場所にフォルダを作成します。

作成したフォルダまでターミナルなどで移動して、以下に示すインストール用のコマンドを利用して、必要なパッケージをインストールしてください。

selenium-webdriver

Seleniumを利用する際の本体のパッケージです。パッケージの公開ページはこちら

パッケージのインストールコマンドは以下の通り。

npm i selenium-webdriver

スクリーンショットを撮影するためのコード

必要なパッケージをインストールしたフォルダに、main.jsというファイルを作成し、以下のコードをコピーします。

今回は、私のブログのTOPのURLである「https://spekiyoblog.com/」をスクリーンショットの対象として指定しています。

let webdriver = require('selenium-webdriver');
let chrome = require('selenium-webdriver/chrome');
const fs = require('fs');

main();

//Chrome用のWebDriverを構築します
async function buildChromeDriver(version)
{
    let options = new chrome.Options();
    options.addArguments("--headless");//ヘッドレスモードに指定
    options.setBrowserVersion(version);

    return await new webdriver.Builder()
        .forBrowser('chrome')
        .setChromeOptions(options)
        .build();
}

//スクリーンショットを撮影して、ファイルに保存します。
async function saveScreenShotTo(driver, screen_width, save_file_path)
{
    await driver.manage().window().setRect({ width: screen_width, height: 1024 });
    const page_width = await driver.executeScript("return document.body.scrollWidth;");
    const page_height = await driver.executeScript("return document.body.scrollHeight;");
    await driver.manage().window().setRect({ width: page_width, height: page_height });

    //スクリーンショットを取得
    let ss = await driver.takeScreenshot();

    //一旦ファイルに書き出す。
    fs.writeFileSync(save_file_path, ss, 'base64');
}

//指定のURLに遷移します。
async function navigateToURL(driver, url, wait = undefined)
{
    await driver.get(url);
    if(wait)
    {
        await driver.wait(wait);//条件に合わせて待機する
    }
}

//指定されたURLのスクリーンショットを撮影する。
async function takeScreenShot(driver, url, screen_width, wait = undefined, save_file_path = "./screen_shot.png")
{
    await navigateToURL(driver, url, wait);
    await saveScreenShotTo(driver, screen_width, save_file_path);
}

//メイン関数
async function main()
{
    //WebDriverを作る
    let driver = await buildChromeDriver("stable");
    //スクリーンショットを撮影
    await takeScreenShot(driver, "https://spekiyoblog.com/", 1280, webdriver.until.elementLocated(webdriver.By.className('footer')), "./spekiyo.png");
    //ドライバーを閉じる
    await driver.quit();
}

実行する

main.jsファイルにコードをペーストしたら、次のコマンドで実行します。

node main.js

Chromeが起動し、ページにアクセスした後、スクリーンショットが撮影され、main.jsと同じディレクトリ内に「spekiyo.png」というファイルで保存されているはずです。

撮影の原理と注意点

原理

画面の横幅を一度指定した後、その横幅で表示した時のページ全体の高さを取得します。

ページ全体の高さとブラウザの高さを合わせてスクリーンショットを撮影するという流れになります。

横幅をあらかじめ指定することで、レスポンシブ対応のページでも任意の横幅のモードで撮影することも可能です。

注意点

物理的な画面のサイズを超えてウィンドウを大きくすることができないためか、WebDriverをヘッドレスモード(ブラウザのWindowを生成せずにバックグラウンドで実行するモード)で構築しないと、画面全体が撮影できません。

ヘッドレスモードを使わない場合、物理的な画面の高さいっぱいに表示されたページのスクリーンショットが撮影されます。

また、ウィンドウの高さで大きさが変わる要素がページ内に存在しているとうまく撮影できませんし、スクロールされて初めて要素がゆっくり表示されるページでは、スリープを挟まないとうまく撮影できません。

この辺りはページの要件によって要調整ですね。

さいごに

今回は、SeleniumとJavaScriptを使ってスクリーンショットを撮影する方法を紹介してみました。

ヘッドレスモードを使えば、物理的な画面サイズを超えて撮影できることを気づかず苦労しました。

何かの参考になれば幸いです。

タイトルとURLをコピーしました