1. 序章

このチュートリアルでは、コマンドラインからWebサイトのスクリーンショットを撮るためのいくつかのアプローチを見ていきます。 典型的な使用例は、GUIを使用せず、sshを介してのみアクセス可能なリモート環境で自動スクリーンショットを撮ることです。

すべてのアプローチに、更新されたUbuntu Server20.04LTSを使用します。

2. ヘッドレスFirefox

ヘッドレスブラウザは、GUIのない環境でWebページの自動制御を提供します

Firefoxには、-screenshot フラグが用意されており、Webサイトの全ページのスクリーンショットを撮ることができます。

$ firefox -headless -screenshot myscreenshot.png https://www.baeldung.com/

ウィンドウのサイズを指定できます。 たとえば、スマートフォンでレイアウトの応答性をテストしたい場合があります。 サイズを指定しない場合は、デフォルトの幅1366pxが使用されます。

画面の表示部分だけを取得しましょう。

$ firefox -headless -screenshot myscreenshot.png -window-size 360,640 https://www.baeldung.com/

ページ全体を取得するために、ウィンドウの幅のみを指定することもできます。

$ firefox -headless -screenshot myscreenshot.png -window-size 360 https://www.baeldung.com/

Firefoxは非常に冗長ですが、次のようなメッセージが表示された場合でも、スクリーンショットは正しく保存されます。

user@Ubuntu-LTS:—$ firefox -headless -screenshot myscreenshot.png https://www.baeldung.com/
*** You are running in headless mode.
[GFX1-]: glxtest: libGL.so.1 missing
[GFX1-]: glxtest: libEGL missing
user@Ubuntu-LTS:—$ firefox -headless -screenshot myscreenshot.png -window-size 360,640 https://www.baeldung.com/
*** You are running in headless mode.
[GFX1-]: glxtest: libGL.so.1 missing
[GFX1-]: glxtest: libEGL missing

###!!! [Parent][MessageChannel] Error: (msgtype=0x390078,name=PContent::Msg_DestroyBrowsingContextGroup) Closed channel: cannot send/recv

user@Ubuntu-LTS:—$ firefox -headless -screenshot myscreenshot.png -window-size 360 https://www.baeldung.com/
*** You are running in headless mode.
[GFX1-]: glxtest: libGL.so.1 missing
[GFX1-]: glxtest: libEGL missing

###!!! [Parent][MessageChannel] Error: (msgtype=0x390078,name=PContent::Msg_DestroyBrowsingContextGroup) Closed channel: cannot send/recv 

firefox –help を使用して、使用可能な他のコマンドラインパラメーターを調べることができます。

2.1. クッキーおよびその他の情報の受け入れ

場合によっては、ユーザーが最初にサイトを開いたときの外観のスクリーンショットを撮りたいことがあります。

キャッシュとCookieをクリーンに保つために、-private-windowフラグを使用できます。

$ firefox -headless -private-window -screenshot myscreenshot.png https://www.baeldung.com/

また、ユーザーがサイトとの重要なやり取りを行った後にスクリーンショットを撮りたい場合もあります。 たとえば、ユーザーがCookieを受け入れた後、またはログインした後です。 または、Firefox拡張機能がアクティブなスクリーンショットを撮りたい場合があります。たとえば、広告をブロックするためのものです。

まず、次のコマンドを使用して、GUIを提供しないリモートサーバーに接続してスクリーンショットを撮るとします。

$ firefox -headless -screenshot myscreenshot.png -window-size 360,640 https://www.baeldung.com/

サイトを操作しなくても、次のようになります。

したがって、Cookieを受け入れるにはリモートFirefoxを開く必要があります。 このために、ssh-Yおよび-Cフラグとともに使用します。 xxxxをリモートサーバーのドメインまたはそのIPアドレスに置き換えましょう。

$ ssh -Y -C [email protected]

ここで、 -Y オプションは、信頼できるX11転送を有効にします。 -C オプションは、圧縮を使用してパフォーマンスを向上させます。

