【🔥UiPath vs Automation Anywhere🔥】同一書式の複数Webページから情報を抜き出す (2) - Automation Anywhereの場合

この記事は前回の『**[【🔥UiPath vs Automation Anywhere🔥】同一書式の複数Webページから情報を抜き出す (1) - UiPathの場合](https://qiita.com/Okura_/items/02da1e221bd840a86953)**』からの続きです。繰り返しパターンからリンクされている各詳細ページの情報を取得していく場合を考えています。たとえば、一覧からリンクされているプロファイル情報、商品の詳細ページ、レシピの詳細ページ、などです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/56bd51c5-f49e-8897-9e30-3bcb1d686dfc.png)
 :arrow_up:今回の想定は上の図のような場合です。

# 用意されているデータと取り組み方針
[前回の記事](https://qiita.com/Okura_/items/02da1e221bd840a86953#用意されているデータと取り組み方針)を参照してください。

詳細ページの1つで得たい情報の部分をスクレイピングして、変数とループを使ってその他の同じレイアウトの一覧ページからも同じ部分をスクレイピングします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/6d26aa87-355a-7e8d-b99a-29e33c2057e0.png)

# UiPathの場合
利用環境: UiPath Studio 2020.4.0-beta.472

[前回の記事](https://qiita.com/Okura_/items/02da1e221bd840a86953#uipath%E3%81%AE%E5%A0%B4%E5%90%88)を参照してください。

# Automation Anywhereの場合
利用環境: Automation Anywhere Enterprise 11.3.3.1 (Build 19100531)

この記事では、Automation Anywhere (AA)で実装した場合のやり方について取り上げます(^^♪

>**注:** AAではWebページのスクレイピングは[Object CloningとWeb Recorderの2通りの方法](https://qiita.com/Okura_/items/b8e0e65a9c8b86eb4716)があります。Webページの操作においてはWeb Recorderの方が一般的に操作性がよくスピードも速いのですが、 URL/IEのウィンドウ設定の部分が変数が挿入できずページの一般化ができないため、Object Cloningを使うことになります。
>
>Web Recorderの場合:
>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/63acbc7b-e917-2031-cb5c-4fa25b8c1734.png)
>Object Cloningの場合:
>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/2d272dcf-1cf6-a941-bebd-9a308aaec01c.png)


### 詳細ページ上で必要な要素を変数に取得する
1. 新規ワークベンチを作成、最初のURL `https://kakaku.com/item/K0001219355/` をInternet Explorerで開いておきます。また変数を3つ作っておきます。(`variable1`、`variable2`、`variable3`)
2. Object Cloningコマンドをワークベンチにドラッグ＆ドロップします。開くダイアログボックスでInternet Explorerのウィンドウを指定して、キャプチャボタンを押して、Webページの以下の部分をキャプチャします。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/4de558ae-babf-1eaf-8c87-858e16adf94d.png)<br/>キャプチャした結果は以下のようになります。実行するアクションに「Get Property」を指定し、「HTML Inner」を取得、`variable1`に格納します。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/8d49b3d7-2320-27b7-7f9a-f4299fcbe0ea.png)
3. 同様に、もうひとつObject Cloningコマンドをワークベンチにドラッグ＆ドロップします。開くダイアログボックスでInternet Explorerのウィンドウを指定して、キャプチャボタンを押して、Webページの以下の部分をキャプチャします。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/b8c7bf1b-367a-def5-d6b3-666b1f437209.png)<br/>キャプチャした結果は以下のようになります。実行するアクションに「Get Property」を指定し、「HTML Inner」を取得、`variable2`に格納します。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/e7e9a5aa-0d6d-8ae4-5cc5-1f7bc299dd56.png)
4. 同様に、もうひとつObject Cloningコマンドをワークベンチにドラッグ＆ドロップします。開くダイアログボックスでInternet Explorerのウィンドウを指定して、キャプチャボタンを押して、Webページの以下の部分をキャプチャします。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/2d2a616c-748e-eaf9-2b0a-4577607c9360.png)<br/>キャプチャした結果は以下のようになります。実行するアクションに「Get Property」を指定し、「HTML HRef」を取得、`variable3`に格納します。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/34e0cc16-30eb-153c-f9e9-e2b373013892.png)

