kubernetes + selenium server + Node-RED でWebスクレイピング

#はじめに
以前、Windows上のpythonでselenium+webdriverを扱った事があるのですが、なかなか便利なものだと感じておりました。最近またWebの自動化を調査していたところ、seleniumのコンテナがある事を知り、我が家のRaspberry Pi kubernetesでも動かせないか調べて、なんとか動かす事ができました。

自動化のテスト内容は、私の住んでいる地域では、2021年度からTEPCOの電気料金を通知してくれる検針票が紙からWebでの確認に切り替わりましたので、試しに電気代の取得を自動化してみました。

#環境
- 我が家のkubernetes v1.20.x (ARM64) on Raspberry Pi 4B

```shell-session:
% ssh chino kubectl get nodes -o wide
NAME    STATUS   ROLES           AGE    VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                       KERNEL-VERSION   CONTAINER-RUNTIME
chino   Ready    control-plane   254d   v1.20.5   10.0.0.1      <none>        Debian GNU/Linux 10 (buster)   5.4.83-v8+       docker://20.10.5
chiya   Ready    worker          254d   v1.20.0   10.0.0.5      <none>        Debian GNU/Linux 10 (buster)   5.4.65-v8+       docker://20.10.1
cocoa   Ready    worker          248d   v1.20.0   10.0.0.2      <none>        Debian GNU/Linux 10 (buster)   5.4.65-v8+       docker://20.10.1
maya    Ready    worker          111d   v1.20.1   10.0.0.7      <none>        Debian GNU/Linux 10 (buster)   5.4.65-v8+       cri-o://1.20.0
megu    Ready    worker          146d   v1.20.1   10.0.0.8      <none>        Debian GNU/Linux 10 (buster)   5.4.83-v8+       cri-o://1.20.0
rize    Ready    worker          248d   v1.20.0   10.0.0.3      <none>        Debian GNU/Linux 10 (buster)   5.4.65-v8+       docker://20.10.1
syaro   Ready    worker          248d   v1.20.0   10.0.0.4      <none>        Debian GNU/Linux 10 (buster)   5.4.65-v8+       docker://20.10.1
```

# Seleniumのデプロイ
SeleniumHQにkubernetes用のyamlがありますが、そのままデプロイしてもRaspberry PiのARM64アーキテクチャ環境では動作しません。

https://github.com/SeleniumHQ/docker-selenium/blob/trunk/k8s-deployment-full-grid.yaml

ARM用のイメージについて色々調べたところ、issuesにAMD64/ARM64のイメージを作ってる方がおりました。

https://github.com/SeleniumHQ/docker-selenium/issues/1076#issuecomment-788343926

「seleniarm」とは洒落てますね！
その方が作成したkubernetes用のyamlは、以下にあります。

https://github.com/sj26/docker-selenium/blob/trunk/k8s-deployment-full-grid.yaml

ですが、私はfull-gridではなく、1台だけ使えればいいので「seleniarm/standalone-chromium」のコンテナイメージだけを使い、hubのポート(4444)とvncのポート(5900→6900)をexternalIP(192.168.1.98)経由でアクセスできるようにpodをデプロイしました。
まずは、Serviceリソースです。

```yaml:seleniarm-chromiun-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: seleniarm-chromium
  labels:
    app: seleniarm-chromium
spec:
  type: ClusterIP
  externalIPs:
    - 192.168.1.98
  selector:
    app: seleniarm-chromium
  ports:
    - name: vnc
      port: 6900
      targetPort: 5900
    - name: hub
      port: 4444
      targetPort: 4444
```

kubectlで適用します。

```shell-session:
# kubectl apply -f seleniarm-chromiun-svc.yaml 
service/seleniarm-chromium created
```

次にPodリソースです。

```yaml:seleniarm-chromiun-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: seleniarm-chromium
  labels:
    app: seleniarm-chromium
spec:
  containers:
    - name: seleniarm-chromium
      image: seleniarm/standalone-chromium:4.0.0-beta-1-20210215
      resources:
        requests:
          cpu: 1
          memory: 1Gi
        limits:
          cpu: 1
          memory: 1Gi
      ports:
        - name: vnc
          containerPort: 5900
          protocol: TCP
        - name: hub
          containerPort: 4444
          protocol: TCP
      volumeMounts:
        - name: dshm
          mountPath: /dev/shm
  volumes:
    - name: dshm
      emptyDir: { "medium": "Memory" }
```

