【Python】妻に真夜中のダンスレッスン予約を強要されたので、Webスクレイピングで回避を試みようとしている話 （１０．seleniumでログイン）

前回は、<a href="https://qiita.com/sibulabo/items/24f23284dff33ab73d83">「９．会員・予約情報<Excel>を読み込む。」</a>について投稿しました。<a href="https://qiita.com/sibulabo/items/5c6829d8e4b6540855c8">前々回</a>でレッスン予約サイトを開いて閉じるところまでできているので、今回は次の段階として、IDとパスワードを使用して予約サイトにログインするところまでコーディングしたいと思います。

-------------------------------------------------------------------------------------------
# ブラウザの検証ツールを使用して要素を特定する。
会員番号、パウワードを入力しログインボタンをクリックするには、それぞれの HTMLタグ要素を特定するキーとなる情報が何なのかを確認する必要があります。それらは検証ツールを使用することで確認できます。

ログインページを表示した状態で、マウス右クリで表示されるコンテキストメニューで「検証」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915699/a36b94ac-f047-a0ac-d75d-be9efc749c6c.jpeg" width=70% />

「Elements」が表示されている状態で①要素選択ツールのアイコンをクリックします。次に確認したい②要素（下の画像では会員番号）をクリックすると、Elementsタブ内に該当する HTMLタグがハイライト表示されます。
![WS000016.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915699/de1a630e-6840-8404-4725-618b2882362a.jpeg)

各要素について確認すると、すべて id値で特定できることがわかります。
![WS000015.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915699/bb0f3d88-7385-02d7-3d59-113fc0bb961f.jpeg)

:::note info
- 会員番号：id="member_no"
- パスワード：id="password"
- ログインボタン：id="login_btn"
:::
# ログイン処理のコーディング

## mainサブに予約件数分レッスン予約サブをコールする処理を追加
行番号：２５～２８
```reserveLesson.py
18:  def main():
19:      #会員・予約情報(Excel)を辞書リスト形式で取得する。
20:      rsvlst = getExcelDicList()
21:  
22:      #Webドライバーオブジェクトを取得する。
23:      driver = openChromeBrowser()
24:  
25:      #予約件数分ループ
26:      for rsvdic in rsvlst:
27:          #レッスン予約処理
28:          reserveLesson(driver, rsvdic)
```
### 詳細処理説明
:::note info
26: <a href="https://qiita.com/sibulabo/items/24f23284dff33ab73d83">前回</a>取得した会員予約情報が保存された辞書リスト(rsvlst)を行数分ループします。
（rsvlst変数の中身）
![WS000004.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915699/22369110-c59a-d5f3-2f17-32303879a1f0.jpeg)
28: レッスン予約関数(reserveLesson())をコールします。第２引数には１行分の辞書（rsvdic）を渡しています。
:::

## レッスン予約サブを追加
ログインサイトを表示して、会員番号、パスワードを入力しログインボタンをクリックする処理をコーディングしました。
```reserveLesson.py
36:  #--レッスンを予約する
37:  def reserveLesson(driver, rsvdic):
38:      #サイトを表示する。
39:      driver.get(LOGIN_URL)
40:      #ユーザー名、パスワードを設定してログイン
41:      driver.find_element(By.ID, "member_no").send_keys(rsvdic["ユーザー名"])
42:      driver.find_element(By.ID, "password").send_keys(rsvdic["パスワード"])
43:      driver.find_element(By.ID, "login_btn").click()
44:
```
### 詳細処理説明
seleniumライブラリの find_elementメソッドで要素を特定し、続けて send_keysメソッドで要素に値を設定できます。

:::note info
39: ログインサイトを表示します。
41-42: 会員番号、パスワードを設定しています。
- find_elementメソッドの第１引数で何をキーとするのかを指定します。この場合は、IDをキーとして検索することを指定しています。
- send_keysの引数には、rsvdic辞書のKeyを指定して、Value値を渡しています。

43: 予約ボタンをクリックしています。
- find_elementでIDをキーとしてログインボタンを検索し、clickメソッドでクリックを実行しています。
:::

