Selenium IDE 活用事例 ~オンライン英会話の先生のレッスン状況を取得・通知する~

# この記事はなにか
オンライン英会話のNativeCampでお気に入りの先生のレッスン受けたいな…
更新ボタンを連打しちゃう…それが妻の悩みでした（コイン使えと言われれば関の山）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/84bf5ecf-9e01-9508-ec28-61700b5eb068.png)←何度も押してしまう魔の更新ボタン。
そこで、完全にプライベート用ですが、
レッスン状況を調べてメールで通知する一連の作業をSelenium IDE(Chrome拡張版)で自動化しました。

メールはこんな感じ。一目瞭然！妻歓喜！Yay!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/389d102e-760e-504a-38ab-1b3f9bcdd259.png)

以下の「準備するもの」があれば確認ができますので是非どうぞ！

# 準備するもの

- Chromeブラウザ
- Selenium IDEのChrome拡張(ver3.16.0)
- Gmailブラウザ版(要ログイン済)
- NativeCampアカウント（お気に入りの先生追加済み）

※7日間無料なので是非この機会に始めましょう笑

# フロー

イメージとしては`runProgram`に4つのプログラムを紐付けて実行させています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/374b608d-5179-6a8d-3367-cab6bc32dd52.png)
http://flat-icon-design.com/
https://www.irasutoya.com/

# ソース

<details><summary>ソースを表示するにはここをクリック</summary><div>

