Seleniumのセットアップから基本的な使用法のまとめ【Javascript, Node.js, chrome】


Javascriptを用いてSeleniumを動かしたいという方向けに記事をまとめました。
Node.jsにおけるSeleniumのセットアップからJavascripを用いた基本的な使い方をまとめています。

Seleniumがどういったツールなのかなどの説明はこの記事の対象ではありません。

ご参考になれば幸いです。

※私の理解でまとめていますので、間違っている箇所の修正や情報の追加などございましたらコメントください。


# Seleniumセットアップ(Node.js, chrome)

環境:windows10, Node.js
使用言語: Javascript
ブラウザ: chrome

※今回はブラウザはChromeのみを対象としています。

## 1.Selenium libraryのインストール
seleniumをインストールします。
`npm install selenium-webdriver`

## 2.chromedriverのインストール

Chromeブラウザを操作するにはchromeのweb driverが必要になります。

選択肢1 :chromedriverをダウンロードし、PATHを設定する。
[やり方](https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/)
[chrome driverダウンロード](https://chromedriver.storage.googleapis.com/index.html)

選択肢2:chromedriverパッケージをインストールする。
[https://www.npmjs.com/package/chromedriver/v/97.0.0](https://www.npmjs.com/package/chromedriver/v/97.0.0)
OSに合わせてインストールしてくれる。(はず)

**note:** 
両方ともChromeのバージョンアップに合わせてアップグレードが必要になります。

## 3.seleniumでブラウザを立ち上げる

Seleniumではブラウザのインスタンスを作成し、そのインスタンスを操作するという使い方です。

```jsx
require('chromedriver');// 選択肢2の場合必要
const webdriver = require('selenium-webdriver');
const { Builder } = webdriver;
 
// ブラウザのインスタンスを作成。これを用いてブラウザを操作する。
const driver = new Builder().forBrowser('chrome').build();
```

### chrome optionについて
chromeブラウザを立ち上げる際のoptionがいくつか準備されている。

selenium chrome option説明
[selenium-webdriver/chrome.Options](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/chrome_exports_Options.html)

option一覧
[List of Chromium Command Line Switches « Peter Beverloo](https://peter.sh/experiments/chromium-command-line-switches/)

**例:** optionの受け渡しは以下の方法で可能。

```jsx
const driver = await new Builder()
    .forBrowser('chrome')
    .setChromeOptions(new chrome.Options()
      .excludeSwitches('enable-logging')
      .addArguments('--disable-gpu')
      .addArguments('--disable-dev-shm-usage')
	 )
  .build();
```



# Selenium使い方(Javascript)

基本的に以下のドキュメントを見るとJavascriptでできることがのっている。
:star: [Selenium WebDriver](https://www.selenium.dev/selenium/docs/api/javascript/index.html)

以下まとめてあって見やすい
[Nodejsを使ってSeleniumでChromeを動かす - Qiita](https://qiita.com/tonio0720/items/70c13ad304154d95e4bc)

## ブラウザの操作

指定のページに移動
`await driver.get(URL);`

ウィンドウハンドラの取得
`await driver.getWindowHandle();`

ウィンドウの移動
`await driver.switchTo().window(ウィンドウハンドラ);`

ウィンドウを閉じる
`await driver.close();`

ブラウザの終了
`await driver.quit();`

**note:**
ブラウザセッションが終了したら、closeではなくquitを呼び出す必要があります。ウィンドウを閉じたいだけの時はcloseを使用し、ブラウザプロセスを終了させたいときにquitを使用します。

## 要素の取得

locatorに当てはまる要素を一つ取得
`driver(or webElement).findElement(locator);`

locatorに当てはまる要素をすべて取得
`driver(or webElement).findElements(locator);`

locatorとは: 画面上の要素を指定するための情報。
[selenium-webdriver.By](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_By.html)
`By.(function)`

- `By.className(className)`
- `By.id(className)`
- `By.css(selector)`
- `By.xpath(className)`

よく使うものを記しました。その他は上記リンクを見てみてください。

`By.css(selector)`はcssで要素を指定するときと同じ感覚で使用できるので、基本的にこちらで何でも指定できる。
タグ内のテキストで判断したい場合は`By.xpath(className)`が活用できる。

**例:**

```jsx
const content = driver.findElement(By.className('content'));

// contentの中のclass名titleのものが取得できる
const titleText = content.findElement(By.className('title'));

// 上の2行をまとめて以下のように指定することもできる。
const titleText = driver.findElement(By.css('.content .title'));
```

**note:**
`const { By } = webdriver;`を忘れないように

## 要素を待つ

seleniumには条件を指定して動作を待機させることができる。

waitを使う
`await driver.wait(condition, timeout, message)`

conditionがtrueになるまで待機する。timeout時間を過ぎるとエラーになる。conditionはSelenium側で用意されているものもある。関数をconditionとして使うこともできる。

用意されている条件: [Module selenium-webdriver/lib/until](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/lib/until.html)
よく使う条件をいくつか記します。その他は上記リンクを見てみてください。

- `until.elementLocated(locator)`
- `until.elementIsEnabled(element)`
- `until.elementIsVisible(element)`
- `until.elementTextIs(text)`
- `until.titles(titles)`
- `until.alertIsPresent()`

 **例:**

```jsx
// 用意されている条件を使った場合
// class名がcontentの要素が出現するまで30秒間まで待機する。
await driver.wait(until.elementLocated(By.className('content')), 30000);

// 関数を条件とする場合
// ウィンドウが2つになるまで30秒間待機する。
await driver.wait(
  async () => (await clientDriver.getAllWindowHandles()).length === 2,	
  30000
);
```

**note1:** 
要素の出現を待つ場合に使用する`until.elementLocated(locator)`の引数はLocator(By.)であり、
要素が見えるのを待つ場合に使用する`until.elementIsVisible(element)`の引数はelement(要素自体)である。

**note2:**
`const { until } = webdriver;`を忘れないように

## ログを取得する

ブラウザで出現するログを取得するにはchromeブラウザインスタンスを作成する際にchromeのoptionの設定が必要になる。

### 手順

1.取得するために使うライブラリをインポート
`const { Preferences, Type, Level } = require('selenium-webdriver/lib/logging');`

2.ログの設定をする。
```jsx
const logPrefs = new Preferences();

// 取得するログの種類とログレベルの設定
logPrefs.setLevel(Type.PERFORMANCE, Level.ALL);
```

3.chrome option にセットする

```jsx
const driver = new Builder()
    .forBrowser('chrome')
    .setChromeOptions(new chrome.Options()
      .setLoggingPrefs(logPrefs)
	 )
  .build();
```

4.ログを取得
`const networkLogs = await driver.manage().logs().get(Type.PERFORMANCE);`

上記のコードでは全てのネットワークログが取得されるので、特定のログを取得したい場合は、取得したログ情報からほしい情報だけを選別しフィルタするなどの必要がある。

開発者ツールのネットワークタブのデータを取得したい場合は
"method":"Network.requestWillBeSent”
"method":"Network.responseReceived”
あたりで取得できる。

consoleのログを取得したい場合は、手順2と4で`Type.PERFORMANCE`の部分を`Type.BROWSER`に変更する。
Type.PERFORMANCE: パフォーマンスログを取得(ネットワークログ)
Type.BROWSER:consoleのログを取得