次に、-no-remoteフラグを指定してFirefoxを開きます。

# firefox -no-remote

X11転送のおかげで、リモートFirefoxはローカル環境でGUIを実行します。 したがって、Cookieを受け入れてから、Firefoxを閉じて、スクリーンショットを撮ってみてください。

# firefox -headless -screenshot myscreenshot.png -window-size 360,640 https://www.baeldung.com/

そして、ここに結果があります:

2.2. 考えられる問題

キャプチャされた画像は、ファイル拡張子に関係なく、常にPNG形式になります。

現在、バグ1693011 のため、Firefoxの複数のインスタンスで一度にスクリーンショットを撮ることはできません。

時々、FirefoxはX11転送後にスクリーンショットを撮るのをハングすることがあります ssh-Y。 これを解決するには、 -Y 国旗。

3. ヘッドレスクロームまたはクロム

Chrome(またはChromeのオープンソース版であるChromium)を使用して、Webサイトのスクリーンショットを撮ることもできます。

root としてログに記録される場合は、 –no-sandboxフラグを追加する必要があります。 このフラグがないと、Chromeは起動しません。

ただし、サンドボックスを無効にすると、システムがWebページを介したエクスプロイトに対して脆弱になるため、Googleは推奨していません。 つまり、 GoogleはChromeをルートとして使用することを強く推奨していないため、は使用しません。

そのため、 rootとしてログインしている場合は、新しい標準ユーザーを追加し、このユーザーの権限で次のコマンドを実行することをお勧めします

# adduser browser
# sudo -i -u browser

-u フラグは、ターゲットユーザーを指定します。 -i フラグは、「初期ログインをシミュレートする」ことを意味し、ターゲットユーザーのパスワードデータベースエントリで指定されたシェルをログインシェルとして実行します。 これは、シェルが .profile .bash_profile などのログイン固有のリソースファイルを読み取ることを意味します。 ] .login

ブラウザユーザーのホームディレクトリでデスクトップのスクリーンショットを撮りましょう。 デフォルトのサイズは800×600ピクセルです。

Firefoxの場合と同様に、-headlessフラグを使用してヘッドレスモードを使用する必要があります。

$ google-chrome --headless --screenshot="myscreenshot.png" https://www.baeldung.com/

残念ながら、次の画像が結果です。

以前は、同じWebサイトでFirefoxでのこのアクセスの問題は発生しませんでした。 このサイトは、ヘッドレスブラウザを認識してブロックするための戦略を採用している場合があります。

3.1. Puppeteer:ChromeまたはChromiumを制御するための高レベルAPI

この場合、遅延を追加することを試みることができますが、Chromeのドキュメント( google-chrome –help で利用可能)には、この目的のためのコマンドラインフラグがリストされていません。 そのため、Puppeteerを使用します。

Puppeteerは、ChromeまたはChromiumを制御するための高レベルのAPIを提供するノードライブラリです。

デフォルトでは、ヘッドレスで実行され、自動化を実行できます。 インストール中に、APIでの動作が保証されている最新バージョンのChromiumをダウンロードします。

$ npm i puppeteer

Puppeteerを使用するには、JavaScriptコードが必要です。 myScreenshot.jsファイルを作成しましょう。

const puppeteer = require('puppeteer');

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
};

(async() => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.setViewport({width: 800, height: 600})
    await page.goto('https://www.baeldung.com/');
    await timeout(5000)
    await page.screenshot({path: 'myscreenshot.png'});
    browser.close();
})();

簡単に言うと、このスクリプトは puppeteer モジュールをロードし、puppeteer変数でアクセスできるようにします。 次に、遅延を取得するためのtimeout関数を定義します。

次に、指定されたサイズのウィンドウでブラウザを非同期的に起動し、指定されたURLを開き、5秒間待機して、最後にスクリーンショットをキャプチャし、ブラウザを閉じます。

詳細については、 PuppeteerAPIを参照してください。