これでObject Cloningコマンドが3つ並びました。ちなみに、Object Cloningコマンドを使うときは「Object Cloningイメージ」ウィンドウが自動的に表示され、選択しているコマンドでキャプチャしているUI要素を表示してくれるのですが、キャプチャしたコントロールそのもののみしか表示してくれないのと、ウィンドウの縦横比がいつも決まっているため、だいたい縦に間延びした画像となってしまい、ちょっと醜いですね( ;∀;)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/04ad6640-c26c-3f3d-e188-f4fbb2a41fdb.png)

>注: Object Cloningの「キャプチャ」ボタンを押してマウスカーソルをキャプチャしたいコントロールの上に載せようとすると、マウスカーソルが点滅したりいきなり位置が変わったりすることがあるので、正しいコントロールがキャプチャできるまで何回か根気よく試す必要があります。ちなみに、キャプチャする場合は、キャプチャしたいコントロールをクリックするのではなく、マウスカーソルを移動させて数秒間待つ、という動作となります。

尚、アクションリストの最後にMessage Boxコマンドを追加して`variable1`、`variable2`、`variable3`の内容を表示するようにしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/bffae9b5-857c-7bfa-cda9-53bb7bb4c32b.png)

アクションリストを保存して実行するとコントロールのテキストがきちんと取得できていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/0702066b-29e0-7ad7-a82c-8d1821aa0dd6.png)



### 処理する詳細ページを一般化する
最初の詳細ページでは必要な情報を取得する仕組みができたので、他の詳細ページでも同じ情報が取得できるようにアクションリストを一般化します。

1. まず、新たに変数として`URL`と`Title`を追加します。既定値には最初の詳細ページのURLとWebページのタイトルを入れておきます。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/56eaedbd-6194-2d63-e96f-85fbb2741c34.png)
2. 次に、**「Web Browser」-「Open Browser」コマンド**をアクションリストの先頭に追加、URLプロパティには変数`$URL$`を入れておきます。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/53666204-4e40-87a2-f179-8de2262fb812.png)
3. 3つのObject Cloningコマンドのダイアログボックスを開いて、ウィンドウ選択のテキストボックスに変数`$Title$`を入力します。「保存」ボタンを押した後に、右下のような「List of Window」というダイアログボックスが出てきて、「そんなウィンドウタイトルないけどこの中のどれかの間違えじゃない？」と聞いてくるので、「None of the Above」ボタンを押すと、おとなしく入力されます。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/4cfdcfcd-2ac2-f60c-1637-b9480f2feb80.png)
4. これで、以下のような一般化されたアクションリストが出来上がりました！<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/b809440e-91a2-0a63-085b-1fa6aa2b85c4.png)<br/>アクションリストを保存して実行するとコントロールのテキストがきちんと取得できていることがわかります。<br/>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/0702066b-29e0-7ad7-a82c-8d1821aa0dd6.png)

### さらにプロパティを編集して正しいコントロールを選択できるようにする
さて、ここからはちょっと難しいですが、他の詳細ページでもObject Cloningが働くように、AAのObject Cloningの仕様 (特に[XPathの仕様](https://ja.wikipedia.org/wiki/XML_Path_Language)も) を見ながら、プロパティの内容を最適化します。ちょっと厄介なのは、今回の場合、**詳細ページの構造がページごとに微妙に異なることです**。いくつかページのHTMLソースを見て、共通なルールを見極め、それをもとにDOMXPathに指定していく必要があります。
まず、抜き出したい要素の近くのHTMLソースを見てみます。

```HTML:HTMLソース(id="priceBox"付近を抜粋)
<div id="priceBox" class="priceBoxWrap">
  <div class="priceWrap">
    <span class="newBrand">最安価格(税込)：</span>
    <div class="subInfoObj1">
      <p>
        <span class="priceTxt">&yen;52,830</span>
      </p>
      <div class="offer">
        <span class="priceRate">(前週比：<span class="priceNovary">±0 </span><img width="12" height="12"  src="https://img1.kakaku.k-img.com/images/itemview/item/icon_help2.gif" alt="" onclick="balloonOver()">)
          <span style="display:none" id="balloonMini">
            <span class="balloonMiniMain">7日前の最安価格との対比<a href="javascript:void(0)" onClick="balloonOut();return false;" title="閉じる"><img width="15" height="15" src="https://img1.kakaku.k-img.com/images/itemview/item/itemv_balloon_close.gif"></a>
            </span>
          </span>
          </span>
        <span class="priceRateG"><span class="priceRateLink"><a target="_blank" href="https://kakaku.com/item/K0001219355/pricehistory/">価格推移グラフ</a></span></span>
      </div>
...
  <div class="subInfoObj4">
    <span>価格帯：<span itemprop="lowPrice">&yen;52,830</span>～<span itemprop="highPrice">&yen;52,830</span> (<a href="https://kakaku.com/item/K0001219355/#tab"><span itemprop="offerCount">1</span>店舗</a>)</span>
    <span>メーカー希望小売価格：&yen;―</span>
  </div>
```

**1番目のObject Cloningコマンドでは、以下の部分を変更します。**

* オブジェクト終了までの待機時間を15秒から2秒に変更。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/3a45167f-fe61-0ca7-2ef1-f35f2a256b2b.png)
* Path を検索対象から外す (Pathの左側にある「双眼鏡」アイコンをダブルクリックして非表示にする) - DOMXPathと被っているので
* DOMXPathを以下のとおり変更します

```xml:変更前
//div[@id='priceBox']/div[1]/div[1]/div[1]/span[1]/span[1]
```
```xml:変更後
//div[@id='priceBox']/div[1]/div[1]/div[1]/span[1]
```

**2番目のObject Cloningコマンドでは、以下の部分を変更します。**

* オブジェクト終了までの待機時間を15秒から2秒に変更。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/3a45167f-fe61-0ca7-2ef1-f35f2a256b2b.png)
* Path を検索対象から外す (Pathの左側にある「双眼鏡」アイコンをダブルクリックして非表示にする) - DOMXPathと被っているので
* DOMXPathを以下のとおり変更します

```xml:変更前
//div[@id='priceBox']/div[2]/span[1]/span[1]
```
```xml:変更後
//div[@class='subInfoObj4']/span[1]
```

**3番目のObject Cloningコマンドでは、以下の部分を変更します。**

* オブジェクト終了までの待機時間を15秒から2秒に変更。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/3a45167f-fe61-0ca7-2ef1-f35f2a256b2b.png)
* HTML Inner Text、HTML HRef、Path を検索対象から外す (各項目の左側にある「双眼鏡」アイコンをダブルクリックして非表示にする)


### Excelファイルの内容を読み込んでWebページタイトルとURLでループして詳細ページを切り替える仕組みを作る
全詳細ページについての情報が入っている`d:\kakakucom.xlsx`を読み込んで、詳細ページの数だけループを回してみましょう(^^)/

1. 「Excel」-「Open Spreadsheet」コマンドをアクションリストの先頭に挿入します。読み込むファイルには`d:\kakakucom.xlsx`を指定して、ヘッダーを含めます。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/142c3590-d60f-185a-1c28-f76917c1fe28.png)
2. 「Excel」-「Get Cells」コマンドを次に挿入し、全セルを取得をしています。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/19ac0267-2ffa-9bb9-9088-af5f200eb7a7.png)
3. 「LOOP」-「Each Row In An Excel Sheet」コマンドを次に挿入します。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/b93ac81e-0179-d507-7c4f-a1834ba5ef52.png)<br/>これで、先頭に以下のアクションリストが完成します。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/fea6a07e-01d6-62d8-e602-dabf64a55f95.png)
4. 6-10行目を選択して、4行目のコメントの部分にドラッグ＆ドロップして、アクションをループの中に取り込みます。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/a843f42f-7e10-1f29-c690-823dbd31aabc.png)
5. 続いて、4行目の部分に、Variable Operationコマンドをドラッグ＆ドロップします。最初は`URL`にExcelシートの3列目`$Excel Column(3)$`を代入します。<br/>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/dc9b9804-5474-8d89-1489-ef1d082c23ff.png)
6. もう一度4行目の部分に、次は、VB.NETで書くと以下のようなロジックを`Title`に代入します。(タイトル文字列はUiPathと比べると " - Internet Explorer"という文字列が最後に必要です。)

