はじめに
Seleniumでページ全体のスクリーンショットを撮る際,以下のようなプログラムをよく目にしますが,複数のページを撮りたい場合にはあまりふさわしくないように感じます。
driver.get(url)
w = driver.execute_script('return document.body.scrollWidth')
h = driver.execute_script('return document.body.scrollHeight')
driver.set_window_size(w, h)
driver.save_screenshot('screenshot.png')
上記手法の問題点
-
別のページにアクセスする前にサイズをリセットする必要がある。
ページによっては画面のサイズやアスペクト比で表示形式を変えている場合があります。PC用(スマホ用)デザインで統一したい場合はでいちいちウィンドウサイズをリセットする必要があります。 -
動作が遅い
基本的にSeliniumの動作は遅いです。そのため複数のページに対して一連の作業を順にやらせていてはかなりの時間がかかってしまいます。
これら問題から,複数ページのスクリーンショットを取る場合はマルチプロセスで行うことをおすすめします!
コード
以下のプログラムはGitHubでも見ることができます。
import subprocess
def screenShotFull(driver, filename, timeout=30):
'''フルページ スクリーンショット'''
# url取得
url = driver.current_url
# ページサイズ取得
w = driver.execute_script("return document.body.scrollWidth;")
h = driver.execute_script("return document.body.scrollHeight;")
# コマンド作成
cmd = 'gtimeout ' + str(timeout) \
+ ' "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"' \
+ ' --headless' \
+ ' --hide-scrollbars' \
+ ' --incognito' \
+ ' --screenshot=' + filename + '.png' \
+ ' --window-size=' + str(w) + ',' + str(h) \
+ ' ' + url
# コマンド実行
subprocess.Popen(cmd, shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
解説
大まかな流れはコメントを読めば分かると思いますが,少しだけ補足させていただきます。
コマンドオプション
-
gtimeout
:プロセスの時間制限を設定。ページにアクセスできないなど,何らかの理由で処理が進まない場合にプロセスが残り続けてしまうことを防ぎます。インストールはbrew install coreutils
で。LinuxやWindowsの場合はtimeout
だったかな? -
headless
:ヘッドレス指定 -
hide-scrollbars
:スクロールバーを隠す -
incognito
:シークレットモード。拡張機能がオフになったり,履歴が残らなくなる。 -
screenshot
:スクリーンショット -
window-size
:ウィンドウサイズ指定。
ちなみにFirefoxを使用したい場合は,コマンドを以下のように変更すればOK。
Firefoxの場合はサイズ指定をしなくてもいいので少し簡単です。(ただしPC用デザインでしか取得できなくなる。)取得率があまり高くないようなので,私はChromeで取得できなかったときだけ使用するようにしています。
cmd = 'gtimeout ' + str(timeout) \
+ ' "/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox"' \
+ ' -headless' \
+ ' -private' \
+ ' -screenshot=' + filename + '.png' \
+ ' ' + url
-private
:プライベートモード(Chromeでいうシークレットモード)
使用例
driver.get(url)
screenShotFull(driver, filename='screenshot')
driver.close()