Python + Selenium で Chrome の自動操作を一通り

# はじめに

Python + Selenium + Chrome で、要素の取得、クリックなどの UI系の操作、待機、ページ全体のスクリーンショットなど、一通り試してみます。

PhantomJS はもう更新されないということなので、ブラウザは Chrome にします。

この記事には、Selenium の API に関する情報と Chrome に特化した情報がありますが、前者の Selenium の使い方に関する情報は Firefox など別のブラウザでも使えます。

## 注意事項

ウェブの自動テストやスクレイピングで使われる技術です。特にスクレイピングでは、著作権の問題や、サーバー側の負荷、各種規約（会員としてログインする場合の会員規約等）やマナーなどを考慮する必要があります。
たとえば、Twitter など利用規約で明示的にスクレイピングが禁止されていることや、robot.txt などでクローリングが禁止されていることもあります。

参考: 

- https://qiita.com/nezuq/items/c5e827e1827e7cb29011
- https://vaaaaaanquish.hatenablog.com/entry/2017/12/01/064227

## オフィシャル + alpha 情報

- ChromeDriver: http://chromedriver.chromium.org/getting-started
- Selenium の API (Official): https://www.seleniumhq.org/docs/03_webdriver.jsp
    - ページの一番上プログラミング言語を選択できるので、Python を選んでおくと便利
- 非オフィシャルだと Python + Selenium なら https://selenium-python.readthedocs.io/ やその[日本語訳](https://kurozumi.github.io/selenium-python/)

## 環境

Selenium と ブラウザ（今回は Chrome）の間に WebDriver（今回は ChromeDriver）が必要になります。OS の依存性は低そうですが、Windows で試すことにします。

- Windows 10 Pro (64bit)
- Chrome 69.0.3497.100
- ChromeDriver 2.42.591088
- Python 3.5.4 （3.6以降でも変わらないと思われます）
- selenium 3.14.1

Python は Anaconda でインストールし、Python 3.5の仮想環境にて selenium を pip しました。

```
pip install selenium
```


Chrome は最近のものであれば `--headless` を付けて実行するとヘッドレスモードが使えるようです。

# ChromeDriver のインストール

## バイナリを直接ダウンロードする場合

OS にあった ChromeDriver を http://chromedriver.chromium.org/downloads からダウンロードし、実行ファイルを PATHの通った場所にコピーするか、環境設定で PATH を通します。

（確認）コマンドラインから `chromedriver` を実行すれば `Starting ChromeDriver 2.42.591088...` のようなメッセージが表示されます。実際にはコマンドラインから実行するわけではないですが、これで PATH が通っていることを確認できます。

環境変数の PATH に追加せず、プログラム中でパス指定することも可能です。

## pip でインストールする場合

ChromeDriver を Python でのみ利用するなら、`pip install chromedriver-binary` でインストールすることもできます。
環境変数等でパスを通す必要はなく、プログラム中で `import chromedriver_binary` のようにインポートすればパスが通ります。
バイナリのフルパスを表示してくれる `chromedriver-path` というコマンドもインストールされるので、これを利用してコマンドラインで PATH に加えておくこともできます。

参考: https://pypi.org/project/chromedriver-binary/

以降の例では、事前にパスが通っているものとします。

## 非headlessモードでテスト

[ChromeDriver オフィシャルサイトの Getting Started](http://chromedriver.chromium.org/getting-started) にあるサンプルコードをほぼそのまま実行してみます。

1. Chrome が立ち上がり、5秒後に ChromeDriver という文字列でGoogle検索が行われます。（Chromeのウィンドウには「Chrome は自動テスト ソフトウェアによって制御されています。」と表示されます。）
2. さらに5秒経つと自動で閉じます。

```python
import time
from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.google.com/')
time.sleep(5)
search_box = driver.find_element_by_name("q")
search_box.send_keys('ChromeDriver')
search_box.submit()
time.sleep(5)
driver.quit()
```



## プログラムでのパス指定

環境設定で ChromeDriver に PATHを通していない場合、プログラム中で指定できます。
ChromeDriverを `c:\opt\chromedriver_win32` に展開した場合は、以下のように実行ファイルのパスを指定します。

```python
driver = webdriver.Chrome(executable_path='c:\\opt\\chromedriver_win32\\chromedriver.exe')
````

## headless モードのテスト

`driver = webdriver.Chrome()` のあたりを以下のように変更します。動作しているかどうかよくわからないので、途中でウェブページのタイトルを表示しつつ、スクリーンショットをとってみます。

```python
from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)  # 今は chrome_options= ではなく options=

