今回は、Webページのスクリーンショットを撮るPowerShellスクリプト「getss.ps1」を仕上げる。具体的には、スクリーンショットからスクロールバーを消したり、netcat.ps1で実装した機能をマージしたりして、これまでに作った内容を整理していく。
前回の確認
まずは前回までに作成したgetss.ps1の確認だ。現状、getss.ps1は次のようになっている。
#!/usr/bin/env pwsh
#========================================================================
# スクリーンショットを取得する
#========================================================================
#========================================================================
# 引数を処理
# -URI uri スクリーンショットを取得するリソースのURI
# -Width width スクリーンショットの幅
# -Height height スクリーンショットの高さ
#========================================================================
Param(
[Parameter(Mandatory=$false)][String]$URI = "desktop:",
[Int]$Width = 1200,
[Int]$Height = 800
)
#========================================================================
# デフォルトのスクリーンショットファイル
#========================================================================
$outfile="${env:HOME}/ss.png"
#========================================================================
# スクリーンショットの取得に利用するアプリケーションほか
#========================================================================
$msedge='C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe'
$snippingtool='SnippingTool.exe'
$curl='C:\Windows\System32\curl.exe'
#========================================================================
# どの方法でスクリーンショットを取得するか判断
#========================================================================
switch -Wildcard ($URI)
{
'http*'
{
#========================================================
# Microsoft Edgeを使って取得
#========================================================
$method='msedge'
break
}
'desktop:*'
{
#========================================================
# Snipping Toolを使って取得
#========================================================
$method='snippingtool'
break
}
default
{
$method='none'
}
}
#========================================================================
# スクリーンショットを撮るリソース種類の特定
#========================================================================
$contenttype='none'
switch -Wildcard ($URI)
{
#================================================================
# コンテンツの種類を特定
#================================================================
'http*.html'
{
$contenttype='text/html'
break
}
'http*.htm'
{
$contenttype='text/html'
break
}
'http*.shtml'
{
$contenttype='text/html'
break
}
'http*/'
{
$contenttype='text/html'
break
}
'http*.txt'
{
$contenttype='text/plain'
break
}
'http*.csv'
{
$contenttype='text/csv'
break
}
'http*csv=1'
{
$contenttype='text/csv'
break
}
'http*.pdf'
{
$contenttype='application/pdf'
break
}
'http*.zip'
{
$contenttype='application/zip'
break
}
default
{
$contenttype=( & $curl --location `
-Ss -I `
$URI |
Select-String "^Content-Type:" )
break
}
}
#========================================================================
# スクリーンショットが取れないWebリソースの場合、代わりに
# http://example.com/ のスクリーンショットを取っておく
#========================================================================
switch -Wildcard ($contenttype)
{
#================================================================
# コンテンツの種類を特定
#================================================================
'*text/html*'
{
break
}
'*text/plain*'
{
break
}
'*/*'
{
$URI='http://example.com/'
break
}
}
#========================================================================
# スクリーンショットを取得
#========================================================================
switch ($method)
{
#================================================================
# Microsoft Edgeを使って取得
#================================================================
'msedge'
{
$o1='--headless'
$o2='--screenshot="' + ${outfile} + '"'
$o3="--window-size=${Width},${Height}"
Start-Process -FilePath $msedge `
-ArgumentList $o1,$o2,$o3,$URI `
-Wait
break
}
#================================================================
# Snipping Toolを使って取得
#================================================================
'snippingtool'
{
Start-Process -FilePath $snippingtool
# ※ -Waitは指定しても機能しない
break
}
}
今の時点で、もうほとんど実用に耐えるレベルにはあり、ほかのPowerShellスクリプトに組み込んだりして自動化処理に利用できる状態になっている。今回は、ここからさらに細かい部分を整理して仕上げていく。
保存先ファイルをパラメータで指定できるように変更
getss.ps1の内容を整理すると、次の部分に変更の余地があるように見える。
#========================================================================
# デフォルトのスクリーンショットファイル
#========================================================================
$outfile="${env:HOME}/ss.png"
ここではスクリーンショットを保存するファイルを固定化しているが、この部分はパラメータで指定できるようにしておいた方がよいだろう。ということで、パスを引数で指定するように次のように書き換える。
#========================================================================
# 引数を処理
# -URI uri スクリーンショットを取得するリソースのURI
# -Width width スクリーンショットの幅
# -Height height スクリーンショットの高さ
# -OutputFilePath path スクリーンショットを保存するファイル
#========================================================================
Param(
[Parameter(Mandatory=$false)][String]$URI = "desktop:",
[Int]$Width = 1200,
[Int]$Height = 800,
[String]$OutputFilePath = "${env:HOME}/ss.png"
)
パラメータ化するときに変数名(パラメータ名)を変更したので、それに合わせて次の部分も変更した。
#================================================================
# Microsoft Edgeを使って取得
#================================================================
'msedge'
{
$o1='--headless'
$o2='--screenshot="' + $OutputFilePath + '"'
$o3="--window-size=$Width,$Height"
Start-Process -FilePath $msedge `
-ArgumentList $o1,$o2,$o3,$URI `
-Wait
break
}
PowerShellスクリプトのparam()はとても強力で便利な機能だ。この機能を利用することでパラメータを簡単に用意でき、デフォルト値や強制指定なども設定できる。PowerShellスクリプトを書いていると、ほかのスクリプトにも欲しくなる機能だ。
1年、2年と経過してどんなパラメータを用意しておいたか忘れた頃になると、「getss.ps1 -[タブキー]」のようにタブキーを連打して用意してあるパラメータを探るだろう。このときにパラメータ名だけで何を指定するものなのかわかるようにしておくと良い。将来確実に発生するであろう“忘却”を予測して、最初からわかりやすいパラメータ名にしておくのが、楽するためのポイントだ。
HTTPサーバへUser-Agentを指定する
getss.ps1の中身は、本連載で以前作成したnetcat.ps1とよく似ている。netcat.ps1の中身は以下の通りだ。
#!/usr/bin/env pwsh
#========================================================================
# URLで指定されたリソースを取得
#========================================================================
#========================================================================
# 引数を処理
# -URL url WebリソースのURL
# -Agent agent リクエストで使うエージェントを指定
#========================================================================
Param(
[Parameter(Mandatory=$true)][String]$URL = "",
[String]$Agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
)
#========================================================================
# Webリソース取得に利用するアプリケーション
#========================================================================
$msedge='C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe'
$curl='C:\Windows\System32\curl.exe'
#========================================================================
# Webリソースの種類を取得
#========================================================================
switch -Wildcard ($URL)
{
'*.html' {
$ContentType='text/html'
break
}
'*.htm' {
$ContentType='text/html'
break
}
'*.shtml' {
$ContentType='text/html'
break
}
'*/' {
$ContentType='text/html'
break
}
'*.txt' {
$ContentType='text/plain'
break
}
'*.csv' {
$ContentType='text/csv'
break
}
'*csv=1' {
$ContentType='text/csv'
break
}
'*.pdf' {
$ContentType='application/pdf'
break
}
'*.zip' {
$ContentType='application/zip'
break
}
default {
$ContentType=(& $curl --location `
-A $Agent `
-Ss -I `
$URL |
Select-String "^Content-Type:")
break
}
}
#========================================================================
# どの方法でWebリソースを取得するかを判断
#========================================================================
switch -Wildcard ($ContentType)
{
#================================================================
# HTMLコンテンツ: JavaScriptでコンテンツを表示するタイプのページ
# にも対応するため、なるべくWebブラウザのヘッドレスモードを使用
#================================================================
'*text/html*' {
#========================================================
# Microsoft Edgeを使って取得
#========================================================
$method='msedge'
break
}
#================================================================
# それ以外のコンテンツは curl を使って取得
#================================================================
default {
#========================================================
# curlを使って取得
#========================================================
$method='curl'
break
}
}
#========================================================================
# Webリソースを取得
#========================================================================
switch ($method)
{
#================================================================
# Microsoft Edgeを使って取得
#================================================================
'msedge'
{
$o1='--headless'
$o2='--dump-dom'
$o3='--enable-logging'
$o4='--user-agent="$Agent"'
$tmpf=New-TemporaryFile
Start-Process -FilePath $msedge `
-RedirectStandardOutput $tmpf `
-ArgumentList $o1,$o2,$o3,$o4,$URL `
-Wait
Get-Content $tmpf
Remove-Item $tmpf
break
}
#================================================================
# curl を使って取得
#================================================================
'curl'
{
& $curl --location `
-A $Agent `
-get $URL
break
}
}
netcat.ps1ではcurl.exeとMicrosoft EdgeのヘッドレスモードでUser-Agentの指定を行っている。これは、User-Agentの指定を行わないとコンテンツが取得できないWebページが存在することへの対策だった。同じ問題は、getss.ps1にも当てはまる。
そこで、User-Agentの指定を行う機能をgetss.ps1にも実装する。該当部分を次のように書き換えればオッケーだ。
◆User-Agentをパラメータで用意
#========================================================================
# 引数を処理
# -URI uri スクリーンショットを取得するリソースのURI
# -Width width スクリーンショットの幅
# -Height height スクリーンショットの高さ
# -OutputFilePath path スクリーンショットを保存するファイル
# -Agent Webサーバへ送るUser-Agent文字列を指定
#========================================================================
Param(
[Parameter(Mandatory=$false)][String]$URI = "desktop:",
[Int]$Width = 1200,
[Int]$Height = 800,
[String]$OutputFilePath = "${env:HOME}/ss.png",
[String]$Agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
)
◆curl.exeでUser-Agentを指定した状態で動くように変更
default
{
$contenttype=( & $curl --location `
-A $Agent `
-Ss -I `
$URI |
Select-String "^Content-Type:" )
break
}
◆Microsoft Edgeのヘッドレスモードで、User-Agentを指定した状態で動くように変更
'msedge'
{
$o1='--headless'
$o2='--screenshot="' + $OutputFilePath + '"'
$o3="--window-size=$Width,$Height"
$o4='--user-agent="$Agent"'
Start-Process -FilePath $msedge `
-ArgumentList $o1,$o2,$o3,$o4,$URI `
-Wait
break
}
ここでもUser-Agentの指定にはparam()を利用した。param()はこのようにデータを整理する目的でも使えるので便利だ。