— 自動化/自動操作 – koneta https://koneta.click DIYとデジモノとプログラミングとライフハックをコネた...小ネタ Mon, 09 Aug 2021 09:42:51 +0000 ja hourly 1 https://wordpress.org/?v=6.1 https://koneta.click/wp-content/uploads/2020/02/cropped-icon-32x32.png — 自動化/自動操作 – koneta https://koneta.click 32 32 Nature Remo APIでn8nから家電を遠隔操作してみました https://koneta.click/p/791 https://koneta.click/p/791#respond Wed, 09 Jun 2021 16:24:36 +0000 https://koneta.click/?p=791 以前の記事でNature Remoというスマートリモコンで生活の未来度合いを向上することができたという記事を書きました。今回はそのRemoの活躍の場を広げるためプログラムから操作する…つまりはAPIを使って操作してみようと思います。加えてn8nでフローから操作もやってみようと思います。

背景

Nature Remoはスマホやスマートスピーカーから家電を簡単に操作することができるスマートリモコンです。私はその中でもNature Remo miniという端末を使用しています。Remo自体は紹介記事を書いていますのでよかったら読んでみてください。

また、IFTTTというサービスを活用することでワークフローを作成して、タイマーや居場所、SNSなどで設定した条件を満たしたときにRemoから家電を操作することができます。しかしIFTTTは最近無料で使用できる範囲が狭くなり使い勝手が悪くなってしまいました。 (私は元々使ってなかったので関係はなかったですが…)

そんな中、IFTTTの代わりとしてよく名前が挙がっているのがn8nです。n8nは無料で色々なサービスの連携/自動実行フローを作成できるのOSSのツールです。

n8nにRemoが公式に対応しているわけではないですが、RemoにはAPIが用意されているためHTTPSリクエストで家電を操作することができます。今回はこのAPIとn8nを使ってちょっと違った遠隔操作をしてみようと思います。

アクセストークンを取得する

APIを使用するためのアクセストークンを取得していきます。というわけでまずは home.nature.global にアクセスしてアクセストークンを作成します。

チープっぽいですが公式です。

ページにアクセスしたらGoogleアカウントで認証するかNatureに登録しているメールアドレスを入力してログイン用のメールを送信してもらってください。ログインができると「home.nature.globalがRemoへのアクセスをリクエストしています。」というページが表示されるので「許可する」を選択して完了です。

トークンは発行直後しか出ないのでモザイクの意味は…

権限の確認が終わると「Generate Access Token」のボタンが表示されます。このボタンを押すとアクセストークンが取得できます。一度ページを離れてしまうとアクセストークンは表示されないのでちゃんとメモしておくようにしてください。また、このトークンがほかの人に知られてしまうと、家電を好きなようにされてしまうので、絶対に外部に漏れないようにしてください。

これでアクセストークン取得完了です。

APIを使ってみる

トークンが取得できたので、n8nでワークフローを設定する前にAPIを使ってみます。APIはHTTPSリクエストで叩くことができるので、リクエストを飛ばせればなんでも大丈夫ですが、今回はcurlコマンドでやってみます。というわけで下記のコマンドを実行してみます。[アクセストークン]のところには1つ前の手順で取得したトークンで書き換えて実行してください。

$ curl -H "Authorization:[アクセストークン]" https://api.nature.global/1/appliances

これによりRemoに登録されている家電とそれぞれに実行できる操作の一覧を取得することができます。コマンド実行時に大切なのがヘッダーとして付与しているAuthorizationです。基本的にAPIを叩くときには必須の項目になります。そして、このコマンドで取得できる家電や操作にはIDが振られています。APIで家電を操作する際にはこのIDをパラメータとして指定するため操作したいIDはメモしておいてください。

今回は照明を操作してみようと思います。照明の操作には先ほどの取得した一覧からIDを持ってきます。

