【PowerShell】WEB ページをアーカイブする

ちょっと必要に迫られて調べただけなので、中途半端な情報ですみません。役に立つ方がいらっしゃるかもしれないので投稿しておきます。

WEB サイトの移行や廃棄等で、既存のページのバックアップを取っておきたい場合があります。それも、大量にあるので出来る限り自動化したいという。

方法はいくつかあるのですが、代表的な方法として2つ考えられます。

※ここでは再現性の高い MHT 形式で保存するものとします。

1. CDO.Message を使用する

いにしえの方法で、こなれた感じではありますが、正直なところ出力結果に難ありです。

例えば、Tech Fielders サイトで公開されている、Windows Intune 利用時に知っておくべき Proxy Server 環境設定 | Tech Fielders コラム(三井情報株式会社 後藤 諭史 さん)を保存してみます。

$url = "https://www.microsoft.com/japan/powerpro/TF/column/sg_01_1.mspx" $filename = "c:\tmp\tf\sg_01_1.mht" $cdo = New-Object -ComObject "CDO.Message" $n = $cdo.CreateMHTMLBody( $url, 0, "", "") $objStm = $cdo.GetStream() $objStm.SaveToFile( $filename,  2)

実行結果は以下の通りです。読めなくはないですが、レイアウト的に微妙な感じですよねぇ。

image

ちなみに、CreateMHTMLBody メソッドの第二パラメタ「0」は、指定したURLの全てのコンテンツをダウンロードすることを示しています。

(参考)CdoMHTMLFlags Enum

また、SaveToFile に指定している 2 は $filename が存在している場合に上書きすることを示しています。1 を指定すると、同じファイルが存在する場合にエラーとなります。

2. IE の ExecWB を使用する

この方法は、IE で「ページを名前を付けて保存する」をスクリプトから実行するものです。IE から GUI を操作して保存した場合とまったく同じ結果を得ることができるため、結果の品質は申し分ありません。

ただ、問題がちょっとだけあります。それは、「名前を付けて保存」を自動化することができないということです。

以下のスクリプトの最終行に書かれている、ExecWB(4,0,$null,[ref]$null) は IE の「名前を付けて保存」ダイアログを呼び出すためのメソッドです。「4」が「名前を付けて保存」を意味しています。第二パラメタには「0」を指定していますが、「2」を指定するとプロンプトを表示しないで実行ができるはずなのです...が、どうもうまくいかない...ということで、だったらダイアログ操作を自動的にやってしまうことにしました。

$url = "https://www.microsoft.com/japan/powerpro/TF/column/sg_01_1.mspx" $code = '$WShell = New-Object -comobject WScript.Shell; ' $code = $code + '$WShell.AppActivate(''Web ページの保存'', $true); ' $code = $code + '$WShell.SendKeys(''%T'') ; ' $code = $code + '$WShell.SendKeys(''{DOWN}'') ; ' $code = $code + '$WShell.SendKeys(''{DOWN}'') ; ' $code = $code + '$WShell.SendKeys(''{ENTER}'') ; ' $code = $code + '$WShell.SendKeys(''%N'') ; ' $code = $code + '$WShell.SendKeys(''{HOME}'') ; ' $code = $code + '$WShell.SendKeys(''C:\TMP\TF\'') ; ' $code = $code + '$WShell.SendKeys(''%S'')' $ie = New-Object -ComObject InternetExplorer.Application $ie.Navigate( $url ) while ($ie.ReadyState -ne 4) { Start-Sleep -Milliseconds 100} Start-Process powershell.exe -argument ('-version 2.0 -noprofile -windowstyle hidden -command "{0}"' -f $code) $ie.ExecWB(4,0,$null,[ref]$null)

コードをご覧いただいてもわかるように、ちょっと特殊なことというか...古臭いことをしています。

Windows Script 時代からスクリプトを使っていた方ならばご存じの、SendKeys メソッドです。

(参考)Converting the Windows Script Host SendKeys Method

事前に、$code に WScript.Shell を使用した SendKyes メソッドを埋め込んでおきます。そして、ExecWB を実行する直前で、Start-Process コマンドレットを使ってスクリプトを実行しています。

こうすることで、ExecWB によって表示されたダイアログを SendKeys メソッドで操作することができます。

image

今回は Windows Script を使用しましたが、.NET Framework らしく [System.Windows.Forms.SendKeys] を使うこともできます。ただ、これだとコードが見づらくなってしまうので、個人的にはあまり好きじゃありません。

ちなみに、「名前を付けて保存」の便利なところは、ファイル名として自動的にWEBページのタイトルを使用してくれるところです。そのため、ファイル名の指定にも SendKey を使用するといった面倒なことをする必要がありません。

この他 WORD に読み込んで保存するなど方法はいくつかありますが、出力結果を比較すると、やはり ExecWB がベターかなといった感じです。