seleniumでサイトに一度だけログインしてセッションを保存してログイン状態を保ちながら使い続ける方法

# はじめに

seleniumを使ったら自動的にサイトにアクセスして色々できて本当に便利ですよね。

seleniumの基本的な使い方については色んな記事に書いてあります。
- [Python + Selenium で Chrome の自動操作を一通り](https://qiita.com/memakura/items/20a02161fa7e18d8a693)
- [10分で理解する Selenium](https://qiita.com/Chanmoro/items/9a3c86bb465c1cce738a)
- [Selenium webdriverよく使う操作メソッドまとめ](https://qiita.com/mochio/items/dc9935ee607895420186)

ただしログインする必要があるサイトを使う時に少し難易度が高くなりますね。

自動でログインする方法は意外とたくさんの記事に書いてあります。
- [Python + Selenium + Chrome で自動ログインいくつか](https://qiita.com/memakura/items/dbe7f6edadd456da1c5d)
- [【Googleログイン自動化】Python×seleniumでGoogleにログインする](https://qiita.com/studyinfra/items/144c6cb7a7444f804564)
- [SeleniumでSlackに自動でログインする](https://qiita.com/h-nabata/items/96d6a9068cb7c6ad26ae)
- [selenium から Twitter にログインして投稿](https://qiita.com/katafuchix/items/8d4c2bed73d79ba072d9)
- [PythonとSeleniumで自動ログインを行う](https://qiita.com/wejhhv/items/59d739b40dc6f7f5aabc)
- [楽天銀行サイトにPythonとSeleniumを使ってログインする](https://qiita.com/yoshi2045/items/2fff5bf5f0fa763f7104)

しかしこれらの記事はどれもログインの状態が保存されないので、毎回ログインする必要があることになります。ログイン状態を保存する方法に関しては書かれていないのです。

毎回ログインしたら手間かかりますね。それにサイトによって何度もログインしたらスパムだと思われる可能性もあります。

なので私のやりたいことは**一回ログインしたら**そのセッションのクッキーを保存して、この後もう一度ログインしなくても**何回も使い続けられる**、という方法です。

この記事はこんなことをするコードの書き方を説明します。

注意：ここで使っているseleniumのバージョンは4.8.0です。3.xを使っている場合なら書き方は色々違います。


# 基本操作

ここて例としてwikipediaを使います。まずはseleniumでwikipediaのログインのページにアクセスしてログインする方法から始めます。

```python
from selenium import webdriver
from selenium.webdriver.common.by import By

login_url = 'https://ja.wikipedia.org/w/index.php?title=特別:ログイン'
username = 'ahoge' # ユーザーの名前（ここではただ適当に書いています）
password = 'afuga' # パスワード

driver = webdriver.Chrome()
driver.get(login_url) # ログインのページにアクセス
driver.set_window_size(600,600)

# ユーザー名入力
name_box = driver.find_element(By.NAME,'wpName')
name_box.send_keys(username)
# パスワード入力
password_box = driver.find_element(By.NAME,'wpPassword')
password_box.send_keys(password)
# ログイン状態を保つためのチェックボックス
remember_box = driver.find_element(By.NAME,'wpRemember')
remember_box.click()
```

これを実行したら、このような画面が出るはずです。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202903/ce4fbc03-3f3d-991b-05bc-fa625eda0f4d.png)

そして最後に
```python
name_box.submit()
```
を追加したらログインすることになります。

これでwikipediaにログインして色々やることができますね。


# ログインしてセッションクッキーを保存する

次はログインした後セッションのクッキーを保存する方法についてです。

保存する方法は色々ありますが、ここではpickleで保存します。jsonを使うのも悪くない方法です。

pickleに関してはこの記事を参考に。
- [【Python】pickle（漬け物）は仮想マシンだった——仕組みとリスク](https://qiita.com/tanuk1647/items/4c2a305c7cc4e12ef99d)

では`.get_cookies()`メソッドを使ってクッキーを取得してpickleで保存するコードは以下です。

```python
from selenium import webdriver
from selenium.webdriver.common.by import By
import pickle

login_url = 'https://ja.wikipedia.org/w/index.php?title=特別:ログイン'
username = 'ahoge' # ユーザーの名前
password = 'afuga' # パスワード
cookies_file = 'morokoshi.pkl' # クッキーを保存するファイルの名前

driver = webdriver.Chrome()
driver.get(login_url)

name_box = driver.find_element(By.NAME,'wpName')
name_box.send_keys(username)
password_box = driver.find_element(By.NAME,'wpPassword')
password_box.send_keys(password)
remember_box = driver.find_element(By.NAME,'wpRemember')
remember_box.click()
name_box.submit()

cookies = driver.get_cookies() # クッキーを取得する
pickle.dump(cookies,open(cookies_file,'wb')) # クッキーを保存する
driver.quit() # ウィンドウを閉じる
```

これでセッションのクッキーは`morokoshi.pkl`に保存して、後で使えるようになります。


# セッションクッキーを読み込んで使う

次は保存されたクッキーをpickleファイルから読み込んで使うコードです。

```python
from selenium import webdriver
import pickle

web_url = 'https://ja.wikipedia.org/wiki/日本書紀' # 入りたいページ
cookies_file = 'morokoshi.pkl' # クッキーを保存するファイルの名前

driver2 = webdriver.Chrome()
cookies = pickle.load(open(cookies_file,'rb')) # クッキーを読み込む
driver2.get(web_url) # まずは一度サイトにアクセス
for c in cookies: # クッキーを設定する
    driver2.add_cookie(c)
driver2.get(web_url) # クッキーを設定した後またアクセス
driver2.set_window_size(800,600)
```

成功したら結果はこんな感じでしょう。ちゃんとユーザー名が上に書いてあります。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202903/10d07571-1ded-c322-da3b-6144ec881040.png)

クッキーを設定する時は`.add_cookie()`メソッドを使って一つずつ追加することになります。

ただしここで注意する必要があるのは、`.add_cookie()`を使う前にまずは一度同じサイトにアクセスする必要があります。そうしなければこのようなエラーが出ます。

```
InvalidCookieDomainException: invalid cookie domain
  (Session info: chrome=109.0.5414.120)
```

先にアクセスするurlは入りたいページと同じurlである必要ないのですが、同じサイトである必要があります。

例えば今回はまず`https://ja.wikipedia.org`にアクセスするのも問題ないです。でも`https://fr.wikipedia.org`は駄目みたい。



# 一度だけログインしたらセッションを使い続ける

実際に使う時にこのように書くと便利です。

```python
from selenium import webdriver
from selenium.webdriver.common.by import By
import pickle,os

login_url = 'https://ja.wikipedia.org/w/index.php?title=特別:ログイン' # ログインのページ
web_url = 'https://ja.wikipedia.org/wiki/Qiita' # 入りたいページ
username = 'ahoge' # ユーザーの名前
password = 'afuga' # パスワード
cookies_file = 'morokoshi.pkl' # クッキーを保存するファイルの名前

driver = webdriver.Chrome()

# まだクッキーを持っていない場合新しくログインして保存する
if(not os.path.exists(cookies_file)):
    driver.get(login_url)
    name_box = driver.find_element(By.NAME,'wpName')
    name_box.send_keys(username)
    password_box = driver.find_element(By.NAME,'wpPassword')
    password_box.send_keys(password)
    remember_box = driver.find_element(By.NAME,'wpRemember')
    remember_box.click()
    name_box.submit()
    
    cookies = driver.get_cookies()
    pickle.dump(cookies,open(cookies_file,'wb'))
# すでにクッキーを持っている場合読み込んで使う
else:
    cookies = pickle.load(open(cookies_file,'rb'))
    driver.get(web_url)
    for c in cookies:
        driver.add_cookie(c)

# やりたいことなど
driver.get(web_url)
driver.set_window_size(800,700)
driver.save_screenshot('wikiscreenshot.png')
driver.quit()
```

結果としてこんなスクリーンショットが保存されますね。
![wikiscreenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202903/8fe9f1be-0e38-874d-4fb7-2f80f86c5617.png)



# ログインの不具合の対策

何かの間違いでログインが失敗で終わる場合もあるので、ちゃんとログインできているか確認する必要がありますね。

方法はサイトによって違いますが、wikipediaでは例えばログイン成功したらそのページの中に自分のユーザー名がついているはずだから、今回はページのコードを取得してその中にユーザー名が含まれるかどうかという情報を利用します。

書いてみたらこんな感じでしょう。

```python
from selenium import webdriver
from selenium.webdriver.common.by import By
import pickle,os

login_url = 'https://ja.wikipedia.org/w/index.php?title=特別:ログイン'
web_url = 'https://ja.wikipedia.org/wiki/Qiita'
username = 'ahoge'
password = 'afuga'
cookies_file = 'morokoshi.pkl'

def login():
    driver.get(login_url)
    name_box = driver.find_element(By.NAME,'wpName')
    name_box.send_keys(username)
    password_box = driver.find_element(By.NAME,'wpPassword')
    password_box.send_keys(password)
    remember_box = driver.find_element(By.NAME,'wpRemember')
    remember_box.click()
    name_box.submit()
    
    cookies = driver.get_cookies()
    pickle.dump(cookies,open(cookies_file,'wb'))

def load_cookies():
    cookies = pickle.load(open(cookies_file,'rb'))
    driver.get(web_url)
    for c in cookies:
        driver.add_cookie(c)
    
driver = webdriver.Chrome()
if(not os.path.exists(cookies_file)):
    login() # ログインしてクッキーを保存する
else:
    load_cookies() # クッキーを読み込む
    driver.get(web_url)
    # クッキーを設定してもログイン状態になっていない場合は一応もう一度ログインを試す
    if('<span>%s</span>'%username not in driver.page_source):
        login()

if('<span>%s</span>'%username in driver.page_source): # 無事でログインできた場合、やりたいコードを実行する
    '''
    やりたいことなど
    '''
else: # 失敗する場合
    print('何か不具合があるみたい')
```


# 関係ある方法

requestsで取得したログインセッションクッキーを使ってseleniumに使うという方法もあるようです。
- [Python requests で取得したログインセッションクッキーを Selenium ブラウザに渡してログインする](https://qiita.com/ytyng/items/5e6dad02a6adabc21fed)

でも自分でこの方法を試しても上手くいかなかったです。それにやっぱりできれば全部seleniumでやる方が簡易です。

逆にseleniumでセッションクッキーを取得してrequestsで使うという方法もあります。
- [【Python】ログイン処理をSeleniumで行い、その後はrequestsで処理する](https://qiita.com/shobota/items/a4ae8f45a4620787b3e9)


# 終わりに

以上、seleniumを使う時にセッションのクッキーを保存したり読み込んだりしてログイン状態を扱う方法について説明しました。

こうしたことで何度もログインする必要がなくて済んで便利だというわけです。

最後に言うまでもないかもしれませんが、スクレイピングはサイトに負担をかける行為だから、ほどほどにしておいた方がいいですね。これを使ってサイトに迷惑をかけてしまったらBANされるかもしれないから。