[
    {
        "他の家電情報"
    },
    {
        "id": "※※※※※※ ここのIDが大事 ※※※※※※",
        "device": {
            "...Remoの情報..."
        },
        "model": {
            "...照明自体の製品情報..."
        },
        "type": "LIGHT",
        "nickname": "照明",
        "image": "ico_light",
        "settings": null,
        "aircon": null,
        "signals": [],
        "light": {
            "buttons": [
                "...ボタン類..."
            ],
            "state": {
                "...明るさやON/OFFなど..."
            }
        }
    },
    {
        "他の家電情報"
    }
]

上記が一覧取得の結果を抜粋したものになりますが、この中の「※※※※※※ ここのIDが大事 ※※※※※※」部分に書かれているID
を使って照明を操作します。操作にはまたcurlで今度はPOSTします。

$ curl -H "Authorization:[アクセストークン]"  -X POST -d "button=on" https://api.nature.global/1/appliances/[照明のID]/light

これを実行すると照明が点灯するはずです。逆に消すときはbutton=onの部分をbutton=offにすれば大丈夫です。ちなみにこのボタンの設定値は先ほどの一覧取得した中のbuttonsnameの項目で確認することができます。ここまでできればあとはプログラムから叩いてもいいし煮ても焼いてもです。

n8nから実行する

さて本記事のメインでありながら、正直蛇足っぽいn8nからAPIを叩くフロー作成をやっていきます。とはいえここまでで動くことは確認できているのでn8nのHTTPリクエストノードに設定してあげるだけで動作します。

完成イメージ

ワークフローの完成イメージは上記の通りです。ただ動かすだけであればSTART含め2つのノードだけで作ることもできますが、一応将来性を考えトークンや照明IDの設定はSETノードに切り分けています。

SETには以下のように設定したい値を登録してあげるだけで大丈夫です。設定後一度ノードを実行してあげると次のノードでこの値を使用することができます。

設定値

次がメインのHTTPリクエストノードです。このノードでは基本的にcurlで叩いた値とSETノードで登録した値を登録してあげれば大丈夫です。SETノードで登録した値を使うには各入力欄の右側にある歯車マークから「Add Expression」を選択して「Nodes」からSetValuesString から選択することができます。あとはcurlで試した通りにHeaderとParametersに登録してあげるだけです。

前半
後半

これでフローは完成です。最後にフロー実行ボタンを押して正常に照明が操作できるかを確認してみてください。

