🪅

Power Automate Desktop Webページからデータを抽出する 2

2024/01/31に公開

Webスクレイピング

はじめに

PADでスクレイピングの2回目。
前回は、抽出したい属性を一つずつ選択しました。今回は違う方法を試してみます。
前回: Power Automate Desktop Webページからデータを抽出する


レシピ

Microsoft Rewardsのポイント履歴をExcelに出力して保存します。
抽出する項目

  • 状態
  • 日付
  • リワード
  • ポイント

スクレイピングする

まず初めに、スクレイピングの部分から作っていきます。
Microsoft Rewardsのサイトを開いて、注文履歴を表示します。
PADから新しいフローを追加します。フロー名は適当にどうぞ。

  1. 新しい Microsoft Edge を起動
    今回は、毎回URLから開くようにします。
    ただ、デバッグの度に毎回ウィンドウが開くのは鬱陶しいので最初は開いたまま作りこみます。
    開きっぱなしにしていた方が、例えば今回はUI要素は使っていませんが、セレクターのテストするときなどにも便利だと思います。
    実行中のインスタンスに接続する
    完成後にこの状態にします。
    新しいインスタンスを起動する

  2. Webページからデータを抽出する
    テーブルからどこでもいいので要素を選んで、HTMLテーブル全体を抽出します。
    HTMLテーブル全体を抽出

  3. 抽出プレビューで確認
    この方法で抽出した場合は、ヘッダー名が日本語でとれるみたいです。
    ポイント #1と#2は要らないので.NETスクリプトで削除しようと思います。
    抽出プレビュー
    リワードのテキストも弄ろうと思います。
    リワードの値

  4. ここまでのコード

PAD
FUNCTION Main_copy GLOBAL
    WebAutomation.LaunchEdge.AttachToEdgeByTitle TabTitle: $'''リワードの引き換え''' AttachTimeout: 5 BrowserInstance=> Browser
    WebAutomation.ExtractData.ExtractHtmlTable BrowserInstance: Browser Control: $'''html > body > div:eq(0) > div:eq(1) > main > div:eq(1) > div:eq(1) > div:eq(1) > table''' ExtractionParameters: {[$'''状態''', $'''日付''', $'''リワード''', $'''ポイント''', $'''ポイント #1''', $'''ポイント #2'''], [$'''''', $'''''', $'''''', $'''''', $'''''', $''''''] } PostProcessData: False TimeoutInSeconds: 60 ExtractedData=> DataFromWebPage
END FUNCTION

スクレイピングの作りこみは完成。


.NETスクリプトを使う

DataTableに格納できたので、ここから.NETスクリプトでデータを弄っていきます。

今はこの状態になっています。

状態 日付 リワード ポイント ポイント #1 ポイント #2

↓ポイント #1 / #2を削除して以下のようにします。

状態 日付 リワード ポイント

.NET スクリプト実行

Language: C#
.NET script imports:
Script Parameters:

.NET parameter name Type Direction Input value Output value
dt Datatable In-Out %DataFromWebPage% %DataFromWebPage%
.NET code to run
dt.Columns.Remove("ポイント #1");
dt.Columns.Remove("ポイント #2");

var table = dt.Clone();
foreach (DataRow row in dt.Rows)
{
	var s = row["リワード"].ToString();
	var position = s.IndexOf("注文番号");
	var rewards = s.Substring(0, position).Trim();	
	table.Rows.Add(row["状態"], row["日付"], rewards, row["ポイント"]);
}
dt = table;

何のアイテムに引き換えたかだけで十分なので
IndexOfを使って注文番号より前のテキストを取得してトリムします。

実行して確認します。
OK

https://learn.microsoft.com/ja-jp/power-automate/desktop-flows/how-to/delete-column-datatable


Excelにデータを書き込む手順は省略

省略。


VBSを使います

Excelの仕上げはVBSでやっちゃいます。

VBScript の実行

Run VBScript
Option Explicit

Dim objExcel, objWorkbook, objSheet
Set objExcel = CreateObject("Excel.Application")
objExcel.Application.Visible = False
Set objWorkbook = objExcel.Workbooks.Open("%ExcelFile%")
Set objSheet = objWorkbook.Sheets(1)

Dim dataAll
Set dataAll = objSheet.UsedRange
dataAll.Borders.LineStyle = True

Const xlCenter = -4108
Const xlThemeColorAccent6 = 10
Dim header
Set header = dataAll.Resize(1)
With header
    .HorizontalAlignment = xlCenter
    .Interior.ThemeColor = xlThemeColorAccent6
    .Interior.TintAndShade = 0.8