kubectlで適用します。

```shell-session:
# kubectl apply -f seleniarm-chromiun-pod.yaml 
pod/seleniarm-chromium created
```

アプリケーション毎の各リソースに同じラベルを付与しておくと、リソース確認時のラベルでのフィルタ指定が楽になります。アプリケーションが多くなるようであれば、手間でも付与しておいた方が良いと思います。

```shell-session:
# kubectl get all -l app=seleniarm-chromium
NAME                     READY   STATUS    RESTARTS   AGE
pod/seleniarm-chromium   1/1     Running   0          12m

NAME                         TYPE        CLUSTER-IP     EXTERNAL-IP    PORT(S)             AGE
service/seleniarm-chromium   ClusterIP   10.96.12.179   192.168.1.98   6900/TCP,4444/TCP   12m
```


# Selenium Serverへのアクセス

selenium hubのコンソールポートとも言われているようですが、ブラウザでアクセスすると、以下のような画面が表示されます。

![スクリーンショット 2021-06-01 15.14.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/85b409b4-6acf-a892-9af1-f7b2350ee916.png)


tuxペンギンの横にある「i」のアイコンをクリックすると、ノードの詳細が表示されます。

![スクリーンショット 2021-06-01 15.14.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/fb83000c-ec05-5b27-6484-69c9ba1db7ef.png)

ちゃんと「aarch64」で稼働できているようです。

# VNCポートへの接続(MacOS X)
MacOS Xの場合は、Finderのメニューから「移動」-「サーバへ接続…」を選択します。

![スクリーンショット 2021-05-27 7.01.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/865a18ad-841a-fe92-3b63-27ef78f75a63.png)

以下のような形式のアドレスでVNC接続できます。(IPアドレスはご自身の環境のものを指定してください)

![スクリーンショット 2021-05-27 7.01.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/414dcb9a-5682-afdb-d61e-e94572e5a069.png)

VNC接続用のパスワードは「secret」です。

![secret.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/c34fb8f2-4023-b993-29d6-610a3aa821a5.png)

以下のようなロゴが確認できればChromiumノードは正常かと思います。

![スクリーンショット 2021-06-01 15.19.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/39d996b8-8e9c-72f8-659f-92dd624140c1.png)


# Node-REDでフローの作成

Node-REDの「パレットの管理」の「ノードを追加」タブで"selenium"を検索語にして、「node-red-contrib-selenium-webdriver」ノードを追加します。

![スクリーンショット 2021-05-30 22.41.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/39413571-8afa-1752-38b5-b19912496128.png)

作成したサブフローは以下のようなものです。

![スクリーンショット 2021-06-01 16.09.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/a4f36c6a-2cc9-6a02-35f2-8a11d47f5355.png)

入力が必要なものは、全て環境変数で設定しています。

![スクリーンショット 2021-06-01 16.09.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/d982675c-922c-f03c-92c1-f08e20dc7fd5.png)

サブフローを書き出したJSONは以下になります。
(seleniumサーバへの接続URLは、サブフローを編集してご自身の環境に合ったものを指定してください)

:::note warn
2021/10/13記載：電話認証が必要になったようなので、スクレイピングできなくなりました。
TEPCOに会員登録してもAPIでさくっと取得できるような仕組みは提供されていないようです。
~~人の手作業でPull型の情報取得しかできないのはレガシーシステムの考え方なのかなと。~~
:::

~~↓三角をクリックでJSONデータが展開されます。~~
<details><summary>~~絶対会員登録せずに確認する電気代取得サブフロー~~</summary><div>

