Seleniumは各ブラウザに対応しますが、ここではGoogle Chromeを操作することを前提に解説します。
C:\python -m pip install seleniumInstall a Selenium library | Selenium
from selenium import webdriver driver = webdriver.Chrome() # Chromeが起動する driver.get("http://example.com") # example.comが開く driver.quit() # Chromeが閉じられるThe Selenium Browser Automation Project | Selenium
Selenium 4.6.0以降はSelenium Managerにより、必要なWebDriverが自動でインストーされます。Selenium 4.6.0 Released! | Selenium
その場所は%USERPROFILE%\.cache\seleniumになります。
ただしブラウザを起動するときにドライバのパスを指定していると自動で更新されず、「session not created」としてSessionNotCreatedExceptionが投げられます。そのときはwebdriver.Chrome()のようにパスを指定せずにドライバを作成すると、必要なドライバが自動でインストールされます。
ドライバのパスの指定を誤ると、「Unable to locate or obtain driver for chrome; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/driver_location」としてNoSuchDriverExceptionで失敗します。
手動でインストールするならば、次のページからダウンロードできます。
Chrome for Testing availability
ChromeDriver とは何ですか? | Chrome for Developersセッションを開始や停止することは、ブラウザを開いたり閉じたりすることです。Driver Sessions | Selenium
driver = webdriver.Chrome(options=options)
optionsで、ブラウザの動作を指定します。Browser Options | Selenium
ブラウザ固有のオプションはSupported Browsersのリンク先にあり、ChromeはChrome specific functionalityにあります。
options.add_argument("--user-agent=test")
とすることでUser-Agentを指定できますが、これは起動オプションとして設定するため、"debuggerAddress"を指定して既存のブラウザに結びつけたときは作用しません。
driver.quit()
セッションを開始するたびに新しいブラウザが開かれず、既に開かれているブラウザが利用されるようにする方法を考えます。
そのためにはChromeを、ポート番号を指定して起動します。ポート転送でローカル サーバーと Chrome インスタンスにアクセスする | Chrome DevTools | Chrome for Developers
ポート番号には9222などの使用可能な番号を、そしてプロファイルのディレクトリも指定します。 Step 2: Launch browser with options - How to connect Selenium to an existing browser that was opened manually? – CosmoCode (Formerly TeachMeSelenium) Chromium Blog: Remote debugging with Chrome Developer Tools
chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\ChromeProfile"
セッションを作成するときにそのポート番号をオプションで、ChromeDriverのパスをサービスで指定します。
options = webdriver.ChromeOptions()
options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
service = Service(executable_path="path/chromedriver.exe")
driver = webdriver.Chrome(options=options, service=service)
Can Selenium interact with an existing browser session? - Stack Overflow
How to connect Selenium to an existing browser that was opened manually? – CosmoCode (Formerly TeachMeSelenium)
Chromeを起動するときにプロファイルのディレクトリを指定していないと、webdriver.Chrome()でSessionNotCreatedExceptionの例外が投げられます。
Chromiumを基にしたブラウザが複数インストールされているならば、それらを指定できます。
options.binary_location = chrome_binStart browser in a specified location - Chrome specific functionality | Selenium
ページを開いたり、移動させたりできます。Browser navigation | Selenium
driver.get("http://example.com/index.html")
リンク先を開くには、その要素に対してclick()を呼びます。
anchor = driver.find_element(By.LINK_TEXT, "TEST") anchor.click()
そのとき確実に新しいタブで開くには、Ctrlキーの押下を模擬してクリックするか、新しいタブを開いた上でそこで新しいページを開きます。 selenium - How to open a new window while clicking on a link using java - Stack Overflow How to open a URL in new window using Selenium Webdriver? - Codekru
anchor = driver.find_element(By.TAG_NAME, "a")
url = anchor.get_attribute("href")
driver.switch_to.new_window('tab') # 新しいタブを開く
driver.get(url) # 指定のURLを開く
driver.back()
driver.forward()
driver.refresh()
ウィンドウ ハンドルやブラウザのサイズや位置、それにCookieなどの情報を要求できます。Browser interactions | Selenium
WebDriverはウィンドウとタブを区別せず、ウィンドウ ハンドルによってそれらを識別します。Windows and tabs - Working with windows and tabs | Selenium
driver.current_window_handle
close()を呼ぶことでウィンドウを閉じられます。Closing a window or tab - Working with windows and tabs | Selenium
driver.close()
ただし閉じたウィンドウを後から操作しようとすると「no such window: target window already closed」としてNoSuchWindowExceptionが投げられるため、そのような状況では閉じるウィンドウに切り替える前に
original_window = driver.current_window_handle
としてハンドルを保持しておき、閉じた後に
driver.switch_to.window(original_window)
として元のウィンドウに切り替えます。
現在のセッションのウィンドウ ハンドルを順に取得し、そのウィンドウにフォーカスを合わせます。そしてそのウィンドウが条件に一致していたら処理を打ち切ります。
for window_handle in driver.window_handles:
driver.switch_to.window(window_handle)
if driver.current_url.startswith("http://example.cm/"):
break
ページの要素を取得や操作するには、それが可能になるまで待機する必要がある場合があります。Waiting Strategies | Selenium
要素が見つかるまで、またはコマンドが完了するまでの待ち時間を指定できます。これはセッション毎に1回の呼び出しが必要です。ブラウザのオプションでも指定できます。単位は秒です。既定値は0です。
driver.implicitly_wait(0.5)
要素がユーザーに可視となるまで待たせるには、次のようにします。
from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions
element1 = driver.find_element(By.ID, "test1") element1.click() wait = WebDriverWait(driver, timeout=2) element2 = driver.find_element(By.ID, "test2") wait.until(lambda _: element2.is_displayed())
expected_conditionsを用いれば、これは次のようにも記述できます。Waiting with Expected Conditions | Selenium
wait.until(expected_conditions.visibility_of_element_located((By.ID, "test2")))
ウィンドウ ハンドルの数が増加するまで待機することで、ウィンドウが開かれるまで待機することになります。Python. Selenium. How to wait for new window opens? - Stack Overflow
要素に関連する操作をするためには、まずその要素を見つける必要があります。Finding web elements | Selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("http://example.com")
sample = driver.find_element(By.CLASS_NAME, "sample")
driver.quit()
Byには、下表の種類を指定できます。
| 定数 | 対象 |
|---|---|
| ID | id属性 |
| XPATH | XPath |
| LINK_TEXT | リンクとして表示されているテキスト |
| PARTIAL_LINK_TEXT | リンクとして表示されているテキストの一部 |
| NAME | name属性 |
| TAG_NAME | HTMLタグ名 |
| CLASS_NAME | クラス名 |
| CSS_SELECTOR | CSSセレクタ |
XPathやCSSセレクタを用いれば、複雑な条件で一致させられます。
elements = driver.find_elements(By.XPATH, "//a[starts-with(@href, 'http://example.com/')]")
一致する要素がなかったときには空のリストが返されるか、「no such element: Unable to locate element」としてNoSuchElementExceptionが投げられます。NoSuchElementException - Understanding Common Errors | Selenium
これを処理するにはNoSuchElementExceptionをインポートした上で、exception - python selenium webscraping "NoSuchElementException" not recognized - Stack Overflow
from selenium.common.exceptions import NoSuchElementException
それをexceptで処理します。
element = []
try:
element = driver.find_element(By.ID, "test")
except NoSuchElementException:
pass
if len(element) == 0:
print("no such element")
find_element()では最初に一致した要素だけが返されるため、これをすべての要素とするには複数形のfind_elements()を用います。All matching elements - Finding web elements | Selenium
items = driver.find_elements(By.TAG_NAME, "li")
要素をクリックしたり、キーを送信したりできます。Interacting with web elements | Selenium
要素をクリックできます。
check_input = driver.find_element(By.NAME, "checkbox_input") check_input.click()
要素の可視、有効、選択状態やタグ名などを取得できます。Information about web elements | Selenium
| メソッド | 機能 |
|---|---|
| is_displayed() | 要素が表示されているならば、Trueを返す |
| is_enabled() | 要素が有効ならば、Trueを返す |
| is_selected() | 要素が選択されているならば、Trueを返す |
描画されているテキストを取得できます。Text Content - Information about web elements | Selenium
element.text
要素の属性を取得できます。Fetching Attributes or Properties - Information about web elements | Selenium
element.get_attribute("href")
アップロード ダイアログを操作することはできないため、ダイアログを開かずにアップロードする必要があります。たとえばtypeがfileであるinput要素にファイルのパスを入力し、送信をクリックします。File Upload | Selenium
リンクをクリックすることでダウンロードを開始することはできますが、その進捗や、ダウンロードされたファイルを検証することはできません。よってその必要があるならば、リンクの情報を他のライブラリに渡して処理します。File downloads | Selenium
driver.find_element(By.TAG_NAME , "a").click()
ファイル名を指定してダウンロードすることはできないため、ダウンロードの完了を待ってからファイル名を変更します。python - Selenium give file name when downloading - Stack Overflow
ダウンロードの完了を待たずにブラウザを閉じるとファイルが不完全な状態となるため、それを待つか、ブラウザを閉じないようにします。
保存先は、ブラウザのオプションを指定することで変更できます。
prefs = {"download.default_directory" : r"C:\Downloads"}
options = webdriver.ChromeOptions()
options.add_experimental_option("prefs",prefs)
driver = webdriver.Chrome(options)
changing default download location in chrome using Python selenium - Stack Overflow
この方法が使用できない、または実行時に動的に変更するにはCDP Commandで指定します。[py] add execute_cdp_cmd to Remote by Delta456 · Pull Request #14809 · SeleniumHQ/selenium · GitHub
params = {"behavior": "allow", "downloadPath": r"C:\Downloads"}
driver.execute_cdp_cmd("Page.setDownloadBehavior", params)
Custom Download Path Not Working with undetected_chrome · Issue #1935 · ultrafunkamsterdam/undetected-chromedriver
Source: chromium.js
ただしこのCDP (Chrome DevTools Protocol) は、新しいWebDriver BiDiが提供されると使用できなくなる恐れがあります。Chrome DevTools Protocol | Selenium