Webサイトのスクリーンショットを自動化する方法
Web サイトのスクリーンショットはブラウザの開発ツールや拡張機能を利用すれば手軽に行えます。しかし、あらかじめスクショしたいサイトやページが決まっていてかつ複数ページある場合では都度ページを開いて作業しているとそれなりに時間がかかります。
この記事ではそんな手動でのスクリーンショット作業を自動化させる方法を紹介します。
知らない単語が途中出てきても何ができるのかイメージだけつかんでもらえれば大丈夫です。
実行環境の用意
今回スクリーンショットの自動化を Python という言語で行います。「Python って何!?」という方は以下リンクの情報を軽く見ておいてもらえると多少理解が進むかと思います。
手元のローカル PC で今回やるような処理を実行するには Python 自体をインストールする必要があります。この記事ではそのような環境構築の手間を省くため Google が提供する Colaboratory と呼ばれるサービスを利用します。
Colaboratory の利用方法は以下記事の一部を参照してみてください。ファイルの準備まで確認できれば OK です。
スクリーンショット自動化スクリプトの作成
Colaboratory で新規ファイルの用意ができたら今回やりたいことの整理をしたいと思います。
最低限やりたいことは主に以下の 3 つです。
- サイト URL を指定するだけでスクリーンショットを自動実行したい
- 取得した画像を一括ダウンロードしたい
- ウインドウサイズを指定してスクリーンショットを撮りたい
すぐに利用したい方はコピペで利用できるので「スクリーンショット自動化スクリプトの利用方法」から読み進めてください。
必要ファイルやライブラリの読み込み
chromium-browserエラー対応方法に関するコメントはこちら
コードブロックを追加し、以下処理を記述し、実行します。
%%shell
# Ubuntu no longer distributes chromium-browser outside of snap
#
# Proposed solution: https://askubuntu.com/questions/1204571/how-to-install-chromium-without-snap
# Add debian buster
cat > /etc/apt/sources.list.d/debian.list <<'EOF'
deb [arch=amd64 signed-by=/usr/share/keyrings/debian-buster.gpg] http://deb.debian.org/debian buster main
deb [arch=amd64 signed-by=/usr/share/keyrings/debian-buster-updates.gpg] http://deb.debian.org/debian buster-updates main
deb [arch=amd64 signed-by=/usr/share/keyrings/debian-security-buster.gpg] http://deb.debian.org/debian-security buster/updates main
EOF
# Add keys
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys DCC9EFBF77E11517
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 112695A0E562B32A
apt-key export 77E11517 | gpg --dearmour -o /usr/share/keyrings/debian-buster.gpg
apt-key export 22F3D138 | gpg --dearmour -o /usr/share/keyrings/debian-buster-updates.gpg
apt-key export E562B32A | gpg --dearmour -o /usr/share/keyrings/debian-security-buster.gpg
# Prefer debian repo for chromium* packages only
# Note the double-blank lines between entries
cat > /etc/apt/preferences.d/chromium.pref << 'EOF'
Package: *
Pin: release a=eoan
Pin-Priority: 500
Package: *
Pin: origin "deb.debian.org"
Pin-Priority: 300
Package: chromium*
Pin: origin "deb.debian.org"
Pin-Priority: 700
EOF
# Install chromium and chromium-driver
apt-get update
apt-get install chromium chromium-driver
# Install selenium
pip install selenium
Colaboratory は標準で日本語フォントが入っていないようで、フォントを入れずに動かすと文字化けしてしまいます。(2021/03/28)
# 日本語フォントインストール
!apt-get -y install fonts-ipafont-gothic
!apt-get -y install fonts-ipafont-mincho
スクリーンショットの自動化スクリプトをすべて一からプログラムを書いていくとめちゃくちゃ時間がかかってしまうので、ライブラリと呼ばれる複雑な処理を抽象化して使いやすくしたプログラムを利用します。
ブラウザ操作を自動化させるため Selenium をインストールします。Selenium はブラウザ操作を自動化させるのに必要なフレームワークです。
# ライブラリインポート
from google.colab import files
import time
import shutil
import os
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Chromeヘッドレスモード起動
options = webdriver.ChromeOptions()
options.headless = True
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome('chromedriver',options=options)
driver.implicitly_wait(10)
ブラウザを裏側で起動させてスクリーンショットをとるために Headless Chrome を利用します。
Headless Chrome はブラウザーの UI を利用せずにブラウザ操作することを可能にします。
たとえば「Chrome を立ち上げてサイトにアクセスして・・・」といった作業をコマンドで指定できます。
スクリーンショットを撮りたいサイトリストを以下のように記述します。
# 対象URL
urls = ['https://example.com', 'https://example.com/about/']
次に調整用の変数を定義しておきます。変数を定義しておくことで、ブラウザのウインドウサイズやファイル名を後から調整しやすくします。
ファイル名の接頭辞は fileNamePrefix
で調整できます。screen
とすると screen-1.png
のように連番で保存されます。
ウインドウ幅 375px でスクリーショットを撮りたい場合は windowSizeWidth = 375
と指定します。ウインドウ幅を指定した場合、 screen-1200-1.png
のようにサイズがファイル名に付与されます。
ウインドウの高さを指定したい場合も幅と同様です。
windowSizeHeight = 1000
ファイル名が被らないように連番を付与させるため番号の初期値を指定します。
shotNum = 0
# ファイル名接頭辞
fileNamePrefix = "screen"
# ウインドウ幅指定
# 初期値: False, スマホ: 375
windowSizeWidth = False
# windowSizeWidth = 1200
# ウインドウ高さ指定
# 初期値: False
windowSizeHeight = False
# windowSizeHeight = 1000
# 連番初期値
shotNum = 0
ダウンロードフォルダーの作成を以下の処理で行います。
# ダウンロードフォルダ作成
folderCheck = os.path.exists('screen-shot')
if folderCheck:
shutil.rmtree('screen-shot')
os.mkdir('screen-shot')
urls で定義したサイトにアクセスし、スクリーショットを撮る処理が以下に記述されています。
スクロールされてから要素が表示されるような表現に対応するため、わざとサイト下部までスクロールする処理を入れています。
# 繰り返し処理
for url in urls:
# パス指定
folderPath = 'screen-shot/' + fileNamePrefix + '-' + str(windowSizeWidth) + '-' if windowSizeWidth else 'screen-shot/' + fileNamePrefix + '-'
# サイトURL取得
driver.get(url)
WebDriverWait(driver, 15).until(EC.presence_of_all_elements_located)
# ウインドウ幅・高さ指定
windowWidth = windowSizeWidth if windowSizeWidth else driver.execute_script('return document.body.scrollWidth;')
windowHeight = windowSizeHeight if windowSizeHeight else driver.execute_script('return document.body.scrollHeight;')
driver.set_window_size(windowWidth, windowHeight)
# スクロール処理
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
# 処理後一時待機
time.sleep(3)
# ファイル連番追加
shotNum += 1
shotNumStringified = str(shotNum)
# スクリーンショット格納
driver.save_screenshot(folderPath + shotNumStringified + '.png')
# サーバー負荷軽減処理
time.sleep(1)
# ブラウザ稼働終了
driver.quit()
最後に保存したスクリーンショットを zip ファイルにまとめてダウンロードする処理を記述します。
# zipファイル変換ダウンロード
!zip -r download.zip screen-shot
files.download('download.zip')
以上でコードの記述は完了です。
スクリーンショット自動化スクリプトの利用方法
サイト URL を指定するだけでスクリーンショットを自動実行し、一括でファイルをダウンロードできます。次の完成スクリプトをそのままコピペして利用できます。すぐに利用したい方は対象 URL だけ適宜調整してください。
まず新規でブロック追加し、以下コードを記述します。添付ができれば一度実行します。
処理を実行する際は赤枠の ▷ ボタンを押下してください。
上記コードの実行ができれば、さらに新規でブロックを追加して同様に以下コードをコピペします。
最後、上記コードを実行するとスクリーンショットの処理が実行されます。
ダウンロードファイルの管理
スクリーンショットされた画像ファイルは download.zip ファイルに格納されます。
意図的に格納ファイルを削除してリセットしたい場合は左サイドバーの 🗂 アイコンを押下し、download.zip ファイルを削除できます。
まとめ
アニメーションで画面が大きく変わるサイトではうまくスクリーンショットを取れないケースがあるかもしれません。そのような場合は処理のタイミングを遅らせてみるなど調整してみてください。
Web 制作の現場ではスクリーンショットをとる作業がよくあるかと思います。今回紹介した内容が時間の効率化に繋がれば幸いです。
Discussion
yonemotoさま
記事拝見して、とても関心を持ちました。いきなりですが、薄謝ではありますがご提供させていただいたうえで、特定のサイト(観光予報プラットフォーム、公益社団日本観光振興協会)の向こう3か月の観光需要の予測画面を、約1週間おきにスクショし続けるプログラムを組んでいただくことは可能でしょうか?
コメントありがとうございます!この記事で紹介するColaboratoryは定期実行に対応していないため、記載いただいた要件ですと一からスクラッチで開発するより以下のようなサービスを使われるのが良いかと思います。
ご親切にありがとうございました。よく見てみます。
えーと
seleniumのv4系を入れたらoptions.add_argument("--headless")が使えなくなっており、options.headless = Trueでできるらしいです。
ご指摘ありがとうございます。取り急ぎ修正しました。
僕も同じように混乱したのでお互い様ですね。。。
とても参考になる記事をありがとうございます。
いつもこの記事を参考にスクリーンショットをとっているのですが、colaboのアップデートに伴い以下部分でエラーが発生するようになってしまいました。
driver = webdriver.Chrome('chromedriver',options=options)
解決策のようなものは見つけられたのですが、初心者には難しく、
よろしければご教示いただけないでしょうか?
ttps://github.com/googlecolab/colabtools/issues/3347
確認したところ私の方でも同様のエラーが確認できました。
原因は以下に記載いただいた参照先通りのようでした。
以下手順で対応できるかと思います。
1 ランタイムの接続削除(Colabのメニューから実行)
2. 事前処理コードの追加と実行
以下コードを本体コードの前にコードブロックを追加し、以下処理のみ先に実行します。
3. 本体コード(スクリーンショット用)を実行
本体コードのselenium、chromium、chromium-driverインストール部分が2の処理と重複するため削除。
上記修正ができれば、本体コードを実行します。
迅速なご対応とご返信ありがとうございます。
いただいた内容で試してみたのですが、以下のような別の行でエラーが出てしまい、
ダウンロードにまでいかないみたいなのですが、こちらはまた別の問題になりますでしょうか…?
行: driver.save_screenshot(folderPath + shotNumStringified + '.png')
▼エラー
TimeoutException: Message: timeout: Timed out receiving message from renderer: 10.000
(Session info: headless chrome=90.0.4430.212)
以下のようなエラーが出ているので、対象サイト側の問題が高いかもです。
サイトをもう一度確認してみます。
ご丁寧にご対応いただきありがとうございました!
こちらの記事参考にして自動取得試してるのですが、
添付画像のコードで実行してもまだ下記エラーが消えません。
こちらのスレッドの3.本体コードの削除箇所について、本体コードにて該当箇所が見当たらないためどこを削除すれば良いのでしょうか?Seleniumのバージョン変更が原因のエラーのようです。
以下のように調整することで対応できました。
ありがとうございます。
無事エラー解消され、スクショ取得できました。
また別の問題が発生しており、申し訳ございませんがアドバイスいただけますと幸いです。
【問題】
一部ページがウィンドウ長すぎて、ページ全体のスクショが取れないです。
現状、windowSizeHeight = Falseだと全体が取れずwindowSizeHeight = "数値"にすると他の関係ないページが余白取得してしまいます。
False以外でページ別に全体取得できる値ありますでしょうか?
もしくは他の#スクロール処理 #サーバー負荷軽減処理などで対処できますでしょうか?