エクスポートファイル (クリックで展開)
{
  "name": "Remo-Light",
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        200,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "Authorization",
              "value": "[アクセストークン]"
            },
            {
              "name": "Light-ID",
              "value": "[照明ID]"
            },
            {
              "name": "button",
              "value": "on"
            }
          ]
        },
        "options": {}
      },
      "name": "Set request data1",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        350,
        0
      ]
    },
    {
      "parameters": {
        "requestMethod": "POST",
        "url": "=https://api.nature.global/1/appliances/{{$json[\"Light-ID\"]}}/light",
        "options": {},
        "bodyParametersUi": {
          "parameter": [
            {}
          ]
        },
        "headerParametersUi": {
          "parameter": [
            {
              "name": "Authorization",
              "value": "={{$json[\"Authorization\"]}}"
            }
          ]
        },
        "queryParametersUi": {
          "parameter": [
            {
              "name": "button",
              "value": "={{$json[\"button\"]}}"
            }
          ]
        }
      },
      "name": "Turn Light1",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 1,
      "position": [
        500,
        0
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Set request data1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set request data1": {
      "main": [
        [
          {
            "node": "Turn Light1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {},
  "id": "7"
}

オマケとして、ここで作成したフローをエクスポートしたjsonファイルを載せておきます。使用する際はSETノード内のトークンと照明IDを修正してください。

終わりに

さて、そんなわけで今回はRemoとn8nの連携をやってみました。APIを使うことで自分のプログラムからでも操作できるようになるのでRemoの適用範囲をだいぶ広げることができると思います。

今回紹介した内容だけではちょっと物足りない気もしますが、私は今回紹介したフローの起点をWebHookにすることでリクエストされたら自動的にフローが実行されるようにし、使わなくなったKindleをリモコン兼データモニターとして活用しています。

意外といい感じ

別途アプリを入れる必要もなく、Kindle自体の脱獄も不要、Webブラウザが動けばリモコンとして使えるため、意外と気に入っています。そのうちこちらの詳細も記事にしたいと思います。

参考

Remo公式リファレンス

アクセストークン管理

]]>
https://koneta.click/p/791/feed 0
OSSのワークフロー作成ツール n8n をVPS(ConoHa)に構築します https://koneta.click/p/680 https://koneta.click/p/680#respond Sun, 14 Mar 2021 15:53:00 +0000 https://koneta.click/?p=680 この世にはWebサービスやイベントを繋げ自動的にワークフローを実行してくれる便利なツールがあります。この手の有名なツールとしてはIFTTTやZapierが挙がってきます。しかし、これらは一部機能が有料だったり登録できる件数が少なかったりします。そこで出てくるのが今回紹介するn8nです。

n8nは、オープンソースで使用できる自動化ツールで、IFTTTなどと同じように、何かしらの動作やイベントをトリガーとしてアクションが始まり、定義したフロー通りに自動で処理を行ってくれます。

そこで今回はn8nの環境をVPS(ConoHa)上のDockerで構築し簡単な操作方法を実際に試してみたいと思います。

環境構築

基本的な環境構築は公式サイトの「How to get started?」の項目を見ると全て書かれています。Node環境があればコマンドちょちょいで、Docker環境があればコマンド1つでツールを動かし始めることができます。しかしあえて今回はここに掲載されていないdocker-composeで環境を作っていこうと思います。

タイトルではVPSに構築しますと書いていますが、正直Docker環境があれば、結構どこでも大丈夫です。というわけでDocker環境を用意しておいていただきたいのですが、ConoHaでの環境構築は以前記事にまとめていますので、そちらを参考にしていただけるとと思います。

では早速作っていきたいと思います。とはいえDocker(docker-compose)上で構築するため、やることはほぼほぼコマンドを実行するだけです。というわけでdocker-composeを実行するため設定ファイルを用意していきます。内容は以下の通りです。

version: "3"

services:
  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER
      - N8N_BASIC_AUTH_PASSWORD
      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_TUNNEL_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ${DATA_FOLDER}/.n8n:/home/node/.n8n
    network_mode: bridge

docker-conpose.ymlだけで完結させることもできますが、取り回しがよくなるよう今回は設定ファイルを別に作成してみます。設定ファイルは.envという名前でymlファイルと同じところに置いておきます。内容は下記の通りです (ほぼ公式サイトのコピペです)。

# どこのフォルダにデータを保存する
DATA_FOLDER=/root/n8n/

# どんなトップドメインにn8nを設置する
DOMAIN_NAME=example.com

# どんなサブドメインでn8nを動かす
SUBDOMAIN=n8n

# BASIC認証のID - ※※※※※ 変更必須です ※※※※※
N8N_BASIC_AUTH_USER=user

# BASIC認証のPASSWORD - ※※※※※ 変更必須です ※※※※※
N8N_BASIC_AUTH_PASSWORD=password

# 定期実行で使用するタイムゾーン
GENERIC_TIMEZONE=Europe/Berlin

この設定で、n8n.example.comで受け付けるための設定ができます。ご自身の環境に合わせて修正してください。ちなみに、タイムゾーンはツール内の設定で変更できるのでそのままでも大丈夫です。

また外部からアクセスできる環境にn8nを設置するのであれば、上記の設定だけではSSLの設定ができたいないのでオープンな環境に設置するには不足しています。今回はn8nコンテナの前段としてリバースプロキシを設置するためSSLはそちらで補います。加えて公式にも書かれていますが、オープン環境に設置するのであればセキュリティ対策として最低限BASIC認証くらいは入れてください。

ここまでくればあとはDockerを起動するだけでn8n自体の設置作業は完了です。

$ docker-compose up --build -d

最後に.envで設定したドメインに合わせてDNSレコードやhostsを設定すれば作業完了です。

追加作業リバースプロキシ

さて、上記設定だけではSSLが未対応なので今回はリバースプロキシを設置して対応していきたいと思います。今回使用するリバースプロキシはDockerで動かすNginxで構築されていて基本的にコンテナを実行するだけで動作してくれるイメージを使います。

本記事でも最低限の項目は書いていこうと思いますが、以前に記事にまとめていますので、詳しくはこちらをご覧ください。

というわけで、リバースプロキシのDockerを用意します。

version: '3'

services:
  nginx-proxy:
    build: jwilder/nginx-proxy
    restart: on-failure
    labels:
      - com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=jwilder/nginx-proxy
    ports:
      - 80:80
      - 443:443
    volumes:
      - proxy:/etc/nginx/vhost.d
      - proxy:/usr/share/nginx/html
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./certs:/etc/nginx/certs:ro
    network_mode: bridge

  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    restart: on-failure
    depends_on:
      - nginx-proxy
    volumes:
      - proxy:/etc/nginx/vhost.d
      - proxy:/usr/share/nginx/html
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./certs:/etc/nginx/certs:rw
    network_mode: bridge

volumes:
  proxy:

これだけでリバースプロキシ自体の用意とSSLの準備が完了しました。毎度のお手軽さには驚かされます。このdocker-composeは先ほどのdocker-composeとは別に作成したほうがいいです。

次に、Nginx側で「良しなに」設定してもらうための記述を先ほどのn8n用docker-composeに追記していきます。追記項目はドメイン設定とSSL証明書取得用のメールアドレス、そしてコンテナを繋げるネットワーク設定です。

version: "3"

services:
  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "5678:5678"
    environment:
      ...(省略)...
      - VIRTUAL_HOST=n8n.knta.cc
      - LETSENCRYPT_HOST=n8n.knta.cc
      - LETSENCRYPT_EMAIL=tunezune.history@gmail.com
    volumes:
      - ...(省略)...
    network_mode: bridge

上記のようにn8nで使用するドメインと証明書取得用のメールアドレス、ブリッジの設定を追記します。最後にNGINXのコンテナを起動、n8nのコンテナを再度起動。これだけで作業完了です。

$ cd /path/to/nginx_docker-compose/
$ docker-compose up -d
$ cd /path/to/n8n_docker-compose/
$ docker-compose up -d

使ってみる

では環境構築ができたので、最後に軽くn8nを使ってみようと思います。題材は「slack投稿を定時実行」でやっていきます。

初期画面

n8nを起動して設定したドメインにアクセスすると上記の画像のようなページが表示されます。こちらがn8nのメイン画面になっています。画像真ん中らへんに表示されているStartのノードが初期フローの開始地点となっています。

基本の作業はこのノードに次のノードを繋げていくことでワークフローを作っていきます。ノードを追加するには右上にある赤色の+ボタンを押すか各ノードのドット部分からドラッグです。

定期実行する開始ノードを追加

上記の操作を行うとノードを選択するウインドウが出てきます。ここから追加したいノードを探します。ノードには2種類あり「Regular」が処理を行うノード、「Trigger」がワークフローの起点になるノードになります。今回は定期実行をするための起点ノードCronを使いたいため、Triger欄からCronを選択しています。

起点を追加した様子

Cronを追加した様子は上記の通りです。ノードを選択した際にノードに対応した設定画面が表示されたと思います。追加後でもノードをダブルクリックすると再度表示されます。今回は定期実行のノードのためいつ実行するかの設定ができます。

次にSlack投稿をしてもらうためSlackのノードを追加します。先ほどと同じようにノード追加画面を開き、今度は「Regular」の項目からSlackのノードを追加します。今回はSlackのAPIキーを取得するところは省略しますが、APIキーの設定、チャンネルと送信するテキストの設定で追加完了です。

また、こちらも本記事では使いませんが、送信するテキストには前のノードのデータ (各サービスのAPIノードであれば取得したデータ、RSS取得ノードならRSSの中身など) を指定することもできます。

フロー完成~!

以上の作業で上記のようなフローが完成です!最後にフローを保存して、右上の「Active」を有効にすることで定期的にSlackに送信してくれるフローが動き始めます。なんともまぁ簡単でした。

終わりに

さて、そんな感じで書いてきました。私の中では自動化というのはいろいろロマンのある作業だったりします。しかし、自動化をするにはいろいろ作業する必要があり、正直めんどくさいという面もあります…..。そんなところでn8nに出会ったわけですが思っていたよりも数倍簡単に環境構築もフロー作成もでき、今回は触れませんでしたがサーバ上のコマンドも実行できるので使い道はどこまでも広げることができます。ありがとういいツールです。何か便利な使い道を思いついたらまた記事にしようと思います。

]]>
https://koneta.click/p/680/feed 0
ConoHa上のDockerでSelenium ~とにかく動かしたい人向け~ https://koneta.click/p/519 https://koneta.click/p/519#respond Fri, 23 Oct 2020 14:30:47 +0000 https://koneta.click/?p=519 前の記事でConoHaというVPSにDockerとdocker-composeの環境を構築しました。なぜ構築したかというと…Seleniumを動かしたかったからです。正直なところ別にDocker上で動かす必要は無いのですが、一度、Docker環境で動かせるようになっておけば、他環境にも入れやすくなるのでやってみました。