driver.get('https://www.google.com/')
print(driver.title)

search_box = driver.find_element_by_name("q")
search_box.send_keys('ChromeDriver')
search_box.submit()
print(driver.title)

driver.save_screenshot('search_results.png')
driver.quit()
```

ページによっては以下も必要になるようです。

```python
options.add_argument('--disable-gpu')
```

# 要素を取得する

ページ内の要素は、ID、クラス名、タグ名、リンクのinnerText、CSSセレクタ、XPathで取得出来ます。

参考: 

- https://selenium-python.readthedocs.io/locating-elements.html
- https://www.seleniumhq.org/docs/03_webdriver.jsp#locating-ui-elements-webelements

以下では Google の検索ページを例にしますが、DOMの構造は記事作成時のものを仮定します。

## By CSS

まずは CSSセレクタを使ってみます。
Google 検索の結果は `div class="g"` で並びますが、その孫要素の `h3` に各ページのタイトルがあるようなので、[子孫結合子](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Selectors)を使って表示してみます。

CSSセレクタの指定方法: https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Selectors

```python
for g_h3 in driver.find_elements_by_css_selector(".g h3"):
    print(g_h3.text)
    # print(g_h3.text.encode('cp932', 'ignore').decode('cp932'))  # Windowsのコマンドプロンプトを使う場合
```
`.text` を使うと innerText 値を取り出すことができます。

Windows のコマンドプロンプトだと print の標準出力時に自動でcp932へ変換されるが、変換できない文字があると UnicodeEncodeError が出てエラーになります。これは、コメントアウトされている行にあるように、いったん ignore オプション付きで byte に変換し、再び string に戻すことで回避できます。（ただし、以降の例ではこの手順は省略します。）

参考: https://qiita.com/butada/items/33db39ced989c2ebf644 

## By ID

例として Google 検索のヒット件数を表示してみます。IDで引っかけられるのであれば、By ID を使うのが[最も効率がよい](https://www.seleniumhq.org/docs/03_webdriver.jsp#locating-ui-elements-webelements)そうです。

```python
from selenium.webdriver.common.by import By
# ... (省略) ...
# 以下の6つの指定方法ではどれも同じものが返ります
stats = driver.find_element(by=By.ID, value="resultStats").text
stats = driver.find_element_by_id("resultStats").text
# elements のように複数形にするとリストを取得できます
stats = driver.find_elements(by=By.ID, value="resultStats")[0].text
stats = driver.find_elements_by_id("resultStats")[0].text
# CSSセレクタも使えますが By ID の方が効率がよいはず
stats = driver.find_element_by_css_selector("#resultStats").text
stats = driver.find_elements_by_css_selector("#resultStats")[0].text
print(stats)