```.json
{
  "id": "e83365b2-7962-46a8-88cd-54b790bf05d9",
  "version": "2.0",
  "name": "semiautoNotification",
  "url": "https://nativecamp.net/",
  "tests": [{
    "id": "3b84e321-486b-4158-8aae-710e276173ae",
    "name": "getTeacherName",
    "commands": [{
      "id": "580e319e-1245-4958-8d31-a5381b2d4138",
      "comment": "",
      "command": "click",
      "target": "id=clearForm",
      "targets": [],
      "value": ""
    }, {
      "id": "218780d8-3818-4465-8294-3a5836a8932b",
      "comment": "",
      "command": "pause",
      "target": "5000",
      "targets": [],
      "value": ""
    }, {
      "id": "3b87c979-79ab-4e13-b4d3-65ba17c6bc2c",
      "comment": "",
      "command": "click",
      "target": "css=.dl_status li:nth-child(2) > .custom_radio",
      "targets": [],
      "value": ""
    }, {
      "id": "eb8c79cb-9ee8-49db-a94d-b8c565adba29",
      "comment": "",
      "command": "click",
      "target": "id=label_check_clear",
      "targets": [],
      "value": ""
    }, {
      "id": "8d5aaa13-c7c0-4138-b524-f6600f1bfa0d",
      "comment": "",
      "command": "click",
      "target": "id=btn_reserve_search",
      "targets": [],
      "value": ""
    }, {
      "id": "ca435085-79b6-43c2-aa3a-0ab0c3aff17f",
      "comment": "",
      "command": "waitForElementPresent",
      "target": "xpath=//*[@id=\"list\"]/li",
      "targets": [],
      "value": "30000"
    }, {
      "id": "710fdf66-468d-4685-a669-bab45bd465af",
      "comment": "",
      "command": "storeXpathCount",
      "target": "xpath=//*[@id=\"list\"]/li",
      "targets": [],
      "value": "theNumberOfTeachers"
    }, {
      "id": "c0d7b036-7024-4aa0-be50-c18ec20e6946",
      "comment": "",
      "command": "executeScript",
      "target": "return Number(${theNumberOfTeachers})-1",
      "targets": [],
      "value": "theNumberOfTeachers"
    }, {
      "id": "493bd6d5-4916-47a4-a34e-767d0fd398be",
      "comment": "",
      "command": "if",
      "target": "${theNumberOfTeachers}>=1",
      "targets": [],
      "value": ""
    }, {
      "id": "251f2f1b-4fa1-4228-9831-c4ebc6567a6c",
      "comment": "",
      "command": "store",
      "target": "なし",
      "targets": [],
      "value": "teacherNameLessonArray"
    }, {
      "id": "7e41f954-6f9f-44ca-97d3-c16a5d149c34",
      "comment": "",
      "command": "store",
      "target": "なし",
      "targets": [],
      "value": "teacherNameWaitArray"
    }, {
      "id": "85c6a900-2eb2-4436-af6c-5be063689dab",
      "comment": "",
      "command": "store",
      "target": "なし",
      "targets": [],
      "value": "teacherNameOnBreakArray"
    }, {
      "id": "66737317-4664-4dd6-a196-bcc78968fc67",
      "comment": "",
      "command": "executeScript",
      "target": "return 2",
      "targets": [],
      "value": "attributeNumber"
    }, {
      "id": "552f722c-b7a1-45a1-b8dd-355ded32cc98",
      "comment": "",
      "command": "times",
      "target": "${theNumberOfTeachers}",
      "targets": [],
      "value": ""
    }, {
      "id": "12f8367e-aae9-416c-b855-ff6c78d7d9d5",
      "comment": "",
      "command": "storeAttribute",
      "target": "xpath=//*[@id=\"list\"]/li[${attributeNumber}]/a/div[1]/div/div/p/span[1]@class",
      "targets": [],
      "value": "class"
    }, {
      "id": "ee66bb80-09b4-40cc-b3c2-bb9c7c6b8c5d",
      "comment": "",
      "command": "if",
      "target": "${class}==='lesson_status_circle lesson_status_circle--wait'",
      "targets": [],
      "value": ""
    }, {
      "id": "6df54bdb-2c95-4b91-a950-0ecc8d7599ec",
      "comment": "",
      "command": "storeText",
      "target": "xpath=//*[@id=\"list\"]/li[${attributeNumber}]/a/div[1]/div/div/p/span[2]",
      "targets": [],
      "value": "teacherName"
    }, {
      "id": "c099016b-a5b8-49fd-89d3-7054003361a9",
      "comment": "",
      "command": "echo",
      "target": "teacherName:${teacherName}",
      "targets": [],
      "value": ""
    }, {
      "id": "d40b8386-951e-4d98-94d9-1b0ef8828e82",
      "comment": "",
      "command": "if",
      "target": "${teacherNameWaitArray}==='なし'",
      "targets": [],
      "value": ""
    }, {
      "id": "e6ffe29c-0682-4955-8852-0e5fbaf01eba",
      "comment": "",
      "command": "store",
      "target": "${teacherName}",
      "targets": [],
      "value": "teacherNameWaitArray"
    }, {
      "id": "000cd31c-a2f8-4cca-a245-e574a1b6d607",
      "comment": "",
      "command": "else",
      "target": "",
      "targets": [],
      "value": ""
    }, {
      "id": "4fd16be0-6d47-4ded-bd2f-97008cf32bf4",
      "comment": "",
      "command": "store",
      "target": "${teacherNameWaitArray}, ${teacherName}",
      "targets": [],
      "value": "teacherNameWaitArray"
    }, {
      "id": "489d31aa-0dc2-4d7b-8dd9-e1f47bb9323d",
      "comment": "",
      "command": "end",
      "target": "",
      "targets": [],
      "value": ""
    }, {
      "id": "9f1c6bf0-0643-426c-b5fb-c4f9782b1c1a",
      "comment": "",
      "command": "elseIf",
      "target": "${class}=='lesson_status_circle lesson_status_circle--lesson'",
      "targets": [],
      "value": ""
    }, {
      "id": "b146faf7-5ff2-456c-ad5e-5dc95ba12380",
      "comment": "",
      "command": "storeText",
      "target": "xpath=//*[@id=\"list\"]/li[${attributeNumber}]/a/div[1]/div/div/p/span[2]",
      "targets": [],
      "value": "teacherName"
    }, {
      "id": "c7f83fe6-0b83-42bd-83c8-f35a3a5a5031",
      "comment": "",
      "command": "if",
      "target": "${teacherNameLessonArray}=='なし'",
      "targets": [],
      "value": ""
    }, {
      "id": "a52802b9-bb1d-4b76-b2c9-843373136712",
      "comment": "",
      "command": "store",
      "target": "${teacherName}",
      "targets": [],
      "value": "teacherNameLessonArray"
    }, {
      "id": "499a7292-1915-40d8-bd53-87c3af63d9f9",
      "comment": "",
      "command": "else",
      "target": "",
      "targets": [],
      "value": ""
    }, {
      "id": "0a96951b-37fb-460b-af02-67f615dafefb",
      "comment": "",
      "command": "store",
      "target": "${teacherNameLessonArray}、${teacherName}",
      "targets": [],
      "value": "teacherNameLessonArray"
    }, {
      "id": "f260a8ef-9f45-4111-b4e7-08197815b807",
      "comment": "",
      "command": "end",
      "target": "",
      "targets": [],
      "value": ""
    }, {
      "id": "83a39e55-3b20-4ab5-9100-e7fddcd9e377",
      "comment": "",
      "command": "elseIf",
      "target": "${class}=='lesson_status_circle lesson_status_circle--on-break'",
      "targets": [],
      "value": ""
    }, {
      "id": "a3d9b547-4e85-4b00-8531-3763850d143b",
      "comment": "",
      "command": "storeText",
      "target": "xpath=//*[@id=\"list\"]/li[${attributeNumber}]/a/div[1]/div/div/p/span[2]",
      "targets": [],
      "value": "teacherName"
    }, {
      "id": "47c84d0c-7a3b-42db-b1be-2291dbc4a768",
      "comment": "",
      "command": "if",
      "target": "${teacherNameLessonArray}=='なし'",
      "targets": [],
      "value": ""
    }, {
      "id": "6ee79b6e-8077-4e4f-9537-8fef03d43ea2",
      "comment": "",
      "command": "store",
      "target": "${teacherName}",
      "targets": [],
      "value": "teacherNameOnBreakArray"
    }, {
      "id": "b11b04a9-fe61-4cad-995f-a6e807570fdd",
      "comment": "",
      "command": "else",
      "target": "",
      "targets": [],
      "value": ""
    }, {
      "id": "883102e7-1f78-4b48-ae23-e5531910793a",
      "comment": "",
      "command": "store",
      "target": "${teacherNameOnBreakArray}、${teacherName}",
      "targets": [],
      "value": "teacherNameLessonArray"
    }, {
      "id": "831b1f5f-0be3-4c51-b4a7-16aab3424f02",
      "comment": "",
      "command": "end",
      "target": "",
      "targets": [],
      "value": ""
    }, {
      "id": "cab8ad2b-7ebb-4e63-a2c8-87f5704e4d4c",
      "comment": "",
      "command": "end",
      "target": "",
      "targets": [],
      "value": ""
    }, {
      "id": "b5c7cae6-a1a8-46ae-9b24-9673b6a18222",
      "comment": "",
      "command": "executeScript",
      "target": "return Number(${attributeNumber})+1",
      "targets": [],
      "value": "attributeNumber"
    }, {
      "id": "3992246b-46d4-474a-8e8c-7392f60aa3c3",
      "comment": "",
      "command": "end",
      "target": "",
      "targets": [],
      "value": ""
    }, {
      "id": "5da1ebeb-5ee8-42c0-bcad-ad37e9cfcefc",
      "comment": "",
      "command": "end",
      "target": "",
      "targets": [],
      "value": ""
    }]
  }, {
    "id": "f3fad674-44c1-43bd-b9a2-883589bac2cc",
    "name": "sendMail",
    "commands": [{
      "id": "bf04e28d-17bf-4c9f-bcd5-bbd65603482f",
      "comment": "",
      "command": "open",
      "target": "https://mail.google.com/mail/u/0/#inbox",
      "targets": [],
      "value": ""
    }, {
      "id": "f5ba3eee-b979-4a58-ba97-ac72f165e927",
      "comment": "",
      "command": "waitForElementPresent",
      "target": "css=.T-I-KE",
      "targets": [],
      "value": "30000"
    }, {
      "id": "b40dd5cc-81db-437e-80da-f684a4b23e06",
      "comment": "",
      "command": "click",
      "target": "css=.T-I-KE",
      "targets": [],
      "value": ""
    }, {
      "id": "d0dc5a51-2812-4217-afd8-099c5a79ac40",
      "comment": "",
      "command": "waitForElementPresent",
      "target": "id=:r3",
      "targets": [],
      "value": "30000"
    }, {
      "id": "a8787902-afeb-48be-9f05-37f9cd95ab01",
      "comment": "",
      "command": "click",
      "target": "id=:r3",
      "targets": [],
      "value": ""
    }, {
      "id": "4ee245d0-2741-4db5-90dc-62802633ddaa",
      "comment": "",
      "command": "type",
      "target": "id=:r3",
      "targets": [],
      "value": "${sendToEmailAdress}"
    }, {
      "id": "8e3ef500-bb87-4ac5-a094-671d469e28ad",
      "comment": "",
      "command": "click",
      "target": "id=:ql",
      "targets": [],
      "value": ""
    }, {
      "id": "155c48aa-abdf-4159-9d5d-97c40d7d949a",
      "comment": "",
      "command": "type",
      "target": "id=:ql",
      "targets": [],
      "value": "【Book Now!】${teacherNameWaitArray}先生が空いてます！"
    }, {
      "id": "4f344f9a-3708-4f7f-a6ee-7c0e3abde659",
      "comment": "",
      "command": "click",
      "target": "id=:rq",
      "targets": [],
      "value": ""
    }, {
      "id": "8df6ba56-27b4-4020-9a9e-127c4fff142b",
      "comment": "",
      "command": "editContent",
      "target": "id=:rq",
      "targets": [],
      "value": "<p>①空いている先生:${teacherNameWaitArray}</p><p>②準備中の先生:${teacherNameOnBreakArray}</p><p>③レッスン中の先生:${teacherNameLessonArray}</p>"
    }, {
      "id": "d4e2eef3-1ab8-4208-bf9d-56afef6bdbcf",
      "comment": "",
      "command": "click",
      "target": "id=:qb",
      "targets": [],
      "value": ""
    }]
  }, {
    "id": "027f3a48-d96f-4b5a-b87e-0e8628d4299a",
    "name": "tryLogin",
    "commands": [{
      "id": "ae18e8e5-dd41-4917-912e-5415ac5128e0",
      "comment": "",
      "command": "type",
      "target": "id=UserEmail",
      "targets": [],
      "value": "${userEmail}"
    }, {
      "id": "c1ef77fe-1136-4ec4-a48d-ff6c1c63e4d9",
      "comment": "",
      "command": "type",
      "target": "id=UserPassword",
      "targets": [],
      "value": "${userPassword}"
    }, {
      "id": "566f2db9-ab41-4226-80ba-9692200188c5",
      "comment": "",
      "command": "click",
      "target": "css=.m_t_20 .btn_style",
      "targets": [],
      "value": ""
    }, {
      "id": "1398e271-8e7c-4db7-9ca2-b9a4ae180631",
      "comment": "",
      "command": "storeTitle",
      "target": "",
      "targets": [],
      "value": "title"
    }, {
      "id": "c095be9a-7855-4d1d-a8c7-fad5d489dda9",
      "comment": "",
      "command": "if",
      "target": "${title}=='ログイン | ネイティブキャンプ'",
      "targets": [],
      "value": ""
    }, {
      "id": "efce9fd8-5c48-4c92-8323-4c778e365b90",
      "comment": "",
      "command": "echo",
      "target": "メールアドレスもしくはパスワードが違います",
      "targets": [],
      "value": ""
    }, {
      "id": "5732d532-7451-47f9-a664-dcabe0f4581a",
      "comment": "",
      "command": "debugger",
      "target": "",
      "targets": [],
      "value": ""
    }, {
      "id": "45c6c07d-5e62-421a-852c-a94759e0d5f4",
      "comment": "",
      "command": "end",
      "target": "",
      "targets": [],
      "value": ""
    }]
  }, {
    "id": "7f6ce389-af9e-436a-818a-18dd3c61747e",
    "name": "runProgram",
    "commands": [{
      "id": "f8633d81-fecd-45c7-87c8-df3eef3024b1",
      "comment": "",
      "command": "run",
      "target": "readInfo",
      "targets": [],
      "value": ""
    }, {
      "id": "a38940c0-9f71-4ff4-9a4e-56b6390fff92",
      "comment": "",
      "command": "open",
      "target": "/mypage",
      "targets": [],
      "value": ""
    }, {
      "id": "7d9d6db1-11c3-4e95-98fd-aaea0818d2d8",
      "comment": "",
      "command": "storeTitle",
      "target": "",
      "targets": [],
      "value": "title"
    }, {
      "id": "ec077fd1-19e2-44a7-8742-4594dc24a5e5",
      "comment": "",
      "command": "if",
      "target": "${title}=='ログイン | ネイティブキャンプ'",
      "targets": [],
      "value": ""
    }, {
      "id": "3943d105-f097-4a27-b1ed-b73d9456d44e",
      "comment": "",
      "command": "run",
      "target": "tryLogin",
      "targets": [],
      "value": ""
    }, {
      "id": "7716d847-f6d6-4c1d-bdcf-e73255558126",
      "comment": "",
      "command": "end",
      "target": "",
      "targets": [],
      "value": ""
    }, {
      "id": "336954a8-7b45-4306-8027-c6db7f65dffa",
      "comment": "",
      "command": "run",
      "target": "getTeacherName",
      "targets": [],
      "value": ""
    }, {
      "id": "e8283736-01b4-49a0-9bb3-b47e5ae4f19f",
      "comment": "",
      "command": "if",
      "target": "${teacherNameWaitArray}!='なし' || ${teacherNameWaitArray}!='' ",
      "targets": [],
      "value": ""
    }, {
      "id": "7ccd1d5c-62cb-43c4-ad40-ead6c3f5411d",
      "comment": "",
      "command": "run",
      "target": "sendMail",
      "targets": [],
      "value": ""
    }, {
      "id": "21cfb2f9-0a33-413d-8ca9-f5b3b41e6b1e",
      "comment": "",
      "command": "end",
      "target": "",
      "targets": [],
      "value": ""
    }]
  }, {
    "id": "f977dfd5-15fc-425f-bf35-ef3dc4f8f760",
    "name": "readInfo",
    "commands": [{
      "id": "3c433589-5999-4d5d-ba4f-461f3dc574ef",
      "comment": "",
      "command": "store",
      "target": "ログイン用のメールアドレス@sample.com",
      "targets": [],
      "value": "userEmail"
    }, {
      "id": "38c0790a-8f97-4cf6-b1ba-625df07a68f9",
      "comment": "",
      "command": "store",
      "target": "ログイン用のパスワード",
      "targets": [],
      "value": "userPassword"
    }, {
      "id": "1a8497c4-ce1c-4306-a5b4-2b42473fcb02",
      "comment": "",
      "command": "store",
      "target": "送付先のメールアドレス@sample.com",
      "targets": [],
      "value": "sendToEmailAdress"
    }]
  }],
  "suites": [],
  "urls": ["https://nativecamp.net/"],
  "plugins": []
}
```