というわけで今回は、ConoHa上のDockerでサクッとSeleniumを動かすことによって、ちょっとした自動操作をやってみたいと思います。GUIがない環境でも動くようにヘッドレス、ChromeとFirefoxで動かすのを目標にやっていきます。

Selenium?

SeleniumはWebアプリケーションのテスト用に開発されているフレームワークです。テスト用ではありますが、自動でWebページを操作できるというのは色々夢が広がります。動作テスト、情報の収集、タスクの自動化など…。Seleniumを動かせる言語は色々とありますが、今回はPythonでやっていきたいと思います。

Dockerfile! docker-compose.yml!

さて、今回はサクッとが目標なので、本題に入ります。まずはdocker-compose.ymlです。これだけあればほぼほぼ構築が完了するんですからDocker…コンテナの技術ってネ申ですね。

version: '3'

services:
  selenium-hub:
    image: selenium/hub
    container_name: 'selenium-hub'
    ports:
      - 4444:4444
    environment:
      - GRID_TIMEOUT=300
    restart: always

  chrome:
    image: selenium/node-chrome-debug
    container_name: 'chrome'
    links:
      - selenium-hub:hub
    ports:
      - 5900:5900
    environment:
      - NODE_MAX_INSTANCES=5
      - NODE_MAX_SESSION=5
      - no_proxy=localhost
      - HUB_ENV_no_proxy=localhost
      - HUB_PORT_4444_TCP_ADDR=selenium-hub
      - HUB_PORT_4444_TCP_PORT=4444
      - SCREEN_WIDTH=1440
      - SCREEN_HEIGHT=900
    volumes:
      - /dev/shm:/dev/shm
    restart: always

  firefox:
    image: selenium/node-firefox-debug
    container_name: 'firefox'
    links:
      - selenium-hub:hub
    ports:
      - 5901:5901
    environment:
      - NODE_MAX_INSTANCES=5
      - NODE_MAX_SESSION=5
      - no_proxy=localhost
      - HUB_ENV_no_proxy=localhost
      - HUB_PORT_4444_TCP_ADDR=selenium-hub
      - HUB_PORT_4444_TCP_PORT=4444
      - SCREEN_WIDTH=1440
      - SCREEN_HEIGHT=900
    volumes:
      - /dev/shm:/dev/shm
    restart: always

  python:
    build: './python-selenium'
    container_name: 'python'
    links:
      - selenium-hub:hub
    working_dir: '/root/script/'
    volumes:
      - ./script/:/root/script/
    environment:
      - 'TZ=Asia/Tokyo'
    tty: true
    restart: always