End With

objWorkbook.Save
objWorkbook.Close True
objExcel.Quit

完成

VBScriptで罫線を引いて、ヘッダーを中央揃え・セルの塗りつぶしを行いました。

完成

完成フロー
FUNCTION Main_copy GLOBAL
    **REGION 設定
    Folder.GetSpecialFolder SpecialFolder: Folder.SpecialFolder.Personal SpecialFolderPath=> Documents
    SET ExcelFile TO $'''%Documents%\\MicrosoftRewards.xlsx'''
    **ENDREGION
    **REGION スクレイピング
    WebAutomation.LaunchEdge.LaunchEdge Url: $'''https://rewards.bing.com/redeem/orderhistory''' WindowState: WebAutomation.BrowserWindowState.Normal ClearCache: False ClearCookies: False WaitForPageToLoadTimeout: 60 Timeout: 60 BrowserInstance=> Browser
    WebAutomation.ExtractData.ExtractHtmlTable BrowserInstance: Browser Control: $'''html > body > div:eq(0) > div:eq(1) > main > div:eq(1) > div:eq(1) > div:eq(1) > table''' ExtractionParameters: {[$'''状態''', $'''日付''', $'''リワード''', $'''ポイント''', $'''ポイント #1''', $'''ポイント #2'''], [$'''''', $'''''', $'''''', $'''''', $'''''', $''''''] } PostProcessData: False TimeoutInSeconds: 60 ExtractedData=> DataFromWebPage
    WebAutomation.CloseWebBrowser BrowserInstance: Browser
    **ENDREGION
    Scripting.RunDotNetScript Language: System.DotNetActionLanguageType.CSharp Script: $'''dt.Columns.Remove(\"ポイント #1\");
dt.Columns.Remove(\"ポイント #2\");

var table = dt.Clone();
foreach (DataRow row in dt.Rows)
{
	var s = row[\"リワード\"].ToString();
	var position = s.IndexOf(\"注文番号\");
	var rewards = s.Substring(0, position).Trim();	
	table.Rows.Add(row[\"状態\"], row[\"日付\"], rewards, row[\"ポイント\"]);
}
dt = table;''' @'name:dt': DataFromWebPage @'type:dt': $'''Datatable''' @'direction:dt': $'''InOut''' @dt=> DataFromWebPage
    **REGION 出力
    Excel.LaunchExcel.LaunchUnderExistingProcess Visible: True Instance=> ExcelInstance
    Excel.WriteToExcel.WriteCell Instance: ExcelInstance Value: DataFromWebPage.ColumnHeadersRow Column: $'''A''' Row: 1
    Excel.WriteToExcel.WriteCell Instance: ExcelInstance Value: DataFromWebPage Column: $'''A''' Row: 2
    Excel.ResizeColumnsOrRows.AutofitAllColumns Instance: ExcelInstance
    Excel.RenameWorksheet.RenameWorksheetWithIndex Instance: ExcelInstance Index: 1 NewName: $'''注文履歴'''
    Excel.CloseExcel.CloseAndSaveAs Instance: ExcelInstance DocumentFormat: Excel.ExcelFormat.FromExtension DocumentPath: ExcelFile
    WAIT (File.WaitForFile.Created File: ExcelFile)
    **ENDREGION
    @@copilotGeneratedAction: 'False'
Scripting.RunVBScript.RunVBScript VBScriptCode: $'''Option Explicit

Dim objExcel, objWorkbook, objSheet
Set objExcel = CreateObject(\"Excel.Application\")
objExcel.Application.Visible = False
Set objWorkbook = objExcel.Workbooks.Open(\"%ExcelFile%\")
Set objSheet = objWorkbook.Sheets(1)

Dim dataAll
Set dataAll = objSheet.UsedRange
dataAll.Borders.LineStyle = True

Const xlCenter = -4108
Const xlThemeColorAccent6 = 10
Dim header
Set header = dataAll.Resize(1)
With header
    .HorizontalAlignment = xlCenter
    .Interior.ThemeColor = xlThemeColorAccent6
    .Interior.TintAndShade = 0.8
End With

objWorkbook.Save
objWorkbook.Close True
objExcel.Quit'''
END FUNCTION

おわりに

HTMLテーブル全体を抽出すると楽で良いですね。
余計な列を削除しようとしたら.NETスクリプトを使うのが良いかも。
あとはExcelを使って削除するとか。

Discussion