Uipathで繰り返し処理を途中再開するための工夫
RPAエンジニア 小林
RPAを使った自動化作業では、繰り返し処理を行うことがよくあります。同じ作業を何度もするのはRPAの得意領域ですが、時には途中で想定外のパターンが生じてしまいロボットが止まってしまうということもあります。小規模の作業ならまだしも、時間のかかる作業を再度初めから動かすのはなるべく避けたいものです。ロボットが止まらない設計も大事ですが、万が一止まってしまっても途中再開がしやすい設計にすることで効率的に作業を進められます。今回は、UiPathでループを途中再開するための工夫を紹介します。
扱う例
Excelファイルに書かれたデータを使って、行ごとに同じ作業を繰り返す場合を考えます。例えば、商品情報が書かれたExcelファイルから各情報を拾い、CMSに入力して商品ページを作るという作業があります。今回扱う例は、Excelファイルの1行目には商品名や価格などの項目名が、2行目から100行目までは各商品の情報が書かれているものとします。
処理がどこまで進んだかログを残す
ロボットを途中再開するために最も重要なのは、処理がどこまで進んだかのログを残すことです。Write Cell(セルに書き込み)アクティビティを使ってExcelファイルに逐次書き込んでもよいですし、Append Line(文字列を追加書き込み)アクティビティを使ってテキストファイルに追記していくのもよいでしょう。どこまで進んだか簡易的に見るだけなら、Write Line(1行を書き込み)アクティビティを使って出力パネルに表示するという方法もありますが、実行の記録を残すという意味ではファイルとして出力したほうが無難です。
どこから再開するか指定する
途中再開できるロボットを組むためには、Excelファイルのどの行から処理するかを指定する(例えば値を30と設定すればExcelファイルの30行目から処理する)変数が必要となります。ここではその変数をStartNo(Int32型)とします。StartNoを指定するには、実行前に既定値として設定するようにしてもよいですし、設定忘れを避けるためにInput Dialog(入力ダイアログ)アクティビティを使って入力するようにしてもよいでしょう。
Whileアクティビティを使ったループの再開
途中再開できるループを組むにあたって、わかりやすいのがWhile(繰り返し(前判定))アクティビティやDo While(繰り返し(後判定))アクティビティを使う方法です。ここではWhileアクティビティを使った例を紹介しますが、Do Whileアクティビティでも同じことができます。
まず、単純にExcelデータの最初の行(2行目)から最後の行(100行目)まで処理することを考えます。読み込みたい行番号をRowNo(Int32型の変数)とします。ループが始まる前にRowNoの初期値を設定(RowNo = 2)し、Whileアクティビティでは100行目まで処理するように条件(RowNo <= 100)を設定します。
Whileアクティビティの中には行いたい処理を配置し、RowNoの値の更新も忘れずに設定します(ループのたびにRowNoの値を1ずつ増やしていきます)。これでExcelファイルの2行目から100行目まで1行ずつ順に処理することができます。
さて、この例ではExcelファイルの2行目から読み込むために、ループ前にRowNo = 2という値を設定しました。他の行から処理を始める場合も同様で、例えば51行目から処理を再開したいという場合は、ループ前にRowNo = 51と設定すれば51行目から再開できます。今回は途中再開の設定値は変数StartNoに入っているという前提なので、ループ前にRowNo = StartNoを設定すればよいでしょう。
For Eachアクティビティを使ったループの再開
ループを組むためのもう一つの代表的なアクティビティとして、For Each(繰り返し(コレクションの各要素))アクティビティがあります。このアクティビティは文字通り、配列変数などの各要素に対して処理を行うことができます。
Whileアクティビティのときと同様、まずは単純に2行目から100行目まで処理する場合を考えます。この場合、2, 3, 4, ..., 100という数字が入った配列を使えばよさそうです。そこで、For Eachアクティビティのコレクション値の欄に、次のような式を設定します。
Enumerable.Range(2, 99).ToArray()
このように書くことで、初期値2で要素数99(つまり2から100までの)の連番配列を生成できます(行番号と要素の個数を混同しないように注意)。要素の欄には変数(ここではRowNo)を設定し、プロパティのTypeArgumentはInt32に設定します。これでWhileアクティビティのときと同様にRowNoの値を2から100まで変化させてループを回すことができるようになりました。
では、51行目から再開するにはどのように式を設定すればよいでしょうか?51行目から最後の100行目までは、50個の行が残っているので、コレクション値を次のように設定すれば実現できます。
Enumerable.Range(51, 50).ToArray()
途中再開するたびに残り行数を考えるのは大変なので、処理を始める行番号StartNoを使って次のように書けばStartNoの値を設定するだけで特定の行から処理を始めることができます。
Enumerable.Range(StartNo, 101 - StartNo).ToArray
For Eachを使った場合のループの途中再開は、Whileの場合より複雑ですが、Whileアクティビティでは扱えないBreak(繰り返しをブレーク)アクティビティやContinue(繰り返しをコンティニュー)アクティビティが使えるというメリットがあります。
DataTableの途中からループを回す
上記の例ではExcelからセルの値を都度読み込む前提で話を進めましたが、Read Range(範囲を読み込み)アクティビティで取得したDataTableを使うという方法もあります。Read Rangeアクティビティでは範囲を指定しない場合、表全体が取得されるため、データが何行目まであるか考えなくてよいというメリットがあります。また、DataTable自体の利点としては、一度DataTableとして取得してしまえば都度ファイルを読む必要がないため処理の高速化が図れる点、DataTableとして取得できるものならExcelに限らず扱える点があります。注意点としては、DataTableのインデックスは0から始まるという点があります。ここまで使ったExcelの行番号とは一致しないので気をつけてください。以下ではRowNoとStartNoはExcelの行番号ではなくDataTableの行インデックスを表しています。
以下の例で扱うDataTable型の変数をProductDataとします(ExcelファイルをRead Rangeアクティビティ(ヘッダーあり指定)で読み込んだDataTableです)。DataTableをループするときに最もよく使われるのはFor Each Row(繰り返し(各行))アクティビティでしょう。このアクティビティでも工夫次第で途中再開できるように組むことができます。
例えば、For Each Rowアクティビティ内で現在のインデックスを変数RowNoに出力し、処理を始めたい行のインデックスよりもRowNoが小さい場合はContinueアクティビティを使ってスキップするという方法があります。
DataTableのループは基本的にはFor Each Rowアクティビティを使えば十分ですが、行インデックスを直接指定する形でループしたい場合は(Do)WhileアクティビティやForEachアクティビティを使います。行インデックスを使ってDataTableの特定の要素を取り出す方法ですが、例えばProductDataから特定の行RowNoに書かれている商品名を取得したければ次のように書きます。
ProductData.Rows(RowNo).Item("商品名").ToString()
また、ProductData全体の行数は次のように取得できます。
ProductData.Rows.Count
あとは基本的には初めに示したWhileアクティビティやFor Eachアクティビティと同じようにループの設定をすればよいのですが、DataTableのインデックスは0始まりのため、設定する式が少し変わる点に注意が必要です。例えばWhileアクティビティの条件は次のようになります。
RowNo < ProductData.Rows.Count
For Eachアクティビティの場合はコレクション値を次のように設定します。
Enumerable.Range(StartNo, ProductData.Rows.Count - StartNo).ToArray()
今回は、UiPathでループを途中再開する方法を紹介しました。中には複雑な方法もありましたが、ループの再開ができるとロボットはかなり扱いやすくなります。スムーズに再開できるための仕組みを心がけてロボットを開発していきたいですね。