これをdocker-compose.ymlに記述します。これだけでSeleniumとChrome,Firefoxの作業環境が構築されます。端末自体にChromeやFirefoxをインストールする必要すらありません。ちなみに各コンテナは上から「SeleniumGrid」「Chrome」「Firefox」「Python実行環境」の機能を提供してくれます。そのため、Python以外の言語で動かしたければ、4つ目のコンテナを変えてもらうだけで動いてくれると思います。

あとはいい感じにPython環境を構築してもらうようにDockerfileを書いていきます。ここでの「いい感じ」とは使用するライブラリ類をインストールしてくれるというだけです。

FROM python:3

# seleniumをインストール
RUN apt-get update

COPY ./requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
selenium

はい。これだけです。ここでやっていることはPython側から呼び出すためにSeleniumのライブラリを入れているだけになります。インストールのためにrequirements.txtを用意します。もし他にもインストールしておきたいライブラリなどがあれば、このテキストファイルに1行に1つずつ書いていくだけでビルド時にインストールしてくれます。

ファイル構成

以上の準備が終わると以下のようになります。(sample.pyはこれから書きます!)

.
├── docker-compose.yml
├── python-selenium
│   ├── Dockerfile
│   └── requirements.txt
└── script
    └── sample.py

Python!

さて環境は整ったので、次はコードを書いていきます。今回はよくあるテストということで、おなじみGoogleさんで自動検索をしてみようと思います。…それだけではつまんないので、スクリーンショットも撮ってみます。

