PowerAutomate: PAD を使わず、Webスクレイピング

# 背景
Power Automate Desktop や RPA だと 定期的な Web Scraping を動かすのがだるい
ってことで、Power Automate でやれる方法を試行してみた記録

# 概要
1. サイトを取得して OneDrive へ保存
1. HTML ページを XML 変換
1. XML から XPATH で取得
あとは煮るなり焼くなり
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/8549a14a-f1db-9866-565c-dd36fdd4dbc9.png)


# 詳細例
## サイトを取得して OneDrive へ保存

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/9b0093f7-3224-e9b4-32a3-d772c12261eb.png)

1. [URL からファイルをアップロード](https://learn.microsoft.com/ja-jp/connectors/onedriveforbusiness/#url-%E3%81%8B%E3%82%89%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89) でサイトを取得して OneDrive へ保存
1. [ファイル コンテンツの取得](https://learn.microsoft.com/ja-jp/connectors/onedriveforbusiness/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB-%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E3%81%AE%E5%8F%96%E5%BE%97) で利用できるように取得しておく

## HTML ページを XML 変換
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/a8ada83d-8fb7-3d2e-2c3b-3e63177d23f4.png)

HTML をそのまま [xml()](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#xml) 関数で変換できるサイトなら、特に苦労なく使うだけ

今回は、以下のような問題があったので、正規表現や replace() を利用して、XML 化出来るように修正をした

### 課題と対処

- script や meta、コメントなど
    - <code>\<!-- Google Tag Manager (noscript) --></code>
        - 正規表現で除外
- タグが閉じていない
    - タグ自体を正規表現で除外
- タグ内属性で、"=" がないもの。 async, defer, etc.
    - <code>\<script src="/oo/np/lsync.js" **async**></script></code>
        - replace() で除外
- 特殊文字
    - \&nbsp;, \&emsp;, \&ensp;, etc.
        - replace() で除外
- 構成が壊れているもの
    - 不要なら、正規表現で除外
    - 必要なら、なんとかして閉じタグを追加　＜今回はこれ

あとは、以下のようにして変換するのみ

```json: xml
@{xml(outputs('Compose_div抜けの対処（追加）'))}
```

正規表現の使い方は、以下で

https://qiita.com/baku2san/items/74885b03ada5be8f6f42

## XML から XPATH で取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/0c6e12ed-f6db-ddfb-8f7d-884a8b7ac943.png)

あとは xpath で、欲しい場所を指定して取得してくるだけ

以下の例だと・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/509cb4cb-bd75-8785-2665-fa45ca02846e.png)


- text() = "電気銅" となっている <span> の親<td> の兄弟<td> に欲しい価格情報が順番に四点入っているので、以下のような xpath() で取得。sibling は便利

```json: xpath
@{xpath(outputs('Compose_to_XML'), '//span[contains(text(),"電気銅")]/../following-sibling::td')}
```

取得結果はこんな感じになるので

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/4160d0cc-f2a3-ba38-bba3-b01bdf44c3a4.png)

あとは、以下で値を取得するのみ

1. $content を取得
1. [base64ToString](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#base64ToString) でデコード
    - <code>\<td class="market-detail-list__value">1,110\</td></code>
1. タグを排除する
    1. substring(), indexof() で頑張ってやってるが、もっと良い方法が欲しい・・
1. int() で数値への変換

```json: 欲しい値を取得
@{int(substring(base64ToString(outputs('Compose_xpath')[0]['$content']), add(indexOf(base64ToString(outputs('Compose_xpath')[0]['$content']), '">'), 2), sub(length(base64ToString(outputs('Compose_xpath')[0]['$content'])), add(5, add(indexOf(base64ToString(outputs('Compose_xpath')[0]['$content']), '">'), 2)))))}
```


# あとがき
xml/xpath で Web スクレイピングが出来た

PAD や PRA, Selenium などと比較すると、取得自体へ面倒だけど、環境準備とか不要ってのがいい

最新データを定期取得して通知する程度ならこれでもいいんじゃね？と

# keyword
web scraping in Power Automate by xml and xpath functions