前回までに、Google Chartsを使ってグラフをレンダリングし、レンダリングした画像をPNG画像として保存するために必要な機能について取り上げてきた。後は、それらを組み合わせてPowerShellスクリプトにまとめれば完成だ。

→連載「PowerShell Core入門 - 基本コマンドの使い方」の過去回はこちらを参照。

Microsoft Edgeを遠隔操作してグラフをレンダリングする

前回までに、「Google Chatsを使ってグラフをレンダリングするためのHTML/JavaScript」を生成するPowerShellスクリプトを作成した。作業の中では、生成したHTML/JavaScriptを人間がMicrosoft Edgeで開き、そこに表示されるBase64エンコードの文字列をコピペした上で、これをデコードしてPNGの画像に変換するといったことを行っていた。

今回は、この人間が行っていた作業部分もPowerShellスクリプトから行うように自動化していく。

先に今回の成果物「test-9.ps1」を示しておこう。

#!/usr/bin/env pwsh

#========================================================================
# 気温データを取得して整理する
#========================================================================
$URL = 'https://www.data.jma.go.jp/obd/stats/data/mdrr/tem_rct/alltable/mxtemsad00.html'
$SrcFile = New-TemporaryFile
$OutFile = $env:HOMEDRIVE + $env:HOMEPATH + '\out.html'

curl        --get $URL                                      > $SrcFile 2> $null

#========================================================================
# Google Charts用HTMLの用意
#========================================================================
$DataName = '現在の気温'
$GraphTitle = '東京都の現在の気温'

$GoogleChartsHTML1 = @"
<html>
  <head>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript">
      // Google Visualization APIおよびコアチャートパッケージを読み込み
      google.charts.load('current', {'packages':['corechart']});

      // Google Visualization API読み込み完了後に実行
      google.charts.setOnLoadCallback(drawChart);
      function drawChart() {
        // データテーブルを作成
        var data = new google.visualization.DataTable();
        data.addColumn('string', '');
        data.addColumn('number', '$DataName');
        data.addRows([
"@

$GoogleChartsHTML2 = @"
        ]);

        // チャートオプションを設定
        var options = {'title':'$GraphTitle',
                       'width':500,
                       'height':300};

        // 初期化およびチャートの生成
        var chart = new google.visualization.BarChart(document.getElementById('chart_div'));

        // チャートイメージをbase64エンコードされたPNG画像データとして出力
        google.visualization.events.addListener(chart, 'ready', function () {
          document.getElementById('chart_base64').innerHTML = chart.getImageURI();
        });

        // チャートを描画
        chart.draw(data, options);
      }
    </script>
  </head>
  <body>
    <div id="chart_div"></div>
    <div id="chart_base64"></div>
  </body>
</html>
"@

#========================================================================
# 東京の気象データを抽出
#========================================================================
# 東京都の気象データを抽出
$s = (Get-Content $SrcFile | Select-String '>東京都</td')

# HTMLタグなどの不要なデータを削除
$s = $s     -replace '</[^>]+>',' '                         `
    -replace '<[^>]+>',''                           `
    -replace '([^)]+)[*]*',''

# 地名と気温を抽出
$GraphData = ""
$Indent = "          "
foreach ($l in $s) {
    $a = $l -split " "
    if ($GraphData) {
            $GraphData = $GraphData + ",['" + $a[2] + "'," + $a[3] + "]"
    }
    else {
            $GraphData = "$Indent['" + $a[2] + "'," + $a[3] + "]"
    }
}

#========================================================================
# Google Charts用のHTMLを出力
#========================================================================
$GoogleChartsHTML1                                  > $OutFile
$GraphData                                          >>$OutFile
$GoogleChartsHTML2                                  >>$OutFile

#========================================================================
# WebDriver起動
#========================================================================
webdriver_edge_start.ps1