#!/usr/local/bin/python3
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def execSearch(browser: webdriver, img_name: str):
    """
    Googleで検索する
    :param browser: webdriver
    """
    # Googleにアクセス
    browser.get('https://www.google.co.jp/')
    WebDriverWait(browser, 15).until(EC.presence_of_all_elements_located)

    # キーワードの入力
    search_box = browser.find_element_by_name("q")
    search_box.send_keys('hello selenium')

    # 検索実行
    search_box.submit()
    WebDriverWait(browser, 15).until(EC.presence_of_all_elements_located)

    # スクリーンショット
    browser.save_screenshot(img_name + '.png')

if __name__ == '__main__':
    try:
        # UA を設定
        capabilities = webdriver.common.desired_capabilities.DesiredCapabilities.CHROME.copy()
        capabilities['javascriptEnabled'] = True

        options = webdriver.ChromeOptions()
        options.add_argument('--user-agent="Mozilla/5.0 (Linux; Android 4.0.3; SC-02C Build/IML74K) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31"')

        # HEADLESSブラウザに接続
        browser = webdriver.Remote(
            command_executor='http://selenium-hub:4444/wd/hub',
            desired_capabilities=DesiredCapabilities.CHROME,
            options=options
        )

        browser2 = webdriver.Remote(
            command_executor='http://selenium-hub:4444/wd/hub',
            desired_capabilities=DesiredCapabilities.FIREFOX
        )

        # FBで実行
        execSearch(browser,  img_name='chrome')
        execSearch(browser2, img_name='firefox')

        browser.close()
        browser2.close()

    finally:
        # 終了
        pass

はい。やっていることはコメントのとおりですが。これだけで、ChromeとFirefoxでGoogleにアクセス&「Hello Selenium」と検索、結果のところでスクリーンショットという処理を行います。

実行!

はい。では最後に実行します。

$ cd [docker-compose.ymlがあるディレクトリ]
$ docker-compose up -d --build
$ docker exec -it python python /root/script/sample.py

はい。これで実行もできて、scriptディレクトリの下には検索結果のスクリーンショットも出力されます。またVNCでブラウザコンテナのポートを指定すると動作している画面を表示することもできます。今回ならlocalhost:5900でOK。

終わりに!

はい。これでいろんな環境でSeleniumが動かせますね。今回作業した内容は下記のリポジトリでまとめておきますので参考までにどうぞ!

次はここで構築したSeleniumを使って何かやりたいと思います。それでは!

]]>
https://koneta.click/p/519/feed 0