## reserveLesson.pyの全容
```reserveLesson.py
 1:  #各コンポーネントをインポート
 2:  from selenium import webdriver
 3:  from selenium.webdriver.chrome import service
 4:  from selenium.webdriver.common.by import By
 5:  from webdriver_manager.chrome import ChromeDriverManager
 6:  from openpyxl import load_workbook
 7:  import os
 8:  
 9:  #--定数----------------
10:  #LOGIN_URL = "##############"    #ログイン画面のURL
11:  LOGIN_URL = "https://google.com"
12:  EXCEL_FILENAME = "reserveLessonList.xlsx"
13:  
14:  
15:  #******************************************************************
16:  # main処理
17:  #******************************************************************
18:  def main():
19:      #会員・予約情報(Excel)を辞書リスト形式で取得する。
20:      rsvlst = getExcelDicList()
21:  
22:      #Webドライバーオブジェクトを取得する。
23:      driver = openChromeBrowser()
24:  
25:      #予約件数分ループ
26:      for rsvdic in rsvlst:
27:          #レッスン予約処理
28:          reserveLesson(driver, rsvdic)
29:  
30:      #chromeドライバー セッション終了
31:      driver.quit()
32:  
33:  #---------------------
34:  # SubRoutine
35:  #---------------------
36:  #--レッスンを予約する
37:  def reserveLesson(driver, rsvdic):
38:      #サイトを表示する。
39:      driver.get(LOGIN_URL)
40:      #ユーザー名、パスワードを設定してログイン
41:      driver.find_element(By.ID, "member_id").send_keys(rsvdic["ユーザー名"])
42:      driver.find_element(By.ID, "password").send_keys(rsvdic["パスワード"])
43:      driver.find_element(By.CLASS_NAME, "login_btn").click()
44:  
45:  #--レッスン予約サイトを開く
46:  def openChromeBrowser():
47:      #Serviceオブジェクトを介して、execute_pathを指定する。
48:      chrome_service =  service.Service(executable_path=ChromeDriverManager().install())
49:      #chromeドライバー セッション開始（最新Ver自動インストール、およびオプション指定）
50:      driver = webdriver.Chrome(service=chrome_service, options=getOptions())
51:  
52:      return driver
53:  
54:  #--Get ChromeDriver Options------
55:  def getOptions():
56:      options = webdriver.ChromeOptions()
57:      options.headless = False    #ヘッドレスモード True:ブラウザ画面非表示、False:表示
58:  
59:      return options
60:  
61:  #--会員・予約情報を辞書リスト形式で取得する。---
62:  def getExcelDicList():
63:      #予約一覧Excelファイルパス取得
64:      rsv_lst_path = os.path.join(os.getcwd(), EXCEL_FILENAME)
65:      #予約一覧を読み込み専用で開く。
66:      wb = load_workbook(rsv_lst_path, read_only=True)
67:      #予約一覧シートを指定
68:      ws = wb["予約一覧"]
69:  
70:      #**********************************
71:      #* {列名：セル値}の辞書をリスト化する。（[{列名：セル値},{列名:セル値},...]）
72:      #**********************************
73:      header = ws[1]  #1行目の列名を取得
74:      rsvlst =  []    #リスト初期化
75:      #予約一覧データ部(2行目～)の行数分処理する。
76:      for row in ws.iter_rows(min_row=2, max_row=ws.max_row):
77:          rsvinf = {}     #辞書初期化
78:          #列名:セル値の辞書作成
79:          for k, v in zip(header, row):
80:              rsvinf[k.value] = v.value
81:          #作成した辞書をリストに追加
82:          rsvlst.append(rsvinf)
83:  
84:      #Close ExcelBook
85:      wb.close()
86:  
87:      return rsvlst
88:  
89:  #-------------------------------
90:  # スクリプト実行時に mainサブコール
91:  #-------------------------------
92:  if __name__ == '__main__':
93:      main()
94:
```

ようやくログインできるところまでこぎつけました。:expressionless:
カレンダーで日付クリックしたり、予約できる場所を見つけたり、まだ色々やらないといけないことがてんこ盛りです。次回はどこまでできるのか、私にもわかりません。:smirk_cat: