見出し画像

Le Selenium avec P02:elementをみつける

【0】はじめに

 今回はSeleniumをつかって、「HTML内の要素(element)」をみつける操作までを実施する。

 人間がブラウザを操作する時は、まず自分の目で「入力エリア」や「ボタン」の位置を確認して、次にフォーカスを当てて、「キー入力操作」や「クリック操作」をしている。

 同じことをプログラム(Selenium)上で実行するためには、まず最初にHTMLドキュメント内から要素(element)をプログラムで検出する。

画像1

 検出した「要素(element)」は、「WebElementオブジェクト」として属性値(htmlタグの設定内容)を取得する、クリック処理する、といった操作をプログラミングできる。

【1】find_element_by_〇〇〇でelementを見つける

■ブラウザを起動してHTMLの構造を確認する
Seleniumで「要素(element)」を見つけるにあたって、まずはブラウザを起動して対象のページのHTML構造を確認する。

画像2


■WebDriver.find_element_by_〇〇〇メソッド
Seleniumでは「find_element_by_〇〇〇メソッド」を使ってHTML内の要素(element)検出することができる。

使用できるメソッドは次の通り。
・find_element_by_id(id)
・find_element_by_name(name)
・find_element_by_class_name(name)
・find_element_by_tag_name(name)
・find_element_by_xpath(xpath)
・find_element_by_css_selector(css_selector)
・find_element_by_link_text(link_text)
・find_element_by_partial_link_text(link_text)

「find_elements_by_〇〇」のように「s」をつけると該当するelementを複数取得できる。

例1:「Usernameのテキストエリア」を「name属性で検出する」

画像3

検出した「WebElementオブジェクト」から、そのelement内の別の属性値を取得することもできる。

画像4


■例2:検出したelement内にあるsize属性の値を取得する

from selenium import webdriver
import chromedriver_binary # pipでいれたのでこれが必要


driver = webdriver.Chrome()

# 10秒の暗黙ウェイト
driver.implicitly_wait(10)

driver.get('http://localhost:8080/login.php')

# name で探したelementから別の属性値を取得
username_field = driver.find_element_by_name("username")
print(username_field.get_attribute("size"))

出力結果:

20

■例3:find_elements_by_tag_nameで複数要素を取得する「find_elements_by_〇〇」のように「s」をつけて複数要素を取得してみる。今回は「各inputタグのelement」を取得して「それぞれname属性」を出力してみる。

画像5

input_fields = driver.find_elements_by_tag_name('input')
for el in input_fields:
   print(el.get_attribute("name"))

出力結果:

username
password
Login
user_token

【2】XPathを使う

Seleniumでelementを一意に特定するにはちょうどいいid属性やname属性がない場合、XPathを使って検索することもできる。XPathはXML文書(HTML含む)のノードを検索するためのクエリー言語。

■使い方:XPathの取得の仕方
ブラウザからコピー操作をすればよい。XPathには「絶対パス」と「相対パス」があるが相対パスを使う方が便利。

画像6

例えば「Password欄のXPath」は以下のようなものが取得できる

# 相対パスのXPath
//*[@id="content"]/form/fieldset/input[2]

# 絶対パスのXPath
/html/body/div/div[2]/form/fieldset/input[2]

あとは「find_element_by_xpath()」で取得すればよい。
■例4:Password欄のname属性を取得する

password_fields = driver.find_element_by_xpath('//*[@id="content"]/form/fieldset/input[2]')
print(password_fields.get_attribute("name"))

出力結果:

password

【3】ここまでの全体コード

name属性での取得、tag名での複数取得、XPathでの取得についてまとめた全体コードは以下のような感じ。

from selenium import webdriver
import chromedriver_binary # pipでいれたのでこれが必要


driver = webdriver.Chrome()


# 10秒の暗黙ウェイト
driver.implicitly_wait(10)

driver.get('http://localhost:8080/login.php')


# name 要素から探す
username_field = driver.find_element_by_name("username")
print(username_field.get_attribute("size"))


# inputタグをすべて探してname要素の値を出力する
input_fields = driver.find_elements_by_tag_name('input')
for el in input_fields:
   print(el.get_attribute("name"))

print("--------")

# xpathで指定する
password_fields = driver.find_element_by_xpath('//*[@id="content"]/form/fieldset/input[2]')
print(password_fields.get_attribute("name"))

driver.quit()

出力結果:

20
username
password
Login
user_token
--------
password

【おまけ】要素を検出できなかった場合の例外エラー:NoSuchElementException

Seleniumでは「find_element_by_〇〇〇」で一致する要素が見つけられなかった場合、「NoSuchElementException」という「例外」を発出する。

そのため、try-exceptで例外を捕捉して何らかの処理をする、といったこともできる。(例えば、Webアプリの自動テストで例外が発生した時点で画面キャプチャする、等)

■例:例外を検知して終了する

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

... ...


try:
   email_field = driver.find_element_by_name("email")
except NoSuchElementException:
   print("can not find element")
   
   #driver.save_screenshot("error.png")
   #raise
   
   driver.quit()

もっと応援したいなと思っていただけた場合、よろしければサポートをおねがいします。いただいたサポートは活動費に使わせていただきます。