6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UiPath (produced with UiPath Friends) Advent Calendar 2023

Day 13

【UiPath】コード化されたワークフローで RPA Challenge を動かす その1 - 基本編

Last updated at Posted at 2023-12-12

はじめに

今回は 2023.10 にて正式リリースとなったコード化されたワークフローを使って RPA Challenge を自動化してみようと思います。

この記事は、UiPath (produced with UiPath Friends) Advent Calendar 2023 の 13日目です。

コード化されたワークフローとは

コード化されたオートメーションの一つで、アクティビティの代わりに C# でコードを書くことにより自動化処理を実現する仕組みです。Coded Workflow とも呼ばれています。

コード化されたワークフローの他にも、コード化されたテストケース、コードソースファイルがあります。それぞれ以下の役割となっています。

  • コード化されたワークフロー:Xaml 形式のワークフローに相当
  • コード化されたテストケース:Xaml 形式のテストケースに相当
  • コードソースファイル:上記2つから呼び出すことができる処理を切り出したロジックを記載できる

コード化されたオートメーションは UiPath Studio 2023.10 以降の Windows またはクロスプラットフォームプロジェクトでのみ利用可能です。Windows レガシでは利用できないので注意しましょう。

作ってみる

RPA Challenge から challenge_ja.xlsx をダウンロードしてプロジェクトフォルダに配置してください。

ワークフローファイルの作成

UiPath Studio でプロジェクトを作成したら、デザインリボンの新規からコード化されたワークフローを選択します。

image.png

名前を入力して作成すると、空の Execute メソッドが定義されたクラスが出てきました。プロジェクト名がネームスペース、ワークフロー名がクラス名となっているようですね。

また、Execute メソッドには [Workflow] という属性が付与されておりこのクラスのエントリポイントとなっているようです。[Workflow] 属性が付与されているメソッドであればメソッドの名前は Execute でなくても問題ないようです。

とはいえ、まぎらわしいのでエントリポイントのメソッド名は Execute としておくのが良いかと思います。

今回はあまり難しいことは考えずに、Execute メソッドに処理を追加していきます。

RPAChallenge.cs
using CodedWorkflow_RPAChallenge.ObjectRepository;
using System;
using System.Collections.Generic;
using System.Data;
using UiPath.CodedWorkflows;
using UiPath.Core;
using UiPath.Core.Activities.Storage;
using UiPath.Orchestrator.Client.Models;
using UiPath.Testing;
using UiPath.Testing.Activities.TestData;
using UiPath.Testing.Activities.TestDataQueues.Enums;
using UiPath.Testing.Enums;
using UiPath.UIAutomationNext.API.Contracts;
using UiPath.UIAutomationNext.API.Models;
using UiPath.UIAutomationNext.Enums;

namespace CodedWorkflow_RPAChallenge
{
    public class RPAChallenge : CodedWorkflow
    {
        [Workflow]
        public void Execute()
        {
            // To start using services, use IntelliSense (CTRL + Space) to discover the available services:
            // e.g. system.GetAsset(...)

            // For accessing UI Elements from Object Repository, you can use the Descriptors class e.g:
            // var screen = uiAutomation.Open(Descriptors.MyApp.FirstScreen);
            // screen.Click(Descriptors.MyApp.FirstScreen.SettingsButton);
        }
    }
}

オブジェクトリポジトリ

コード化されたオートメーションでの UI 要素の指定はオブジェクトリポジトリを使うことになります。

セレクターを直接指定する方法もサポートされていますが、コードと UI 要素の分離ができるオブジェクトリポジトリを使うことが推奨になります。

var screen = uiAutomation.Open(Target.FromSelector("<html app = 'chrome.exe'/>"));

オブジェクトリポジトリについて非常に分かりやすい記事が投稿されているのでそちらを確認ください。

早速オブジェクトリポジトリに UI 要素を追加していきたいところですが、追加方法は省略します。上記記事を参考に皆さんでチャレンジしてください。

こちらが出来上がりのイメージです。3分クッキングみたいですみません。。

image.png

画面を開く

では、早速 RPA Challenge の画面を開く処理を追加しましょう。uiAutomationOpen メソッドにオブジェクトリポジトリに登録されている画面名を渡すことで画面を開くことができます。

