見出し画像

Python×Seleniumでログイン認証後にリスト要素を選択する方法

こんにちは、ようへいです。

趣味の競馬で開発・運用している競馬予想支援システム。

このシステムでは、競馬の予想印(◎/○/▲/△/☆/注/消)を管理しています。
それを毎週netkeibaに手で転記していたのですが、それが非常に単調かつ面倒なので、PythonとSeleniumを使って自動化してしまおう、というものです。

簡単にできるつもりでいましたが、初めてSeleniumを実装してみて盛大にハマったので備忘として残します


Seleniumとは

一言で言うと
ブラウザ操作の自動化ライブラリ です。

人間によるブラウザ操作(手続き)をコードに書いてあげることで、操作を自動化できます。

環境

Python  :3.9
Selenium :4.18.1
urllib3   :2.2.1
webdriver-manager :4.0.1
Microsoft Edge   :122.0.2365.92
Microsoft Edge WebDriver :122.0.2365.92
※EdgeとWebDriverはバージョンを合わせる必要があります。

実現したいこと

実現したいのは大きく2点。

  1. netkeibaにログインする。

  2. システムで管理している予想印をnetkeibaの出馬表に転記する。
    予想印はリストになっているので、リストを選択する。

転記した予想印はPCでもスマートフォンでも見れるようにしたいので、アカウントへのログインが必要になります。

Code Tips

ビジネスロジックは省き、Seleniumを使った実装部分をTipsとして載せます。

ライブラリの参照

import selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
from msedge.selenium_tools import EdgeOptions
from selenium.webdriver.edge.service import Service

EdgeのWebDriverインスタンスの生成

このコードブロックの一番の目的はWebDriverを生成すること。

EdgeOptionを指定しますが、これは、Seleniumでブラウザを起動したときに「Microsoft Edgeは自動テストソフトウェアによって制御されています」を消すためのオプション設定です。

options = EdgeOptions()
options.use_chromium = True
options.accept_insecure_certs = True
options._ignore_local_proxy = True
options.add_argument('–no-sandbox')
options.add_experimental_option("excludeSwitches", ['enable-automation'])
driver = webdriver.Edge(service=Service(executable_path=current_app.config['EDGE_WEB_DRV_PATH']), options=options)

current_app.config['EDGE_WEB_DRV_PATH']は、msedgedriver.exeのフルパスを指定しています。

インストールされていなければ、インストールしてください。

ログイン認証

このコードブロックでは、ログイン認証を突破するため、以下のことを行っています。

  • ログイン認証URLの表示

  • ID、パスワードの自動入力

  • ログインボタンのクリック

driver.get(current_app.config['NET_KEIBA_LOGIN_URL'])
driver.find_element(By.NAME, "login_id").send_keys(current_app.config['NET_KEIBA_LOGIN_ID'])
driver.find_element(By.NAME, "pswd").send_keys(current_app.config['NET_KEIBA_LOGIN_PW'])
div_elem = driver.find_element(By.CLASS_NAME, "loginBtn__wrap")
div_elem.find_element(By.TAG_NAME, "input").click()

予想印のリスト要素の選択

td_elem = horse_list_elem.find_element(By.XPATH, "./td[@class='CheckMark Horse_Select']")
div_tzselect_elem = td_elem.find_element(By.XPATH, "./div[@class='tzSelect']")
driver.execute_script("arguments[0].scrollIntoView();", div_tzselect_elem)
div_tzselect_elem.click()
sleep(0.2)
ul_elem = div_tzselect_elem.find_element(By.XPATH, "./ul")
ul_elem.find_element(By.XPATH, "./li[" + str(yoso_mark) + "]").click()

かみ砕いて説明すると

1~2行目

td_elem = horse_list_elem.find_element(By.XPATH, "./td[@class='CheckMark Horse_Select']")
div_tzselect_elem = td_elem.find_element(By.XPATH, "./div[@class='tzSelect']")

目的のHTML要素をXPATHで辿っています。
デバッグのため、わざわざ2行に分けてしまいましたが、XPATHで指定するので1行にまとめてしまっても問題ありません。

3行目

driver.execute_script("arguments[0].scrollIntoView();", div_tzselect_elem)

Seleniumは人の操作を自動化するだけなので、ディスプレイに映っていない部分に対する操作はエラーになります。
そのため、ブラウザのスクロール位置をnetkeibaの出馬表の対象行に合わせています。

4~5行目

div_tzselect_elem.click()
sleep(0.2)

コード2行目で特定したリスト要素をクリックし、予想印のリストを表示させています。
リストを表示を指示してから表示されるまでの間に、リストの選択が行われれしまうのを避けるため、0.2秒のスリープを入れています。
6~7行目

ul_elem = div_tzselect_elem.find_element(By.XPATH, "./ul")
ul_elem.find_element(By.XPATH, "./li[" + str(yoso_mark) + "]").click()

リストの実態であるUL要素をたどり、その中の目的のLI要素をクリックしています。
これで、表示されたリストの中にある、目的の要素を選択しています。

Seleniumを使ってみた感想

エラーが分かりづらいのでデバッグが大変かな、と思いました。
エラーメッセージから、何をどのようにケアしてあげればよいのか想像できません。
1つ詰まってネットで調べて、、、の繰り返し。
なので、慣れが必要かな、と思います。

書いたコードが動くようになってくると、画期的なツールのようにも感じました。

ブラウザの自動操作が実現できるので、開発中のシステムのブラウザを使ったテストの自動化が期待できますね。
ただし、人の操作をPC上で再現してるにすぎないので、再現中は人間はPCが触れなくなります。
UIの自動テストを目的とするなら、自動テスト専用PCが必要ですね。

上記とは別の視点で。
ブラウザ操作の自動化だけならPowerAutomateとあんまり変わらない気がしますが、Pythonも使っているので、ブラウザ操作の自動化+別の何らかの処理をワンパッケージで扱えるのはPowerAutomateよりも強力な部分かと思いました。

これはちょっとしたひらめきですが、
うちの会社では、出社後にWebの社内システムで出社操作を行います。
退社前には退社操作を行います。

システムにログインして、メニューを選び、操作し、手続き完了。
このルーチンワークを毎日手作業でやってるのが億劫です。

なので、今回の仕組みを活用して、ブラウザの自動操作をログオンスクリプトやシャットダウンスクリプトに組み込んでしまえば、PCを起動した時やシャットダウンした時に自動で出退勤の操作が行えそうです。

これで日々5分短縮できれば、別なことに使えそうですね。

#Python
#Selenium
#認証自動化
#リスト選択




この記事が気に入ったらサポートをしてみませんか?