公式サイトのKnowledge Baseサンプルを詳しく解説します。
今回は**"Automate Data Extraction from Desktop Application"**です。
https://www.uipath.com/kb-articles/automate-data-extraction-from-desktop-application
#シナリオ
経費精算のためのWindowsアプリケーション"ExpenseIt"を起動し、Emailアドレス、従業員番号等を入力してログイン、そして画面にテーブル状に表示された経費リストを自動的に読み取り、CSVファイルに保存します。
#このサンプルで使用する機能
- UiPath Studio
- Desktop Recording - Windowsアプリケーションへのログインを記録します。
- Screen Scraping - 画面に表示された経費リストを読み取ります。
- UiPathアクティビティ - **Open Application** - 経費精算アプリケーションを起動します - **Type into** - 経費精算アプリケーションに情報を入力します - **Click** - ボタンをクリックします - **Build Data Table** - CSVデータを保持するDataTableを作成します - **Write Csv File** - DataTableをCSVファイルで保存します ※Type into, ClickはRecording機能で自動的に作成されます。
- Windows Workflow - **While**コントロール - **Assign**コントロール
- .Net関連 - System.data.**DataTable** - 経費データを格納するデータモデルです
#準備
-
サンプルZIPファイルをダウンロードします。
https://drive.google.com/open?id=0BxVAKI3l9Pc5UWY5Ujd2eElZVUEZIPファイルには以下のファイルが含まれています。これらのファイルを任意の場所に展開します。
- Expenses.csv - 出力されるCSVファイル
- Main.xaml - ワークフローのXAML実装
- project.json - UiPathプロジェクトファイル
- WPF_30_ANYCPU_ExpenseIt.exe - 経費精算アプリケーション実行ファイル
2. UiPathを起動します。Main.xamlを選択し、UiPathで開きます。
3. Flowchartが表示されます。
#実行と結果
- Runボタン(またはF5キー)で実行します。
2. ExpenseItが起動し、自動的に必要項目が入力されます。 3. Expenses.csvが出力されます。 (zipファイルに元々含まれていましたが更新日時が変わっています) ファイルを開けると画面で表示された経費リストが出力されています。
ビデオで見るとこのような感じになります。
[![Video](http://img.youtube.com/vi/m8Irit9Q-qU/0.jpg)](http://www.youtube.com/watch?v=m8Irit9Q-qU)
#ワークフロー作成ビデオ
1から自分でworkflowを作るとこのようになります。
#解説
- "Open application 'WPF_30_ANYCPU_ExpenseIt...'"アクティビティ
- OpenApplicationアクティビティ UiPath.Core.Activitis.OpenApplication が使われています。
ダブルクリックすると以下のようになっています。
<img src="https://qiita-image-store.s3.amazonaws.com/0/202992/0102c11f-b699-afb4-8c51-2ace9677829e.png">
①ここでは操作対象となるウィンドウが表示されています。
Recording機能でウィンドウを選択した際、アプリケーション実行ファイルのパス(FileName)とウィンドウのSelectorが自動的に記録されます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/202992/86b97c54-81ab-a81f-20e6-35f7a328a574.png">
FileNameには経費精算アプリケーションの実行ファイルのパスが記録されています。
<img src="https://qiita-image-store.s3.amazonaws.com/0/202992/62091180-f14d-58e0-1dea-3c6bdd1edd01.png" width=50%>
Selectorを確認してみましょう。Selectorとは、UiPathが操作対象のユーザ・インターフェース要素を特定するために使う情報で、Recording機能で自動的に設定されます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/202992/d5e2e11a-554c-a9fe-a1bc-ca78fb4f772c.png" width=50%>
ここではアプリケーション・ウィンドウを特定するためのSelectorとして以下の3つが使用されています。
"app" - 実行ファイル名
"title" - ウィンドウタイトル
"cls" - ウィンドウクラス名
"app"は経費精算アプリケーションの実行ファイル名である"wpf_30_anycpu_expenseIt.exe"が、"title"はアプリケーションのウィンドウタイトルである"ExpenseIt Standalone"が、"cls"はウィンドウクラス名である"HwndWrapper*"がそれぞれ指定されています(アスタリスク*はワイルドカードで、HwndWrapperで始まる名前を指定しています)。
>**ウィンドウクラスについて**
実行ファイル名、ウィンドウタイトルについては自明ですが、ウィンドウクラスが何かを知るにはWindowsにおけるアプリケーション開発についての知識が必要です。Windowsアプリケーション開発でウィンドウを作成する際、CreateWindowというWindows APIを使い、引数としてlpClassName
としてウィンドウクラス名を渡し、どのようなデザイン・機能を持つウィンドウにしたいか指定します。これが"cls"で指定するウィンドウクラス名です。なお、指定するウィンドウクラスはあらかじめRegisterClassを使い、WNDCLASS構造体としてWindowsシステムに登録しなければいけません。
参考1:C++によるWindowsプログラミングの学習-ウィンドウを作成する
参考2:"WinLister"というツールで筆者のPCでウィンドウクラス名の一覧を表示すると以下のようになります。
②Window Scopeが表示されています。
Recording機能を使う際、"Basic Recording"を使うとWindow Scopeはアクティビティとして出てきません。"Desktop Recording"を使うと出てきます。同じアプリケーション、同じウィンドウタイトルのウィンドウが複数並ぶ場合はDesktop Recordingを使い、明示的にWindowを指定する必要があります。
③Type intoアクティビティでEmailアドレスを入力します。
④Type intoアクティビティで従業員番号(Employee number)を入力します。
⑤"Create Expense Report"ボタンをクリックします
- "Screen scraping"アクティビティ
- "Screen scraping"アクティビティはRecording機能により"Window Scope"アクティビティ、Sequenceアクティビティ、"Get Full Text"アクティビティの組み合わせとして自動で生成されます。
ダブルクリックすると以下のようになっています。
<img src="https://qiita-image-store.s3.amazonaws.com/0/202992/b3a0ce38-55c9-39dd-6089-7fa2e13e6b5d.png">
①"Screen scraping"の実体はSequenceアクティビティです。
②"Attach Window 'CreateExp Hwndwrapp'"はWindow Scopeアクティビティです。プロパティ"Selector"の詳細を見てみましょう。
<img src="https://qiita-image-store.s3.amazonaws.com/0/202992/2175d894-5933-539b-558e-b7b571b237bf.png">
Selector詳細
<img src="https://qiita-image-store.s3.amazonaws.com/0/202992/b2a7ca87-778f-755a-16c7-f18cbf7ba9d7.png">
Open ApplicationアクティビティでもSelectorを使用していますがtitleのみ"Create Expense Report"に変わっています。これは、実際にウィンドウタイトルが親画面と子画面で異なっているためです。(Open Applicationアクティビティでは"ExpenseIt Standalone"でした)
<img src="https://qiita-image-store.s3.amazonaws.com/0/202992/435e882a-0c4f-a45b-cdba-78a55d44658e.png" width=70%>
③Get Full Textアクティビティで画面上のテキスト文字を読み取ります。
実際には、以下の文字列が読み込まれます。
システム
元のサイズに戻す(R)
移動(M)
サイズ変更(S)
最小化(N)
最大化(X)
閉じる(C) Alt+F4
Email Alias:
Email _Alias:
Someone@example.com
Employee Number:
Employee _Number:
57304
Cost Center:
_Cost Center:
4032
Add Expense
Add _Expense
View Chart
Expense Type
Description
Amount
Meal
Mexican Lunch
12
Meal
Italian Dinner
45
Education
Developer Conference
90
Travel
Taxi
70
Travel
Hotel
60
Total Expenses ($):
277
OK
_OK
Cancel
_Cancel
読み込まれた文字列はString変数"scrappedText"に格納されます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/202992/05c12796-852a-9fc2-45df-6a2f3e6b004c.png">
**IgnoreHidden**オプションは今回チェックされていませんが、チェックした場合は画面上表示されていない「システム」から「閉じる(C) Alt+F4」などは読み込まれません。
<img src="https://qiita-image-store.s3.amazonaws.com/0/202992/59559e3b-7d61-98c0-13d7-91235eec266f.png">
- AssignでString型の配列変数"lines"に読み取った結果を代入します。
StringSplitOptions.RemoveEmptyEntries は"空の文字列を格納している配列要素を含まない"ようにするためのオプションです。
-
もう一度読み取ったテキストデータを見てみましょう。
「システム」から始まり「Amount(下から4つ目)」までいったところでループが止まり、その位置の変数iが保持されます。ほしいデータは"Meal"以降です。
-
WhileでCSVデータを格納するDataTableを構築します。
1つの経費アイテムはExpense Type, Description, Amountの3項目で構成されているので"Add Data Row"アクティビティで、
{lines(i), lines(i+1), lines(i+2)}
をDataTable型のdtExpenses変数に追加していきます。1回目のループ、2回目のループではそれぞれ、Meal, Mexican Lunch, 12 Meal, Italian Dinner, 45 ...
がDataTableに追加されます。
ループ処理は"Total Expenses ($):"が出てくるまで3行単位で回ります。