画面名の指定は、Descriptors の定数を使う方法と文字列での指定の2通りがあります。文字列のハードコーディングを避ける意味で Descriptors の定数を利用したほうが良いかもです。

// できればこちら
UiTargetApp screen = uiAutomation.Open(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge);
// この方法でもOK
UiTargetApp screen = uiAutomation.Open("Chrome: Rpa Challenge");

作成されたワークフローの基底クラスである CodedWorkflow クラスには下記メンバ変数が存在しており主要アクティビティパッケージのアクティビティをメソッドとして公開しています。

system : UiPath.System.Activities に相当
uiautomation : UiPath.UIAutomation.Activities に相当
testing : UiPath.Testing.Activities に相当

uiautomation.Open の戻り値として UiTargetApp 型の変数(今回は screen)が返ってきます。この UiTargetApp 型の変数を使ってクリックや文字の入力等の UI 操作をしていくことになります。

続いて開始ボタンをクリックする処理を追加します。UI 要素のクリックは screen 変数の Click メソッドにて行います。メソッドの引数にオブジェクトリポジトリに登録している開始ボタンの UI 要素を指定してください。

screen.Click(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.開始);

Excel ファイルの処理

2023年12月6日現在のコード化されたオートメーションでは UiPath.Excel.Activities に該当する C# のクラスの提供がありません。そのため、何らかの方法で Excel ファイルからデータを取得する必要があります。

今回は NPOI を利用して実装を進めていこうかと思います。

NPOI を使うにあたり、ワークフローに以下のネームスペースを追加します。

using NPOI.SS.UserModel;

NPOI で Excel ファイルの操作が出来るようになったので、ファイルを開いてシートを取得する処理を追加します。

IWorkbook book = WorkbookFactory.Create(@".\challenge_ja.xlsx");
ISheet sheet = book.GetSheetAt(0);

ここまでのコードはこちらになります。

RPAChallenge.cs
RPAChallenge.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using UiPath.CodedWorkflows;
using UiPath.Core;
using UiPath.Core.Activities.Storage;
using UiPath.Orchestrator.Client.Models;
using UiPath.Testing;
using UiPath.Testing.Activities.TestData;
using UiPath.Testing.Activities.TestDataQueues.Enums;
using UiPath.Testing.Enums;
using UiPath.UIAutomationNext.API.Contracts;
using UiPath.UIAutomationNext.API.Models;
using UiPath.UIAutomationNext.Enums;
using CodedWorkflow_RPAChallenge.ObjectRepository;
using NPOI.SS.UserModel;

namespace CodedWorkflow_RPAChallenge
{
    public class RPAChallenge : CodedWorkflow
    {
        [Workflow]
        public void Execute()
        {
            //UiTargetApp screen = uiAutomation.Open("Chrome: Rpa Challenge");
            UiTargetApp screen = uiAutomation.Open(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge);

            screen.Click(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.開始);

            IWorkbook book = WorkbookFactory.Create(@".\challenge_ja.xlsx");
            ISheet sheet = book.GetSheetAt(0);
        }
    }
}

データを入力していく

続いて、1件づつデータを入力していきましょう。Excelファイルからシートの取得までできているので1行ずつのループを入れていきます。

ループの条件に sheet.LastRowNum を使うことでシートの最終行まで繰り返すようにしています。ループ内では行が取れないまたはインデックス 0番のセル(苗字)に値がなければループを抜けるようにしています。

for (int i = 1; i <= sheet.LastRowNum; i++) {
    IRow row = sheet.GetRow(i);
    if (row == null) {
        break;
    }
    if (row.GetCell(0) == null || string.IsNullOrEmpty(row.GetCell(0).ToString())) {
        break;
    }

    // ここに1件ずづの処理を記述していきます
}

文字の入力には screen 変数の TypeInto メソッドを使用します。文字を入力 アクティビティの英語名と同じなので直感的にイメージしやすいですね。

TypeInto メソッドの第一引数に入力先の UI 要素、第二引数に入力したい文字を指定します。ループ内に以下のコードを追加してください。

Excelのセルの値は row.GetCell(インデックス番号) で取得しています。

screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.苗字, row.GetCell(0).ToString());
screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.名前, row.GetCell(1).ToString());
screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.会社名, row.GetCell(2).ToString());
screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.部署, row.GetCell(3).ToString());
screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.住所, row.GetCell(4).ToString());
screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.メールアドレス, row.GetCell(5).ToString());
screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.電話番号, row.GetCell(6).ToString());

