【Python】Selenium4の新機能まとめ

## はじめに

この記事は、Selenium4へのアップデートで新しく追加された機能について、Selenium公式サイトの[アナウンス](https://www.selenium.dev/blog/2021/announcing-selenium-4/)や[ドキュメント](https://www.selenium.dev/documentation/webdriver/)からまとめたものです。抜け漏れに気付いたら随時追加します。

なお、**Selenium WebDriver**に関する記述であり、Selenium IDEやSelenium Gridに関しては言及していません。

## 使用するツール

- [Selenium](https://www.selenium.dev/) 4.0.0
- [ChromeDriver](https://chromedriver.chromium.org/downloads) 94
- Python 3.7.4
- サンプルサイト：[HOTEL PLANISPHERE - テスト自動化練習サイト](https://hotel.testplanisphere.dev/ja/)

## Selenium4の導入方法

・Seleniumのバージョンを指定してインストールする

```sh
pip install selenium==4.0.0
```

・Selenium3からアップデートする

```sh
pip install -U selenium
```

## Selenium4の新機能

### タブとウィンドウの新規作成

新しいドライバオブジェクトを作成せずに、同じセッションで新しいタブやウィンドウを作成し、フォーカスすることができます。例えばURLを新しいタブで開きたい場合、Selenium3ではハンドルの切り替え（`switch_to.window()`）を行っていましたが、これが不要になります。
※参考：[Browser manipulation - Create new window (or) new tab and switch | Selenium](https://www.selenium.dev/documentation/webdriver/browser_manipulation/#create-new-window-or-new-tab-and-switch)

URLを新しいタブで開く方法をSelenim3とSelenium4で比べてみます。

**Selenium3の場合**

```python:create_new_tab_selenium3
from selenium import webdriver

driver = webdriver.Chrome()
driver.get("URLその１")

# 新しいタブを作成
driver.execute_script("window.open()")

# 新しいタブに切り替え
driver.switch_to.window(driver.window_handles[1]) 

driver.get("URLその２")
```

**Selenium4の場合**

```python:create_new_tab_selenium4
from selenium import webdriver

driver = webdriver.Chrome()
driver.get("URLその１")

# 新しいタブを作成し、フォーカスする
driver.switch_to.new_window("tab")
driver.get("URLその２")
```

新しいウィンドウで開きたい場合は、`new_window("window")`とするだけでOKです。

### ウィンドウの最小化

文字通り、カレントブラウザが表示されているウィンドウを最小化します。
※参考：[Browser manipulation - Minimize window | Selenium](https://www.selenium.dev/documentation/webdriver/browser_manipulation/#minimize-window)

```python:minimize
driver.minimize_window()
```

### 相対ロケータ / Relative Locator

指定した要素の近くにある要素を見つけるための機能です。
※参考：[Locating elements - Relative Locator | Selenium](https://www.selenium.dev/documentation/webdriver/locating_elements/#relative-locators)

利用可能な相対ロケータは以下の通り。

- `above`: 指定した要素より**上**に表示される要素
- `below`: 指定した要素より**下**に表示される要素
- `toLeftOf`: 指定した要素より**左**に表示される要素
- `toRightOf`: 指定した要素より**右**に表示される要素
- `near`: 指定した要素から**最大 50px**離れた要素

実際に、サンプルサイト「[HOTEL PLANISPHERE](https://hotel.testplanisphere.dev/ja/plans.html)」の宿泊プラン一覧を対象に使ってみます。

ここでは、下図プラン一覧中央の「出張ビジネスプラン」の見出しを基準要素として、それぞれの相対ロケータに該当する要素を取得します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548627/48392efb-0902-318d-ba8b-c589e4cf1c58.png)

**使用例①：条件１つ**

```python:relative_locator
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.relative_locator import locate_with

driver = webdriver.Chrome()
driver.get("https://hotel.testplanisphere.dev/ja/plans.html")

# 基準とする要素を取得
base = driver.find_element(By.CSS_SELECTOR, "#plan-list > div:nth-child(2) > div > div > h5")

# 上に表示される要素のうち、CLASS名が`card-title`のもの
targets = driver.find_elements(locate_with(By.CLASS_NAME, "card-title").above(base))
print("above:", [x.text for x in targets])

# 左に表示される要素のうち、CLASS名が`card-title`のもの
targets = driver.find_elements(locate_with(By.CLASS_NAME, "card-title").to_left_of(base))
print("left:", [x.text for x in targets])

# 最大 50px 離れた要素
targets = driver.find_elements(locate_with(By.CLASS_NAME, "card-title").near(base))
print("near:", [x.text for x in targets])
```

実行結果は以下の通り。 **基準となる要素に近い順**でリストアップされます。

```text:実行結果
above: ['お得な特典付きプラン']
left: ['素泊まり', '貸し切り露天風呂プラン']
near: ['素泊まり', 'エステ・マッサージプラン']
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548627/03f1f18d-0e34-031c-3828-a133c568ee60.png)


**使用例②：複数条件**

複数条件を組み合わせて要素を絞り込むこともできます。

```python:multi_relative_locator
targets= driver.find_elements(locate_with(By.CLASS_NAME, "card-title").below(base_plan).to_right_of(base))
print([x.text for x in targets])
```

実行結果は以下の通り。 「出張ビジネスプラン」よりも**右下**に表示されているプランが取得されました。

```text:実行結果
['テーマパーク優待プラン']
```

**※相対ロケータの注意点**

相対ロケータは、表示されている要素の位置を参照しています。

つまり、ウィンドウサイズや倍率によってUIの配置が変わってしまう場合、相対ロケータで取得される要素も変わってしまう可能性が高いので要注意です。

▼ 例：ウィンドウ幅によって配置が異なる

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548627/66e26716-164f-e99b-22c9-3a29ffbaada6.png" width="40%">　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548627/f365e2f7-0cd3-123b-cd7b-1dc07c8f28a8.png" width="40%">

## 参考
- [WebDriver | Selenium](https://www.selenium.dev/documentation/webdriver/)
- [Announcing Selenium 4 | Selenium](https://www.selenium.dev/blog/2021/announcing-selenium-4/)