loader image

Pythonとseleniumでタイピングゲームを自動化する

Python

はじめに

seleniumでの自動化がとても簡単で汎用性が高いため紹介しようと思います。
今回はさくっと実装できるPythonで作成しましたが、Python以外の言語でも簡単に作成できるのでぜひ挑戦してみてください。
ただ、サイトの規約でスクレイピングが禁止にされていたりする場合が多々あるため使用する際は気を付けてください。また業務で使用する際も責任者に確認をとるようにしましょう。

自動化ツールの作成

環境:とりあえず古くなければ動きます(Python 3.11.4)
本記事では関数もクラスも使用していませんが冗長化するのであれば可読性を上げるために関数を使用してください。クラスは可読性が落ちるためお勧めしませんが複数の業務を自動化するのであれば選択肢の一つとしてありです(当たり前ですがコメントは入れましょう。余裕があればナレッジ作成も)

必要なものをimportする

必要なものは以下になります。もし足りないものがあればインストールしてください。
※「pyautogui」はタイピングゲームの自動化に必要だっただけで、それ以外の用途では基本的に使うことはないと思います。

from selenium import webdriver  # Selenium WebDriverを使用するためのモジュール
from selenium.webdriver.chrome.service import Service  # Chromeドライバーのサービスを設定するためのモジュール
from selenium.webdriver.support.ui import WebDriverWait  # Seleniumの待機条件を使用するためのモジュール
from selenium.webdriver.common.by import By  # 要素を検索するための方法を指定するためのモジュール
from selenium.webdriver.support import expected_conditions as EC  # Seleniumの期待条件を使用するためのモジュール
from selenium.common.exceptions import NoSuchElementException  # 要素が見つからない場合の例外を扱うためのモジュール
from webdriver_manager.chrome import ChromeDriverManager  # Chromeドライバーを自動的に管理するためのモジュール
import time  # 時間待ちなどの一般的な処理のためのモジュール
import pyautogui  # マウスとキーボードの操作をシミュレートするためのモジュール
Python

今回はこれだけですが、もしExcelからデータを読み込んだり、シートに出力したい場合は「openpyxl」というライブラリもインストールしておくと良いでしょう。

変数を定義する

url = "https://www.e-typing.ne.jp/roma/check/"  # e-typingのURL

webdriver_service = Service(ChromeDriverManager().install()) # ChromeDriverのサービスを設定
driver = webdriver.Chrome(service=webdriver_service) # Chrome WebDriverを初期化

wait = WebDriverWait(driver=driver, timeout=30) # Driverが特定の要素を待つためのオブジェクトを作成
locator = (By.XPATH,'//*[@id="start_btn"]') # クリックを待機するための要素のロケータ
Python

3行目と4行目は重要なので解説を入れます。
この部分のコードは、Chromeブラウザを制御するためのWebDriverを設定して初期化しています。

webdriver_service は、Chromeドライバーを実行するためのサービスを設定しています。ChromeDriverManager().install() は、WebDriver Managerを使用して自動的にChromeドライバーをインストールし、そのパスを取得します。
これの設定をしない場合はChromeからドライバーをインストールしてくる必要があり、更新の手間やツールを共有したときに環境の違いから動作しないなど不都合が多いため、ほぼ必須になります。

driver = webdriver.Chrome(service=webdriver_service) は、設定されたサービスを使用してChromeのWebDriverを初期化しています。これにより、SeleniumがChromeブラウザを制御するためのWebDriverインスタンスが作成されます。

共通処理

自動化する際によく使用する処理について実際のコードを見ながら説明します。

基本的な処理の流れ

主な処理の流れはdriver.find_element()で要素を取得し、その要素に対して何かしらの操作をすることの繰り返しになります。要素の指定はIDやCLASS、XPATHなどで指定できます。
今回は取得した要素に対してクリック以外の操作はしていませんが他にも様々な操作ができます。