```

`find_element(by=...` を使うには1行目の import が必要です。また、引数がこの順序なら `by=` や `value=` は省略できます。

- `find_element_...` のように**単数形にするとひとつ目にマッチした要素を取得**します。見つからなければ**例外** `NoSuchElementException` が投げられます。
- `find_elements_...` のように**複数形にするとリストを取得**できます。見つからなければ**空のリスト**が返ります。したがって上の例だと、対応する要素がなければ `IndexError` が起こります。

ページにつき ID は一意に複数回でないように書くことになっていますが、実際には同じ ID が複数回使われているページもあるので `find_elements_by_id` の出番もあるのですかね。


## By Class Name や By Tag Name

Google の検索結果は `div class="g"` の中に `div class="r"` と `div class="s"` があり、それぞれ、リンク `a href` とタイトル `h3`、サマリー `span class="st"` を含みます。これを、クラス名とタグ名で抽出してみます。

```python
for i, g in enumerate(driver.find_elements_by_class_name("g")):
    print("------ " + str(i+1) + " ------")
    r = g.find_element_by_class_name("r")
    print(r.find_element_by_tag_name("h3").text)  # タイトル
    print("\t" + r.find_element_by_tag_name("a").get_attribute("href"))  # URL
    s = g.find_element_by_class_name("s")
    print("\t" + s.find_element_by_class_name("st").text)  # サマリー
```
これは `find_element` のみで以下のように書くこともできます。

```python
for i, g in enumerate(driver.find_elements(By.CLASS_NAME, "g")):
    print("------ " + str(i+1) + " ------")
    r = g.find_element(By.CLASS_NAME, "r")
    print(r.find_element(By.TAG_NAME, "h3").text)
    print("\t" + r.find_element(By.TAG_NAME, "a").get_attribute("href"))
    s = g.find_element(By.CLASS_NAME, "s")
    print("\t" + s.find_element(By.CLASS_NAME, "st").text)
```

## By Name

`name` 属性を使って要素を探します。Googleの検索フィールドの `input` は `name="q"` という属性を持つので以下のように検索フィールドを見つけることができます。（これははじめの例で出てきました。）

```python
driver.find_element_by_name("q")
# 以下でも同様
driver.find_element(By.NAME, "q")
```

## By Link Text や By Partial Link Text

リンク要素を、`<a href=...>`と`</a>` の間のテキスト (innerText) を使って見つけます。

```python
# 完全マッチ
for a in driver.find_elements_by_link_text("このページを訳す"):
    print(a.get_attribute("href"))

# 部分マッチ
for a in driver.find_elements_by_partial_link_text("訳す"):
    print(a.get_attribute("href"))
```

`find_elements` を使うなら `By.LINK_TEXT`、`By.PARTIAL_LINK_TEXT` と組み合わせます。

## By XPath

XPath も使えるので、たとえば上の例は以下のように書くことができます。

```python
for a in driver.find_elements_by_xpath("//a[text()='このページを訳す']"):
    print(a.get_attribute("href"))

for a in driver.find_elements_by_xpath("//a[contains(text(), '訳す')]"):
    print(a.get_attribute("href"))
```

兄弟（姉妹）要素なども XPath ならば簡単に取得できます。以下では弟（妹）要素を取得してみます。
まず、`element = driver.find_element...` のように要素を取得しておいたとします。この要素 `element` と同階層の後方にあり、かつ `class` 属性が `hogehoge` を含む `div` 要素は次のように探します。

```python
element.find_element_by_xpath("./following-sibling::div[contains(@class, 'hogehoge')]")
```

はじめの `./` は無くてもよいです。
`following-sibling` を `preceding-sibling` にすれば兄（姉）要素になります。
関係ないですが、英語の sibling （性別を指定しない兄弟）に一対一対応する日本語が欲しいですね。

参考:

- https://ja.wikipedia.org/wiki/XML_Path_Language
- https://qiita.com/rllllho/items/cb1187cec0fb17fc650a
- https://webbibouroku.com/Blog/Article/xpath

## 要素の状態を調べる

以下のメソッドで、見つけた要素の状態を調べることができます。

- `element.is_displayed()`
- `element.is_enabled()`
- `element.is_selected()`


# ユーザー入力（クリックや選択など）

## クリックする

取得した要素に対して `.click()` でクリックできます。

## サブミットする

- 単純には `driver.find_element_by_id("submit").click()` のような感じサブミットボタンなどをクリックすればよいです。
- `submit()` というメソッドも用意されています。要素 `element` がフォーム内にあるならば、`element.submit()` でフォームをサブミットできます。

## 文字列を入力する

テキストフィールドやテキストエリアに文字列を入力するには `send_keys()` を使います。
`Keys` を使うには `from selenium.webdriver.common.keys import Keys` しておきます。　


- `element.send_keys("文字列")`
- `element.send_keys(Keys.RETURN)` などで特殊キー入力
- `element.send_keys("文字列", Keys.RETURN)`（続けて書く場合）
    - 例: `driver.find_element_by_name("q").send_keys("python", Keys.RETURN)`
- `element.clear()` でクリア（念のため `send_keys` の前に入れておくなど）

## select 要素内の option を選択する

- `select = Select(driver.find_element...)` select 要素を見つけ
- 選択
    - `select.select_by_index(index)`
    - `select.select_by_visible_text("text")`
    - `select.select_by_value(value)`
- 選択解除
    - `select.deselect_by_index(index)`
    - `select.deselect_by_visible_text("text")`
    - `select.deselect_by_value(value)`
    - `select.deselect_all()` ですべて選択解除
- その他
    - `select.all_selected_options` 選択されているオプション要素のリスト
    - `select.options` 選択できるオプション要素のリスト
        - 例: `option_texts = [opt.text for opt in select.options]`

[select 要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/select)に特化しているので、Google フォームなど、select 要素を使わないような（背後でスクリプトが動くような）フォームの入力には使えません。最近のフォームに対しては、要素の状態チェックや，条件指定による待機、クリックやホバー（マウスオーバー）などを組み合わせて入力していくことになりそうです。


# ActionChains を使う

## ホバー（マウスオーバー）する

スクリプトが裏で動いているページではよく使うかもしれません。

```python
from selenium.webdriver.common.action_chains import ActionChains
# ...省略...
actions = ActionChains(driver)
actions.move_to_element(
    driver.find_element_by_class_name("name")
).perform()  # hoverする
```

## ドラッグ・アンド・ドロップする

まだ試していないですが Drag & Drop もできるようです。

```python
src = driver.find_element_by_name("source")
tgt = driver.find_element_by_name("target")
actions.drag_and_drop(src, tgt).perform()
```

# ページやウィンドウ間などの移動

## ページ間の移動

- `driver.get(<URL>)`
- `driver.forward()`
- `driver.back()`

## ウィンドウやフレームへ移動

未テストですが、[APIのページ](https://selenium-python.readthedocs.io/navigating.html#moving-between-windows-and-frames)にあるものを並べておきます。

- `driver.switch_to.window("windowName")`
    - `<a href=... target="windowName">リンク</a>` で開いたウィンドウへ移動する場合
- `driver.switch_to.frame("frameName")`
    - `driver.switch_to_frame("frameName.0.child")`
    - `driver.switch_to_default_content()`

以下のようにすると複数ウィンドウを順に移動できるようです。

```python
for handle in driver.window_handles:
    driver.switch_to.window(handle)
```

## ポップアップダイアログに応える

ポップアップしてきたダイアログボックスへもアクセスできるようです。（未テスト）

- `alert = driver.switch_to_alert()`


# 待つ

基本的には読み込まれるまで（onloadイベントまで）待ってくれます。ですが、Ajax ベースでいろいろ書かれていると、要素の追加タイミングがいろいろなので対応できません。その場合は要素の存在や状態を調べるような待ち方が必要です。

## 条件を指定（明示的待機）

`expected_conditions` を使います。（インポートしておきます。）

```python
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# ...省略...
# タイムアウト時間を固定するならまとめておく
wait = WebDriverWait(driver, 10)  # Timeout 10秒（最大待ち時間）

# 例1: すべて読み込まれて"Google"を含むタイトルが表示されるまで待つ
driver.get('https://www.google.com')
wait.until(EC.title_contains("Google"))

# 例2: 何かをクリックしてから、innerTextに"ほげ"を持ちかつclass属性が hoge である要素が現れるのを待つ。
element = find_element...
element.click()
wait.until(
    EC.text_to_be_present_in_element((By.CLASS_NAME, "hoge"), "ほげ")
)

# 例3: class属性が fuga である要素が visible になるのを待ってからクリックする。
xpath = "//a[@class='fuga']"
a = wait.until(
    EC.visibility_of_element_located((By.XPATH, xpath))
)
a.click()
```

条件を指定するためのクラスはかなりいろいろあります。その一部を紹介します。

ロケーターは `(By.ID, "id")` のようなタプルで指定するため、`from selenium.webdriver.common.by import By` しておく必要があります。
タプルの第一要素は、[「要素を取得する」](https://qiita.com/memakura/items/20a02161fa7e18d8a693#%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B)と同様に、`By.CLASS_NAME` や `By.XPATH`、`By.CSS_SELECTOR` など、いくつかの指定方法があります。

- 値を指定
    - title_is
    - title_contains
- ロケーターを指定
    - presence_of_element_located
    - visibility_of_element_located
    - presence_of_all_elements_located
    - frame_to_be_available_and_switch_to_it
    - invisibility_of_element_located
    - element_to_be_clickable
    - element_located_to_be_selected
- 要素を指定
    - visibility_of
    - element_to_be_selected
    - staleness_of
- ロケーターと値を指定
    - text_to_be_present_in_element （textを指定）
    - text_to_be_present_in_element_value （textを指定）
    - element_located_selection_state_to_be （期待するselectionの状態をBooleanで指定）
- 要素と値を指定
    - element_selection_state_to_be （期待するselectionの状態をBooleanで指定）
- 引数なし
    - alert_is_present

独自にクラスを作ることもできます（詳しくは[APIのドキュメント](https://selenium-python.readthedocs.io/waits.html#explicit-waits)）。


## ポーリング時間指定（非明示的待機）

要素がすぐに見つからない場合の待ち時間（ポーリング時間）を指定します。デフォルトは 0 です。

- `driver.implicitly_wait(秒数)`

## time.sleep() を使う

サーバーに負荷をかけ過ぎないように、`import time` + `time.sleep(秒数)` なども積極的に入れる必要がありそうです。

`expected_conditions` などではうまくいかない場合にも使います。




# スクリーンショット

画面のキャプチャを詳細にみてみます。

著作権をよく考慮する必要があります。



## 画面サイズを変えてスクリーンショット

### サイズ変更やスクロール

```python
driver.set_window_size(1280, 720)
# driver.maximize_window()  # 最大化する場合（ヘッドレスモードでは効かない）
"""
print(driver.get_window_size())
print((driver.execute_script("return window.innerHeight;"),
       driver.execute_script("return window.innerWidth;")))
print((driver.execute_script("return window.outerHeight;"),
       driver.execute_script("return window.outerWidth;")))
"""
driver.execute_script("window.scrollTo(0, 600);")  # スクロールして撮る場合
driver.save_screenshot('screenshot.png')
# driver.get_screenshot_as_file('screenshot.png')  # これも可
```

`driver.execute_script(...)` で JavaScript を実行することができます。
これでスクロールとスクリーンショットを繰り返すこともできます。

ヘッドレスモードにした方が調整しやすい & ずれないようです。
通常（非ヘッドレス）モードの場合、指定した値は `outerWidth, outerheight` に一致するようです。
一方、スクリーンショットの結果は `innerWidth, innerHeight` に対応する領域です。
ヘッドレスモードではこれらはずれませんが、通常モードでは少し設定が必要です（後述）。

Chrome 起動時からウィンドウのサイズを変えておくなら、`driver.set_window_size()` ではなく、Chrome 起動前に以下のオプションを指定します。

```python
options.add_argument('--window-size=800,600')
# options.add_argument('--start-maximized')  # 最大サイズでスタート
# options.add_argument('--start-fullscreen')  # 全画面表示でスタート
```

### スクロールバーをなくす

```python
driver.execute_script("document.body.style.overflow = 'hidden';")
```


### 通常モードでサイズのずれをなくす

以下の1から3をいずれも設定すれば、通常（非ヘッドレス）モードでも思ったようなサイズのスクリーンショットを得ることができます。つまり、ブラウザの outerWidth(Height) が innerWidth(Height) に一致し、さらに `set_window_size` の指定解像度とも一致します。

1. OS のディスプレイ設定で、拡大縮小を 100% にすることで解像度のずれをなくす。
    - 最近の高解像度のグラフィックボードに合わせて、150% や 200% などになっていることが多いです。
    - Windows では、デスクトップで右クリック > 「ディスプレイ設定」>「拡大縮小とレイアウト」
1. Chrome のオプションに `--disable-infobars` を追加して「Chrome は自動テスト ソフトウェアによって制御されています。」の表示を消す。
1. Chrome のオプションに `--start-fullscreen` を追加するか、スクリーンショットを撮る前に `driver.fullscreen_window()` を入れる。

ただし最後の設定でフルスクリーン（F11を押した状態、全画面表示）にしているため、画像サイズが画面解像度になってしまいます。

もし小さめのサイズにしたいなら、あらかじめ innerWidth(Height) に対して outerWidth(Height) がどれだけ大きいかを計算しておけば、その分あらかじめ大きめに `driver.set_window_size(...)` で指定できます。
この場合は、上記の1の設定（OS側での解像度の拡大をオフにする）だけ行い、2と3は不要です。

```python
# 通常モードでサイズのずれをなくす方法
driver = webdriver.Chrome()
h_add = driver.execute_script("return window.outerHeight - window.innerHeight;")
w_add = driver.execute_script("return window.outerWidth - window.innerWidth;")

driver.get("https://www.google.com")
driver.find_element_by_name("q").send_keys("python", Keys.RETURN)

# 1280 x 720 でスクリーンショットを撮りたい場合
driver.set_window_size(1280 + w_add, 720 + h_add)  # outerWidth, outerHeight を指定する
driver.save_screenshot('test2.png')  # 取得される画像サイズは innerWidth x innerHeight
```

### ファイルではなくメモリへ保存

`driver.get_screenshot_as_png()` や `driver.get_screenshot_as_base64()` を使って、ファイル保存することなく、メモリ上で画像を扱うことができます。

下の例では、いったん Pillow (PIL) の `Image.open(...)` で読み込むために、`io.BytesIO(...)` を使ってメモリ上の png バイナリデータをファイルオブジェクト（ストリーム）に変換しています。

```python
import io
from PIL import Image
# ... (省略) ...
img_png = driver.get_screenshot_as_png()
img_io = io.BytesIO(img_png)
img = Image.open(img_io)
img.show()  # 表示してみます
```

## ページ全体のスクリーンショット

ページサイズを JavaScript で取得しておくことで、ページ全体を撮ることもできます。

### ヘッドレスモードの場合

検索結果ページ全体のスクリーンショットを撮ってみます。

```python
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)