```VisualBasic:Title
Title="価格.com - " + iif(Left(Excel Column(2),Len(Excel Column(1)))=Excel Column(1),"",Excel Column(1)+" ")+Excel Column(2)+" 価格比較 - Internet Explorer"
```
このような複雑な文字列オペレーションの場合、AAではVariable Operation / String Operationや条件分岐等を複数回使用する必要があります。ロジックをくみ上げて、いままでのアクションリストを整理すると、以下のものが完成します。(<font color="Red">赤枠</font>内が上の式のロジック部分に相当します(^^♪)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/b94c6583-fa6a-8392-3143-cb606f9928c9.png)

### CSVファイルへの結果の書き込みを行う
詳細ページから得られた情報`variable1`、`variable2`、`variable3`ですが、Excelの表に列を3つ追加して格納したうえで`d:\kakakucom_output.csv`にCSVファイルとして書き込むことにします。これは文字列をファイルにテキストとして出力する「Log To File」コマンドを2か所に挿入することで対応します。まず、ループに入る前にヘッダーを書き込みます。(「ログファイルに加える」はOFFにして既存データがあれば破棄します。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/0512ed3c-7a7f-0d6b-d044-4e610032b713.png)
後はループの最後で、各変数をCSV形式で書き込みます。(「ログファイルに加える」はONにして既存データに追加します。)

これを加えたアクションリストは以下のようになります。(<font color="Red">赤枠</font>内が追加した部分)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/0a77dd25-bdf5-65f9-62e5-0eaca1ee6571.png)


### ページによっては要素が存在しない場合のエラー処理を加える
1ページ目、2ページ目とブラウザーが開いて実行されていきますが、今回の場合、2ページ目の途中で以下のエラーで止まってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/bd39a626-5e4c-6b17-ebb6-2bb32890c225.png)
これは2ページ目には「価格帯」の情報がないためです。このように、Object Cloningコマンドは、要素がないときにエラーが出てしまいますので、3つとも、Error Handlingコマンドで囲いましょう(^_-)-☆ (完成リストの18-29行目)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/969b6d5f-fc40-8b24-f4f2-09f54255d4db.png)

ここで、Error Handlingコマンドの囲いは、エラーが起こると思われる**コマンド毎に、別々に囲ってください**。エラーが発生した場合のアクションについて、既定ではContinueとなっていますが、Error Handlingコマンドの囲いの中に複数のコマンドが含まれる場合、エラーが起こった行でError Handlingの囲いを離脱してしまう仕様になっているからです。つまり、エラーが起こった場合、囲われている後ろの方のコマンドは実行されなくなってしまいます( ;∀;)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/9fd7a3fd-de42-8b0e-13a5-6ce27dd8b952.png)
([公式製品ドキュメント](https://docs.automationanywhere.com/bundle/enterprise-v11.3/page/enterprise/topics/aae-client/bot-creator/commands/error-handling-command.html?_LANG=jpjp)ではエラー時の動作は触れられていませんが、実際に実行してみるとそうなります)

また、`variable1`、`variable2`、`variable3`を初期化するコマンドを直前に入れておきます。(完成リストの15-17行目)



### 完成!
これですべて完成です。また、デバッグのために入れていたMessage Boxコマンドは無効または削除しておきましょう。
アクションリストは以下の通りになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/0979ecae-39a6-1e7c-b7d0-0bf121b6c79b.png)



保存して実行すると、`d:\kakakucom_output.csv`に以下のようなCSVファイルができています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490819/83b85d28-de5f-25c9-e260-f251486eef97.png)

[サンプルファイルscraping2.atmxをGitHubからダウンロード](https://github.com/o-kura/AutomationAnywhere/blob/master/v11/scraping2.atmx)

# まとめ
これで、UiPathとAAでの実装の両方についてみてきました！それぞれ実装時のクセや得意、不得意分野があるのがお判りいただけたかと思います。どちらがいいということはありませんが、両方ともいろいろできるRPAなので、うまく使いこなすのが吉です♪