#========================================================================
# Microsoft EdgeでGoogle Charts用のHTMLをオープン
#========================================================================
$FileURL = "file:///" + $OutFile.Replace('\','/')

'Microsoft Edgeでグラフを描画します。'
Set-SeUrl -Url $FileURL

#========================================================================
# WebDriverを終了
#========================================================================
#webdriver_edge_stop.ps1

#========================================================================
# 作業用の一時ファイルを削除
#========================================================================
Remove-Item $SrcFile
Remove-Item $OutFile

このPowerShellスクリプトは、Microsoft Edgeを遠隔操作で起動し、生成したHTML/JavaScriptを読み込み、グラフをレンダリングするところまでを自動的に行う。これまでに取り上げてきた機能と、今回のグラフ編に入る前のPowerShell Seleniumの機能を組み合わせて実現している。

PowerShellスクリプトの変更内容

書き換えた内容を詳しく見ていこう。まず、生成したHTML/JavaScriptはMicrosoft Edgeから開けるように拡張子HTMLのファイルとして保存しておく必要がある。これを実施するためにここでは次のようにホームディレクトリ以下に「out.html」というファイルを用意することにした。ファイル名がほかのファイルと重複する場合には適宜変更してもらえればと思う。

$OutFile = $env:HOMEDRIVE + $env:HOMEPATH + '\out.html'

生成したHTML/JavaScriptデータは、次のようにこのファイルに書き出すようにする。

$GoogleChartsHTML1                                  > $OutFile
$GraphData                                          >>$OutFile
$GoogleChartsHTML2                                  >>$OutFile

次に、Microsoft Edgeでこのファイルを開きたい。ここからはWebDriverとSeleniumの機能を使ってMicrosoft Edgeを操作する。本連載で説明してきたように、PowerShellからSelenium経由でMicrosoft Edgeを操作するには、対応するWebDriverをインストールし、PowerShell Seleniumモジュールをインストールする必要がある。その作業を手動でやるのは面倒なので、「webdriver_edge_start.ps1」というPowerShellスクリプトにまとめた。このPowerShellスクリプトを実行して、事前準備を完了させよう。

webdriver_edge_start.ps1

webdriver_edge_start.ps1は、付録として稿末に掲載してあるので、そちらを参照されたい。

次に、HTML/JavaScriptを出力したファイルのパスを、Microsoft Edgeで開けるURLになるように書き換える。

$FileURL = "file:///" + $OutFile.Replace('\','/')

PowerShell SeleniumモジュールのSet-SeUrlコマンドレットを使ってこのURLをMicrosoft Edgeに渡し、開く。

Set-SeUrl -Url $FileURL

これで今回の目的は達成された。後処理として、WebDriverなどを終了する処理を次のように加えておく。

webdriver_edge_stop.ps1

また、生成したHTML/JavaScriptを出力したファイルを削除する処理も加えておく。

Remove-Item $OutFile

これで自動的にMicrosoft Edgeが起動し、グラフのレンダリングが行われることになる。

実行して動作を確認する

作成したPowerShellスクリプトを実行すると、次のようにMicrosoft Edgeが起動する。

  • 実行して起動してくるMicrosoft Edge

    実行するとMicrosoft Edgeが起動する

実行した時点で気象庁のWebページに掲載されている東京都の気温データを取得し、グラフデータを生成していることがわかる。グラフデータをPNG画像にした場合のBase64エンコード文字列もを確認できる。

ポイントは、Webサービスの活用と自動化

現在は、さまざまなサービスがWeb経由で提供されるようになっている。多くのケースでWebブラウザを使ったサービスとして提供されており、日々の業務において欠かすことのできないツールとなっている。

こうしたサービスの利用を自動化できるかどうかは、業務効率を引き上げる上で重要なポイントになる。API経由で使おうとしてもそもそもAPIが提供されていない場合もあるし、Google Chartsのようにインタラクティブではない操作は禁止されていることもある。

こうした操作をPowerShellスクリプトから自動化できるという点で、PowerShell Seleniumはとても強力だ。ぜひとも活用していただきたい。

付録

webdriver_edge_start.ps1

#!/usr/bin/env pwsh

#========================================================================
# Microsoft Edge WebDriverを起動する
#========================================================================

#========================================================================
# 動作しているMicrosoft Edge WebDriverをすべて終了
#========================================================================
webdriver_edge_stop.ps1

#========================================================================
# Seleniumモジュールがない場合にはインストール
#========================================================================
if (-Not (Get-InstalledModule -Name Selenium 2> $Null)) {
    'Seleniumモジュールをインストールします。'
    Install-Module -Name Selenium -AllowPrerelease -Force
    Get-InstalledModule -Name Selenium
}

#========================================================================
# Microsoft Edge WebDriverを起動
#========================================================================
'Microsoft Edge WebDriverを起動します。'
$Size = '1200,800'
if  (-Not (Start-SeDriver -Browser Edge -Size $Size 2> $Null 3> $Null))
{
    #================================================================
    # Microsoft EdgeとMicrosoft Edge WebDriverのバージョンが一致して
    # いないためにドライバが動作しなかった可能性がある。
    #================================================================

    #================================================================
    # 不要なドライバプロセスを終了
    #================================================================
    webdriver_edge_stop.ps1

    #================================================================
    # Microsoft Edgeのバージョン番号
    #================================================================
    $EdgeDir='C:\Program Files (x86)\Microsoft\Edge\Application\'
    $EdgeVersion=(  Get-ChildItem -Name $EdgeDir                    | 
                    Where-Object { $_ -NotMatch "[a-zA-Z]+" }       |
                    Select-Object -First 1                          )
                    # ↑ 【Select-Object -First 1の理由】
                    # 更新前のバージョンと更新後のバージョンが同時に
                    # 存在するタイミングがあるので、更新後のバージョン
                    # のみを取得するためにSelect-Objectを実行している。

    #================================================================
    # Microsoft Edge WebDriverダウンロードURLとデプロイ先パス
    #================================================================
    $DriverURL="https://msedgedriver.azureedge.net/$EdgeVersion/edgedriver_win64.zip"

    $SeModVer=(Get-InstalledModule -Name Selenium).Version -replace "-.+$",""
    $DriverDir="$env:HOME\Documents\powershell\Modules\Selenium\$SeModVer\assemblies"
    $DriverDownloadDir="$DriverDir\_download"

    #================================================================
    # WebDriverダウンロード用の一時ディレクトリを作成
    #================================================================
    New-Item        $DriverDownloadDir -ItemType Directory -Force

    #================================================================
    # Microsoft Edgeと同じバージョンのMicrosoft Edge WebDriverを
    # ダウンロード
    #================================================================
    "Microsoft Edge WebDriver version $EdgeVersion をダウンロードします。"
    curl            -get                                            `
                    -o      $DriverDownloadDir\edgedriver_win64.zip `
                    $DriverURL

    #================================================================
    # Microsoft Edge WebDriverをデプロイ
    #================================================================
    "Microsoft Edge WebDriver version $EdgeVersion をインストールします。"
    Expand-Archive  -Path $DriverDownloadDir\edgedriver_win64.zip   `
                    -Destination $DriverDownloadDir                 `
                    -Force

    Copy-Item       -Path $DriverDownloadDir\msedgedriver.exe       `
                    -Destination $DriverDir\msedgedriver.exe        `
                    -Force

    #================================================================
    # WebDriverダウンロード用の一時ディレクトリを削除
    #================================================================
    Remove-Item     $DriverDownloadDir -Recurse -Force

    #================================================================
    # Microsoft Edge WebDriverを起動する
    #================================================================
    if      (-Not (Start-SeDriver -Browser Edge -Size $Size 2> $Null 3> $Null)) 
    {
            #========================================================
            # 原因不明の起動不能
            #========================================================

            #========================================================
            # 不要なドライバプロセスを終了
            #========================================================
            webdriver_edge_stop.ps1

            Exit
    }
}
'Microsoft Edge WebDriverの起動処理完了。'

webdriver_edge_stop.ps1

#!/usr/bin/env pwsh

#========================================================================
# Microsoft Edge WebDriverを終了する
#========================================================================

#========================================================================
# WebDriverプロセスを終了
#========================================================================
if  (Get-Process -Name msedgedriver 2> $Null) 
{
    '動作しているMicrosoft Edge WebDriverを終了します。'
    Get-Process -Name msedgedriver 2> $Null

    # Microsoft Edge WebDriverを終了
    Stop-SeDriver 2> $Null

    # まだ動作しているほかのMicrosoft Edge WebDriverを終了
    if      (Get-Process -Name msedgedriver 2> $Null) 
    {
            Get-Process -Name msedgedriver 2> $Null | Stop-Process
    }

    '動作しているMicrosoft Edge WebDriverの終了処理完了。'
}