</div></details>

形式はjsonのようですが、保存する際は`test.side`のように拡張子は`.side`で保存します。
（[拡張子sideは「SeleniumIDE」から来ている？](https://aoma23.hatenablog.jp/entry/side_extension)）

保存してSeleniumIDEで開くと以下のような感じになっているか思います。
実行する場合は`runProgram`を選択して「▷」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/a68f0666-ad2f-2f21-3e0a-3de506e05af2.png)

# 詰まった&工夫したポイント

基本的には下記のコマンドリファレンスを主に参考にしました。ありがとうございます。
[Selenium IDE コマンドリファレンス (2019/09版 : Selenium IDE v3.12.0 [全96コマンドを徹底解説])｜Qiita](https://qiita.com/oh_rusty_nail/items/77782973b4152992017b#execute-async-script)

## ①変数を数値型にするにはexecute script！
変数はそのままだと文字列として登録されたため、
コマンドを`execute script`、ターゲットを`return Number(${hogehoge})`のようにしました。
例えば、下記は先生が一覧で見れるページに先生の枠が何個あるか調べるもの。
それを`theNumberOfTeachers`に入れています。[他のやり方もあるようです](https://qiita.com/oh_rusty_nail/items/b8ba525d31ea7c522856#javascript%E5%BC%8F%E3%82%92%E4%BD%BF%E3%81%86)。

## ②変数は各テストで引き継げる
最初は変数が引き継げないと思ってまとめて作っていたのですが、見づらくなってしまったので
機能ごとに小分けにしてそれを一つのプログラムを実行したときに`run`で順番に実行する形に。
待機中の先生がいない場合はメールを送らない、ログインしていない場合は実施するなどの判定はここで実施。
今回省略した○分ごとに繰り返しとする場合もここで指定すると楽です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/32d4e53c-66ee-fd7a-7bc7-18df4ca1ebfa.png)

## ③ pauseは使っちゃだめ？
プロジェクトでpauseを初めて指定すると、アラートが表示されました。
画面変遷がなく、待機したいところでうまく行かなかったためやむなく使用しましたが一応動いています。
楽なので使いたくなりますが、`wait~`が用意されているので可能な限りそちらを使用しました。

## ④ Xpathで要素の取得
動きを記録することでも取得できますが、時々GoogleのDeveloperToolで要素を選択し、`Copy → Copy XPath`しました。
ターゲットの右側にある`Select target in page`でも同じことができるかと。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224314/03042e70-d590-9879-24d3-185b82295411.png)

## ⑤取得したい要素で順番が違うものを取得したい
`xpath=//*[@id="list"]/li[1]`のあとに`xpath=//*[@id="list"]/li[2]`を取得したい時、
`xpath=//*[@id="list"]/li[${attributeNumber}]`という感じで中に変数を入れて繰り返し処理で対応しました。

# 所感
記録からスタートできてそこから編集できるので敷居が低いですね。
改めて、Selenium IDEはテストツールとしてだけではなく業務効率化にも有益なツールだと思いました。

# 参考
[Selenium IDE コマンドリファレンス (2019/09版 : Selenium IDE v3.12.0 [全96コマンドを徹底解説])｜Qiita](https://qiita.com/oh_rusty_nail/items/77782973b4152992017b#execute-async-script)
[全国のSeleniumer必読｜Qiita](https://qiita.com/oh_rusty_nail/items/b8ba525d31ea7c522856)