【取得した要素に対する操作一覧】
click(): 要素をクリックする。
send_keys(): 要素にテキストやキーボード入力を送信する。
clear(): 要素の内容をクリアする(テキスト入力フィールドの場合)。
get_attribute(): 要素の属性の値を取得する。
is_displayed(): 要素が表示されているかどうかを判断する。
is_enabled(): 要素が有効化されているかどうかを判断する(クリック可能な要素など)。
is_selected(): チェックボックスやラジオボタンなどの要素が選択されているかどうかを判断する。
text: 要素のテキストを取得する(変数に格納して使用する)

driver.get(url)  # 指定されたURLにブラウザを移動

time.sleep(3)  # 3秒待機

# レベルチェックボタンをクリック
driver.find_element(By.ID,"level_check_btn").click()

time.sleep(5)  # 5秒待機

# タイピングコンテンツのiframeを取得して切り替える
iframe = driver.find_element(By.XPATH,'//*[@id="typing_content"]')
driver.switch_to.frame(iframe)

# スタートボタンをクリックするための要素を待機
start = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "start_btn")))
start.click()

time.sleep(3)  # アニメーションがあるため3秒待機

pyautogui.press('space')  # スペースキーを押下

time.sleep(4)  # アニメーションがあるため4秒待機
Python

timeモジュールとECモジュール

time.sleep()を多用していますが、これは一定時間待つだけの処理であるため
要素の表示を待つのにはなるべく使わないようにしてください(18,22行目のようなアニメーションの終了を待つだけであれば良いが、それ以外は要素が表示されている保証がないため)

もし、要素の表示を待ちたいのであれば15行目のようなECモジュールを使用するようにしてください。
今回はさくっと作りたかったのでtime.sleep()でごり押ししています…。

【ECモジュール(expected_conditions)の使い方一覧】
presence_of_element_located(locator):指定された要素がDOM内に存在することを待つ。
visibility_of_element_located(locator):指定された要素が表示されることを待つ。
visibility_of(element):指定された要素が表示されることを待つ。
element_to_be_clickable(locator):指定された要素がクリック可能になることを待つ。
title_is(title):指定されたタイトルがページのタイトルと一致することを待つ。
title_contains(partial_title):指定された部分タイトルがページのタイトルに含まれることを待つ。
alert_is_present():アラートが表示されるのを待つ。

iframeについて

iframeが登場することは少ないため詳細は割愛しますがザックリと解説をすると
iframe内の要素にアクセスするには、WebDriverがiframeを切り替える必要があります。
その後、iframe内の要素に対して通常通りの操作が可能になります。

カスタマイズ処理

先ほどまでの処理は自動化するにあたってよく使用する処理でした。ここからはタイピングゲーム専用の処理になります。と思ったけど特に解説することがないのでこのゲームの仕様について少しだけ。
8行目でインターバルを設定しない場合、超高速タイピングが可能になりますが記録はエラー判定になります。おそらく自動化対策なのかな??

while True:
    try:
        # 文字入力要素を取得
        type_text_element = driver.find_element(By.XPATH, '//*[@id="sentenceText"]/div/span[2]')
        
        # 要素のテキストを取得して入力する
        type_text = type_text_element.text
        pyautogui.typewrite(type_text, interval=0.05)  # キーストローク間の待機時間を0.05秒に設定
        time.sleep(0.5)  # 0.5秒待機して次の要素を探す
    except NoSuchElementException:
        print("NoSuchElementException")  # NoSuchElementExceptionが発生した場合、処理を終了
        break
        
input("Enterで終了")  # Enterキーが押されるまで待機

driver.quit()  # WebDriverを終了する
Python

おまけ

たいしたことではありませんが業務で自動化ツールを作成して展開するときにおすすめのやり方を紹介します。
それは実行ファイルと一緒にバッチファイルを展開することです。バッチファイルは2つに分けます。
一つが環境を整えるためのバッチファイル(ライブラリのインストールやアップデート用)
もう一つが実行ファイルを実行するバッチファイルです。
これをすることによる利点は3つあります。①誤ったライブラリのインストールを防ぐことができる。②保守管理が容易である。③実行環境だけ用意すればあとはバッチを叩くだけで実行できる(それぞれの環境の影響を受けにくい)。

コメント

タイトルとURLをコピーしました