試してみましょう:

$ node myScreenshot.js

繰り返しますが、結果は私たちが望むものではありません。 遅延を追加すると、追加のハードルが発生しました–キャプチャを渡すための要件:

したがって、このWebサイトの場合、遅延によってヘッドレスブラウザの検出が回避されることはありません。 より複雑な戦略を使用する必要があります。

3.2. ヘッドレスクロムの検出を避ける

ヘッドレスChromiumを検出するすべての方法を防ぐことはおそらく不可能ですが、検出を回避するプラグインであるpuppeteer-extra-plugin-stealthのおかげで最善を尽くすことができます

$ npm install puppeteer-extra puppeteer-extra-plugin-stealth

myScreenshot.js を変更して、ステルスプラグインを使用するようにします。 まず、すべての回避手法を使用して適切なモジュールをロードしましょう。

// puppeteer-extra is a drop-in replacement for puppeteer,
// it augments the installed puppeteer with plugin functionality
const puppeteer = require('puppeteer-extra');

// add stealth plugin and use defaults (all evasion techniques)
const StealthPlugin = require('puppeteer-extra-plugin-stealth')
puppeteer.use(StealthPlugin())

残りのコードはほとんど同じです。timeout関数とそれを呼び出すコード行を削除するだけで済みます。

結果は次のとおりです。

Firefoxで見たように、X11転送を使用して、ブラウザーを開き、Cookieを受け入れることができます。 ただし、 .Xauthority ファイルをコピーして適切な権限を設定するには、3つの追加コマンドが必要です。 このファイルは、通常のユーザーとしてX11転送に必要です。

$ ssh -Y -C [email protected]
# cp /root/.Xauthority /home/browser/
# chown browser:browser /home/browser/.Xauthority 
# chmod 0600 /home/browser/.Xauthority
# sudo -i -u browser

それがすべてではありません。 ChromeまたはChromiumを直接開くことはできません。 代わりに、Puppeteerを使用する必要があります。

したがって、ヘッドレスモードを無効にし、セッションデータをuser_dataフォルダーに保存します。

const puppeteer = require('puppeteer-extra');
const pluginStealth = require('puppeteer-extra-plugin-stealth')();
puppeteer.use(pluginStealth);

(async() => {
    const browser = await puppeteer.launch({headless:false, userDataDir: "./user_data"});
    const page = await browser.newPage();
    await page.setViewport({width: 360, height: 640});
    await page.goto('https://www.baeldung.com/');
    // await page.screenshot({path: 'myscreenshot.png'});
    // browser.close();
})();

これで、ChromiumGUIを起動してCookieを受け入れることができます。

$ node myScreenshot.js

その後、ユーザーのホームにディレクトリuser_dataがあります。 保存したセッションを読み込んだ後、コードをもう一度編集してスクリーンショットを撮りましょう。

const puppeteer = require('puppeteer-extra');
const pluginStealth = require('puppeteer-extra-plugin-stealth')();
puppeteer.use(pluginStealth);

(async() => {
    const browser = await puppeteer.launch({headless:true, userDataDir: "./user_data"});
    const page = await browser.newPage();
    await page.setViewport({width: 360, height: 640});
    await page.goto('https://www.baeldung.com/');
    await page.screenshot({path: 'myscreenshot.png'});
    browser.close();
})();

それを実行しましょう:

$ node myScreenshot.js

そして、結果は次のとおりです。

フルページのスクリーンショットを取得するには、次の行を編集します。

await page.screenshot({path: 'myscreenshot.png', fullPage: true});

4. 結論

この記事では、FirefoxとChromeを使用してコマンドラインからスクリーンショットを撮る方法を見てきました。 他のツールもありますが、これら2つのブラウザーは常に更新されており、ユーザーに表示されるように、ページの正しいレンダリングを保証します。

セッションを保存し、自動化されたツールに対する保護をバイパスする必要があるという重要なケースに直面しました。 特にパペッティアは、優れたコントロールを提供してくれます。