driver.get("https://www.google.com")
driver.find_element_by_name("q").send_keys("python", Keys.RETURN)

width = driver.execute_script("return document.body.scrollWidth;")
height = driver.execute_script("return document.body.scrollHeight;")
driver.set_window_size(width, height)
driver.save_screenshot('screenshot-full.png')
```

参考: https://blog.amedama.jp/entry/2018/07/28/003342 




### 通常モードの場合

通常（非ヘッドレス）モードだと画面サイズがウィンドウのサイズに制限されてしまうようなので、スクロールしながらスティッチング（画像貼り合わせ）してみます。

調べたところ[「Chromeでフルサイズのスクリーンショットを撮るためのパッチ」](https://qiita.com/myhr/items/dff7cee30182ab56f737)など、すでにいろいろとあるようです。このコードを参考にしつつ、メモリ上でスティッチングするように変えてみます。

コードを [Gist](https://gist.github.com/memakura/067caffde0850127f561b9d02f10435e) に置きます。

- [gist (fullscreenshot.py)](https://gist.github.com/memakura/067caffde0850127f561b9d02f10435e)


使い方

- OS 側のディスプレイ設定で、拡大を 100% にしておきます。（windows であればデスクトップで右クリックし「ディスプレイ設定」>「拡大縮小とレイアウト」)
- 同じフォルダに fullscreenshot.py がある場合、以下のように `save_fullscreenshot(...)` を呼びます。
- スクロールしても固定される要素（スタイルが `position: fixed;` のものなど）があれば、呼び出す前に解除しておきます（コード内のコメントを参照のこと）。

```python:how_to_use_fullscreenshot.py
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import fullscreenshot as fss