```json:
[
  {
    "id": "dc9d610d.db821",
    "type": "subflow",
    "name": "電気代取得",
    "info": "",
    "category": "",
    "in": [
      {
        "x": 30,
        "y": 80,
        "wires": [
          {
            "id": "333b08dd.0bdd58"
          }
        ]
      }
    ],
    "out": [
      {
        "x": 570,
        "y": 460,
        "wires": [
          {
            "id": "a384a647.e68528",
            "port": 0
          }
        ]
      }
    ],
    "env": [
      {
        "name": "OFFICECODE",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "事業所コード"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "VISITNUM1",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "お客様番号1"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "VISITNUM2",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "お客様番号2"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "VISITNUM3",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "お客様番号3"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "VISITNUM4",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "お客様番号4"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "ZIPCODE1",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "郵便番号1"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "ZIPCODE2",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "郵便番号2"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "FIRSTNAME",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "セイ"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "LASTNAME",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "メイ"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "PHONENUM1",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "電話番号1"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "PHONENUM2",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "電話番号2"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "PHONENUM3",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "電話番号3"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "BANCHI",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "番地"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      },
      {
        "name": "GOU",
        "type": "str",
        "value": "",
        "ui": {
          "label": {
            "en-US": "号"
          },
          "type": "input",
          "opts": {
            "types": [
              "str"
            ]
          }
        }
      }
    ],
    "meta": {},
    "color": "#FFAAAA",
    "icon": "font-awesome/fa-flash"
  },
  {
    "id": "333b08dd.0bdd58",
    "type": "open-web",
    "z": "dc9d610d.db821",
    "name": "TEPCO Web検針票",
    "browser": "chrome",
    "weburl": "https://www.kenshin.tepco.co.jp/",
    "width": 1024,
    "height": 768,
    "webtitle": "Google",
    "timeout": 3000,
    "maximized": true,
    "server": "c6ee5be2.9cbec8",
    "x": 200,
    "y": 80,
    "wires": [
      [
        "0c1928376142fec3"
      ]
    ]
  },
  {
    "id": "a384a647.e68528",
    "type": "close-web",
    "z": "dc9d610d.db821",
    "name": "",
    "waitfor": 500,
    "x": 470,
    "y": 460,
    "wires": [
      []
    ]
  },
  {
    "id": "7bb1c1d6.a09cb",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "事業所コード",
    "text": "",
    "selector": "id",
    "target": "officeCode",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 890,
    "y": 80,
    "wires": [
      [
        "77348357.8acdac"
      ]
    ]
  },
  {
    "id": "578491ab.632b7",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "お客様番号1",
    "text": "",
    "selector": "id",
    "target": "visitNumber1",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 390,
    "y": 140,
    "wires": [
      [
        "46bf4be5.dd4b54"
      ]
    ]
  },
  {
    "id": "e6a1ba49.8b01f8",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "お客様番号2",
    "text": "",
    "selector": "id",
    "target": "visitNumber2",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 750,
    "y": 140,
    "wires": [
      [
        "a4f546a3.c2bf58"
      ]
    ]
  },
  {
    "id": "94b6af32.8c5e7",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "お客様番号3",
    "text": "",
    "selector": "id",
    "target": "visitNumber3",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 1110,
    "y": 140,
    "wires": [
      [
        "fa76224d.19f81"
      ]
    ]
  },
  {
    "id": "d207bc31.15e9d",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "お客様番号4",
    "text": "",
    "selector": "id",
    "target": "visitNumber4",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 1470,
    "y": 140,
    "wires": [
      [
        "a342b4bb.a189d8"
      ]
    ]
  },
  {
    "id": "f6a70e22.d581e",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "郵便番号1",
    "text": "",
    "selector": "id",
    "target": "zipCode1",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 390,
    "y": 210,
    "wires": [
      [
        "6ea2fc8e.678544"
      ]
    ]
  },
  {
    "id": "9e1a02dc.651f4",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "郵便番号2",
    "text": "",
    "selector": "id",
    "target": "zipCode2",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 750,
    "y": 210,
    "wires": [
      [
        "7f1b1ac8.44a814"
      ]
    ]
  },
  {
    "id": "7f1b1ac8.44a814",
    "type": "click-on",
    "z": "dc9d610d.db821",
    "name": "住所検索",
    "selector": "id",
    "target": "searchAddress",
    "timeout": 1000,
    "waitfor": 500,
    "clickon": false,
    "x": 920,
    "y": 210,
    "wires": [
      [
        "571f0a78.bef2d4"
      ]
    ]
  },
  {
    "id": "80d1c5a2.083a88",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "契約名義(セイ)",
    "text": "",
    "selector": "id",
    "target": "first_name",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 400,
    "y": 360,
    "wires": [
      [
        "e5e08208.c6ea5"
      ]
    ]
  },
  {
    "id": "262a8670.52c6ea",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "契約名義(メイ)",
    "text": "",
    "selector": "id",
    "target": "last_name",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 780,
    "y": 360,
    "wires": [
      [
        "81aba5bf.f99688"
      ]
    ]
  },
  {
    "id": "5fc18ee8.704e6",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "電話番号1",
    "text": "",
    "selector": "id",
    "target": "phoneNumber1",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 390,
    "y": 670,
    "wires": [
      [
        "21b8833f.795a8c"
      ]
    ]
  },
  {
    "id": "72999e09.363cb",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "電話番号2",
    "text": "",
    "selector": "id",
    "target": "phoneNumber2",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 770,
    "y": 670,
    "wires": [
      [
        "a0a555b7.cfdaa8"
      ]
    ]
  },
  {
    "id": "16ffc28.fdfa03e",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "電話番号3",
    "text": "",
    "selector": "id",
    "target": "phoneNumber3",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 1130,
    "y": 670,
    "wires": [
      []
    ]
  },
  {
    "id": "81aba5bf.f99688",
    "type": "click-on",
    "z": "dc9d610d.db821",
    "name": "照会",
    "selector": "id",
    "target": "inquiry",
    "timeout": 1000,
    "waitfor": 500,
    "clickon": false,
    "x": 190,
    "y": 460,
    "wires": [
      [
        "4d792456.f4a91c"
      ]
    ]
  },
  {
    "id": "4d792456.f4a91c",
    "type": "get-text",
    "z": "dc9d610d.db821",
    "name": "",
    "expected": "",
    "selector": "className",
    "target": "info-price",
    "timeout": 1000,
    "waitfor": 500,
    "savetofile": false,
    "x": 330,
    "y": 460,
    "wires": [
      [
        "a384a647.e68528"
      ]
    ]
  },
  {
    "id": "8a09a506.aed678",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "OFFICECODE",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 700,
    "y": 80,
    "wires": [
      [
        "7bb1c1d6.a09cb"
      ]
    ]
  },
  {
    "id": "77348357.8acdac",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "VISITNUM1",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 210,
    "y": 140,
    "wires": [
      [
        "578491ab.632b7"
      ]
    ]
  },
  {
    "id": "46bf4be5.dd4b54",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "VISITNUM2",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 570,
    "y": 140,
    "wires": [
      [
        "e6a1ba49.8b01f8"
      ]
    ]
  },
  {
    "id": "a4f546a3.c2bf58",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "VISITNUM3",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 930,
    "y": 140,
    "wires": [
      [
        "94b6af32.8c5e7"
      ]
    ]
  },
  {
    "id": "fa76224d.19f81",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "VISITNUM4",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 1290,
    "y": 140,
    "wires": [
      [
        "d207bc31.15e9d"
      ]
    ]
  },
  {
    "id": "a342b4bb.a189d8",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "ZIPCODE1",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 210,
    "y": 210,
    "wires": [
      [
        "f6a70e22.d581e"
      ]
    ]
  },
  {
    "id": "6ea2fc8e.678544",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "ZIPCODE2",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 570,
    "y": 210,
    "wires": [
      [
        "9e1a02dc.651f4"
      ]
    ]
  },
  {
    "id": "7a5d7e5b.fc01d",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "FIRSTNAME",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 210,
    "y": 360,
    "wires": [
      [
        "80d1c5a2.083a88"
      ]
    ]
  },
  {
    "id": "e5e08208.c6ea5",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "LASTNAME",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 590,
    "y": 360,
    "wires": [
      [
        "262a8670.52c6ea"
      ]
    ]
  },
  {
    "id": "d86ff679.729248",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "PHONENUM1",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 210,
    "y": 670,
    "wires": [
      [
        "5fc18ee8.704e6"
      ]
    ]
  },
  {
    "id": "21b8833f.795a8c",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "PHONENUM2",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 590,
    "y": 670,
    "wires": [
      [
        "72999e09.363cb"
      ]
    ]
  },
  {
    "id": "a0a555b7.cfdaa8",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "PHONENUM3",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 950,
    "y": 670,
    "wires": [
      [
        "16ffc28.fdfa03e"
      ]
    ]
  },
  {
    "id": "6f807932.4dac58",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "番地",
    "text": "",
    "selector": "id",
    "target": "address_banchi",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 370,
    "y": 270,
    "wires": [
      [
        "94aaa7a1.8f5da8"
      ]
    ]
  },
  {
    "id": "571f0a78.bef2d4",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "BANCHI",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 210,
    "y": 270,
    "wires": [
      [
        "6f807932.4dac58"
      ]
    ]
  },
  {
    "id": "618ae571.e8087c",
    "type": "send-keys",
    "z": "dc9d610d.db821",
    "name": "号",
    "text": "",
    "selector": "id",
    "target": "address_gou",
    "timeout": 1000,
    "waitfor": 500,
    "clearval": false,
    "x": 700,
    "y": 270,
    "wires": [
      [
        "7a5d7e5b.fc01d"
      ]
    ]
  },
  {
    "id": "94aaa7a1.8f5da8",
    "type": "change",
    "z": "dc9d610d.db821",
    "name": "",
    "rules": [
      {
        "t": "set",
        "p": "value",
        "pt": "msg",
        "to": "GOU",
        "tot": "env"
      }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 540,
    "y": 270,
    "wires": [
      [
        "618ae571.e8087c"
      ]
    ]
  },
  {
    "id": "0c1928376142fec3",
    "type": "click-on",
    "z": "dc9d610d.db821",
    "name": "照会",
    "selector": "className",
    "target": "btn-bg-red notes-open-top",
    "timeout": 1000,
    "waitfor": 500,
    "clickon": false,
    "x": 380,
    "y": 80,
    "wires": [
      [
        "ddbe05e91f23c0a8"
      ]
    ]
  },
  {
    "id": "ddbe05e91f23c0a8",
    "type": "click-on",
    "z": "dc9d610d.db821",
    "name": "照会",
    "selector": "className",
    "target": "btn btn-s modal-button-upper",
    "timeout": 1000,
    "waitfor": 500,
    "clickon": false,
    "x": 530,
    "y": 80,
    "wires": [
      [
        "8a09a506.aed678"
      ]
    ]
  },
  {
    "id": "c6ee5be2.9cbec8",
    "type": "selenium-server",
    "remoteurl": "http://192.168.1.9:30444"
  },
  {
    "id": "8be0fab6cfc13f9e",
    "type": "subflow:dc9d610d.db821",
    "z": "4c288cd6.7479c4",
    "name": "",
    "x": 810,
    "y": 1580,
    "wires": [
      []
    ]
  }
]
```

</div></details>

サブフローをダブルクリックして環境変数を設定してインジェクトノードから実行すれば、「msg.payload」に直近の期間の電気代が返ります。

![スクリーンショット 2021-06-01 16.32.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/e5e9ddaa-e845-8f53-982c-d07ae6ccdf86.png)

VNCの画面でブラウザの動作が確認できます。いつ見ても自動でブラウザが動いているのを見るのは楽しいです。(4倍速にしてます)

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/382b9e6d-8d9b-9bec-e2f3-43b8dca3eb9c.gif)

# おわりに
今回のテストはcurlでもできそうなくらいの内容なのですが、Node-REDからseleniumが利用できると何でも自動化できそうな気がして夢が膨らみますね。
注意点としては、「node-red-contrib-selenium-webdriver」のノードはサブフローで組まないと、すぐに「RangeError: Maximum call stack size exceeded」になります。
あと、流石にRaspberry Pi kubernetesでは重いですね...full gridをデプロイしてWeb画面のテストとかはキツそうです。