最後に登録ボタンのクリック処理を追加して完成です。

screen.Click(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.登録);

実行してみる

通常のワークフローと同様でデザインリボンから実行することができます。ファイルを実行 を選択して実行してみましょう。

image.png

無事完走できましたが、イメージしていたより遅く感じませんでしたか?遅く感じた人は鋭いです。実は入力モードが ハードウェアイベント だったため処理がもっさりしていました。

image.png

オプションを変えてみる

入力モードを ハードウェアイベント から シミュレート に変更してみましょう。クリックや文字を入力ごとに細かく変更することも出来ますが今回は一括での変更をしてみます。

全体に影響を与える変更は TargetAppOptions クラスを使います。 RPAChallenge クラスのメンバ変数として以下を追加します。

TargetAppOptions でプロパティを変更するときは、OpenMode も必ず指定してください。

public TargetAppOptions targetAppOptions => new TargetAppOptions(){
    InteractionMode = NInteractionMode.Simulate,
    OpenMode = NAppOpenMode.IfNotOpen
};

メンバ変数 targetAppOptionsuiautomation.Open メソッドの第二引数として渡します。

UiTargetApp screen = uiAutomation.Open(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge, targetAppOptions);

この状態でもう一度実行してみましょう。処理も安定して実行も倍近く早くなったことが確認できるかと思います。

image.png

コードは最終的にこのようになっているはずです。

RPAChallenge.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using UiPath.CodedWorkflows;
using UiPath.Core;
using UiPath.Core.Activities.Storage;
using UiPath.Orchestrator.Client.Models;
using UiPath.Testing;
using UiPath.Testing.Activities.TestData;
using UiPath.Testing.Activities.TestDataQueues.Enums;
using UiPath.Testing.Enums;
using UiPath.UIAutomationNext.API.Contracts;
using UiPath.UIAutomationNext.API.Models;
using UiPath.UIAutomationNext.Enums;
using CodedWorkflow_RPAChallenge.ObjectRepository;
using NPOI.SS.UserModel;

namespace CodedWorkflow_RPAChallenge
{
    public class RPAChallenge : CodedWorkflow
    {
        public TargetAppOptions targetAppOptions => new TargetAppOptions(){
            InteractionMode = NInteractionMode.Simulate,
            OpenMode = NAppOpenMode.IfNotOpen
        };

        [Workflow]
        public void Execute()
        {
            //UiTargetApp screen = uiAutomation.Open("Chrome: Rpa Challenge");
            UiTargetApp screen = uiAutomation.Open(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge, targetAppOptions);

            IWorkbook book = WorkbookFactory.Create(@".\challenge_ja.xlsx");
            ISheet sheet = book.GetSheetAt(0);

            screen.Click(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.開始);

            for (int i = 1; i <= sheet.LastRowNum; i++) {
                IRow row = sheet.GetRow(i);
                if (row == null) {
                    break;
                }
                if (row.GetCell(0) == null || string.IsNullOrEmpty(row.GetCell(0).ToString())) {
                    break;
                }

                screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.苗字, row.GetCell(0).ToString());
                screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.名前, row.GetCell(1).ToString());
                screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.会社名, row.GetCell(2).ToString());
                screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.部署, row.GetCell(3).ToString());
                screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.住所, row.GetCell(4).ToString());
                screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.メールアドレス, row.GetCell(5).ToString());
                screen.TypeInto(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.電話番号, row.GetCell(6).ToString());
                
                screen.Click(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.登録);
            }
        }
    }
}

おわりに

颯爽と現れたコード化されたオートメーションですがいかがだったでしょうか?

今までのローコード開発とは逆のアプローチの機能がリリースされましたが、今までのアクティビティでの開発が主流であることは変わらないのでご安心ください。この機能はプログラミング経験のある開発者やチームが生産性を損なわずに自動化処理を実装していくのに役に立つものと理解しています(Selenium 等で画面の自動化テストを実装していた方が UiPath でテストケースを記述する際に効果を発揮する気がしています)。

個人的にはオブジェクトリポジトリを使うことで UI 要素とコードの分離ができていてすっきりした記述が可能となっており今後の成長が楽しみな機能の一つになりました。

是非皆さんもお試しください!

6
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?