#今回の内容
WinActorで開発した時に遭遇した、困った話と解決方法を書いていきたいと思います。
今回はIE編です。
前回見せれなかったWinActorの実際の画面も貼っていきます。
#何が起きたのか?
##処理の内容
IEを使ったシステムに対しWinActorで、下図のシナリオを作っていました。
※判定材料の取得は全部で10個ほどあるのですが、省略しています。
この流れでひとまずは完成したのですが…
1つの問題を除いては正常に動きました。
だけど、その1つが非常に大きな問題になったのです…
##問題とは?
遅い、とにかく遅い!
今回のシナリオは1日1000件を超える件数に対して処理を行うのですが、作ったシナリオを実行すると処理完了までに約4~5時間かかったのです。
これでは日が変わると同時に動かし始めても、終わるころには日が昇り始めます…
何としても解消する必要がありました。
#原因は?
##原因その1:画面遷移
上の図で発生している画面遷移が一つ目の問題です。
IEは主流ブラウザと違い動作が遅いため、この画面移動に非常に時間がかかるのです。
移動1回が1秒だとして、1件に対し移動が2回。
1000件×2秒=2000秒
移動だけで約33分かかる計算、処理の10分の1が画面遷移。
結構時間かかってる。
##原因その2:判定処理
詳細画面で、この行は処理を行うべきかどうかの判定をしているんですが、画面情報を色々と参照する必要があって1件辺り約8秒かかってました。
1000件×8秒=16000秒
処理判定だけで約260分かかる計算に、そりゃ遅いわ…
##解決策
処理速度の向上のためには原因1と2を解決する必要がありますが、今回作ったシナリオでは流れ的に解決不可能なので大幅に修正を加える必要があります。
なので対応として一覧画面上で判定を行い、対象外の場合は画面遷移を行わないという形で対応することに。
今回は一覧画面上で処理の可否判定が行える材料があったので助かりました。
#解決方法
##色による判定
処理可否判定の仕様に、一覧画面のボタンがあるセルの背景に色がついている行は無視していいというのがありました。
しかし何故最初からそうしなかったのか?
それはWinActorの標準ライブラリに、HTMLソース内のクラス名やスタイルを取得するものが存在しなかったからです。
(以前の記事で書いた通りWinActorはブラウザの画面をHTMLソースで読み込むため、色の取得は出来ません。)
そのため仕方なく詳細画面内の情報で判断を行っていたのです。
##クラス取得ライブラリの作成
というわけで上で書いた問題点を解消するため、VBScriptを使い独自ライブラリを作成することにします。
ieTitle = GetUMSWindowTitle(@ウィンドウ識別名@)
ieHWnd = GetUMSWindowHandle(@ウィンドウ識別名@)
' 引数を解釈する
frameNum = !frame index! + 0
tableNum = !tag index! + 0
cname = !対象クラス名!
cellRow = !行番号! - 1
cellColumn = !列番号! - 1
If IsNull(ieTitle) Then
SetUMSVariable $処理結果$, "指定されたウィンドウ識別ルールに該当するウィンドウが存在しません。"
WScript.Quit
End If
' タイトルの接尾辞を取り除く
ieTitle = Left(ieTitle, InStrRev(ieTitle, " - ") - 1)
' 指定されたページのdocumentを取得する
Set document = Nothing
Set shell = CreateObject("Shell.Application")
For i = 0 To shell.Windows.Count - 1
Set window = shell.Windows(i)
title = Empty
On Error Resume Next
title = window.document.title
On Error Goto 0
If title <> Empty Then
If InStr(title, ieTitle) <> 0 Then
Set document = window.document
Exit For
End If
End If
Next
If document Is Nothing Then
SetUMSVariable $処理結果$, "指定されたタイトルのページが開かれていません。"
WScript.Quit
End If
' document内の指定された番号のframeオブジェクトを取得する
On Error Resume Next
Set document = FindFrame(document)
On Error Goto 0
If document Is Nothing Then
SetUMSVariable $処理結果$, "指定された番号のフレームが存在しません。"
WScript.Quit
End If
' document内の指定された番号のtableオブジェクトを取得する
Set table = Nothing
On Error Resume Next
Set table = (document.document.getElementsByTagName("table"))(tableNum)
On Error Goto 0
If table Is Nothing Then
SetUMSVariable $処理結果$, "指定された番号の表が存在しません。"
WScript.Quit
End If
' table内の指定された行番号・列番号のcellオブジェクトを取得する
Set cell = Nothing
On Error Resume Next
Set cell = (table.rows(cellRow)).cells(cellColumn)
On Error Goto 0
If cell Is Nothing Then
SetUMSVariable $処理結果$, "指定されたセルが存在しません。"
WScript.Quit
End If
' 正常に処理が完了したため"OK"を返す
result = ""
If InStr(cell.outerHTML, cname) > 0 Then
result = "true"
Else
result = "false"
End If
SetUMSVariable $処理結果$, result
'---------------------------------------------------------------
' フレーム0を探索する
Function FindFrame(rootDoc)
If frameNum = 0 Then
Set FindFrame = rootDoc.frames
Exit Function
End If
frameNum = frameNum - 1
Dim i
For i = 0 To (rootDoc.frames.Length - 1)
Set frms = rootDoc.frames
Set frm = frms(i)
Set FindFrame = FindFrame2(frm)
If Not FindFrame Is Nothing Then
Exit Function
End If
Next
Set FindFrame = Nothing
End Function
'---------------------------------------------------------------
' 子フレームを探索する
Function FindFrame2(rootFrame)
If frameNum = 0 Then
Set FindFrame2 = rootFrame
Exit Function
End If
frameNum = frameNum - 1
Set frms2 = rootFrame.document.frames
Dim j
For j = 0 To (rootFrame.document.frames.Length - 1)
Set frm2 = frms2(j)
'Set FindFrame2 = FindFrame2(rootFrame.document.frames(j)) 'NG
Set FindFrame2 = FindFrame2(frm2)
If Not FindFrame2 Is Nothing Then
Exit Function
End If
Next
Set FindFrame2 = Nothing
End Function
'--
このコード自体は、WinActorに元々ある「テーブル指定セルのテキストを取得」するライブラリを改造したものです。
ライブラリの画面はこんな感じ。
大事な部分は引数の追加と、
' 正常に処理が完了したため"OK"を返す
result = ""
If InStr(cell.outerHTML, cname) > 0 Then
result = "true"
Else
result = "false"
End If
SetUMSVariable $処理結果$, result
この部分になります。
上記の処理で指定セルにクラス名が存在するかを判定し、存在すればTrue、しなければFalseを返却するようにしています。
もしもテーブル以外の判定でも使いたければ、似たことを行っているライブラリに上記コードを追加すればいいでしょう。
スクリプトが完成したので、早速シナリオに組み込むことにします!
#修正と結果
##シナリオ修正
ライブラリを作成したことで、シナリオは下のようになりました。
分岐の直前に作成したライブラリを追加し、そこの結果に対して分岐処理をかけています。
そのためライブラリ処理でFalseが返ってきた場合は、詳細画面へ行かず次の行の判定を行うようになりました。
これで詳細画面での処理が大幅に削減されるようになりました。
##結果
さて修正して実施してみた結果ですが…
処理時間:約300分⇨約160分
大体半分の処理時間に!やったぜ!!
#まとめ
今回はWinActorで作ったシナリオが遅い場合の対応方法の一例を記事にしてみました。
高速化を行う場合にまず考えるべきことは下の2点。
- 画面遷移の削減
- シナリオの削減
ブラウザ上で処理を行う場合、どうしても画面の読込を待つ必要があります。
またシナリオも画面上の値を取得したり、値に対する加工編集を行うと意外と時間がかかるので、以下にシナリオの実行回数を減らすのかも重要になってきます。
今回の修正コンセプトは、画面遷移を減らすことで、シナリオの実行回数を減らすだったので、このような形になりました。
このコンセプトはRPA開発では、どのような状況でも使えると思うので、常に意識するといいんじゃないでしょうか。
次回は、WinActorで困った話Chrome編を書いていきたいと思います。