driver = webdriver.Chrome()
driver.get("https://www.google.com")
driver.find_element_by_name("q").send_keys("python", Keys.RETURN)

# driver.set_window_size(800, 600)  # 小さいウィンドウサイズでのテスト用
# スクロールについてくるヘッダやメニューなど（style.position が 'fixed' のもの）
# は適宜解除しておく。以下はあくまで例。
# driver.execute_script("document.getElementById('g-header').style.position = 'static';")
# driver.execute_script("document.getElementsByClassName('js-navi-menu-wrapper')[0].style.position = 'static';")

fss.save_fullscreenshot(driver, 'screenshot-full.png')

driver.quit()
```








# その他

## close() vs quit()

- `driver.close()` は現在フォーカスが当たっているブラウザウィンドウが閉じます。
- `driver.quit()` は全てのブラウザウィンドウを閉じるとともにその WebDriver セッションを終了します。

参考: https://code.i-harness.com/ja/q/e5e7e3


## クッキー関係

- 追加
    - `driver.add_cookie({'name':'key', 'value':'value'})`
    - 他に追加できる項目
        - `path`: 文字列 (/...)、`domain`: 文字列
        - `secure`: True/False、`expiry`: ミリ秒（エポック）、など
- 取得
    - `driver.get_cookies()`
        - 名前だけ表示してみる: `print([cookie['name'] for cookie in driver.get_cookies()])`
- 削除
    - `driver.delete_cookie("CookieName")`
    - `driver.delete_all_cookies()`


## その他の参考ページ

- 逆引き: http://www.seleniumqref.com/api/webdriver_gyaku.html
- 言語間の違いの整理: https://qiita.com/mochio/items/dc9935ee607895420186
- Chrome起動オプション: http://chrome.half-moon.org/43.html