各言語でのfind_elementとfind_elementsの違い
概要
Seleniumには、PythonやRubyでは
- find_element
- find_elements
Java系では
- findElement
- findElements
という、よく似たメソッドがあります。
【A.find_element / findElement】が指定したロケータにマッチする要素(WebElement)を返すのに対し、
【B.find_elements / findElements】は取得した要素の配列(list/collection)を返します。
各タグとも、idは一意、classは「link」で共通です。
各言語での記述方法
XPathで要素を取得する場合のコード例を記述します。
Python
driver.find_element_by_xpath('要素のXPath')
driver.find_elements_by_xpath('要素のXPath') #引用符は「"」又は「'」
Java
driver.findElement(By.xpath('要素のXPath'));
driver.findElements(By.xpath('要素のXPath')); //引用符は「"」
C#
driver.FindElement(By.XPath("要素のXPath")); //XPath
driver.FindElements(By.XPath("要素のXPath")); //引用符は「"」
Ruby
driver.find_element(:xpath, '要素のXPath')
driver.find_elements(:xpath, '要素のXPath') #引用符は「"」又は「'」
JavaScript
driver.findElement(By.xpath('要素のXPath'));
driver.findElements(By.xpath('要素のXPath')); //引用符は「"」又は「'」
Python
サンプルコード
Seleniumでテストページの要素を取得してクリックする処理を、Pythonで書くと以下のようになります。
# -*- coding:utf-8 -*- from selenium import webdriver driver_path = r'D:\Selenium\driver\chromedriver.exe' driver = webdriver.Chrome(executable_path=driver_path) driver.get("https://selenium-world.net/page/test_link1.html"); #find_element element = driver.find_element_by_xpath('//a[@class="link"]') #find_elements elements = driver.find_elements_by_xpath('//a[@class="link"]') elements[0].click() driver.quit()
通常、動作確認のたびにスクリプトを書き換えて、Seleniumを再起動する必要があります。CodeCheckerを使用すれば、ブラウザを開いたまま、繰り返しコードを実行できます。
ケース1(find_element)
まず【A.find_element】でclassを指定します。
CodeCheckerのコード欄に、コードを入力して、「Code」ボタンを押すと、結果が表示されます。
入力コード
driver.find_element_by_xpath('//a[@class="link"]')
戻り値
<selenium.webdriver.remote.webelement.WebElement (session="4eabe4f404fb3885f85c1142eb8bd621", element="8ca5f5d4-5e0a-4567-b769-9f90f6b5a902")>
該当する要素は5個ありますが、戻り値は1個のWebElementです。
このようにSeleniumの【A.find_element】は指定したロケータで複数の要素がヒットする場合、最初に見つかった要素を返します。
ケース2(find_elements)
続いて【B.find_elements】でclass指定します。
入力コード
driver.find_elements_by_xpath('//a[@class="link"]')
戻り値
[<selenium.webdriver.remote.webelement.WebElement (session="4eabe4f404fb3885f85c1142eb8bd621", element="8ca5f5d4-5e0a-4567-b769-9f90f6b5a902")>, <selenium.webdriver.remote.webelement.WebElement (session="4eabe4f404fb3885f85c1142eb8bd621", element="b763fa4c-621a-4989-b4cb-fa099d55bf3a")>, <selenium.webdriver.remote.webelement.WebElement (session="4eabe4f404fb3885f85c1142eb8bd621", element="a3bfa971-be58-4105-8bd0-2f5cb2e61a71")>, <selenium.webdriver.remote.webelement.WebElement (session="4eabe4f404fb3885f85c1142eb8bd621", element="97bed18b-aa45-4b7a-8bbb-526a0b246a3e")>, <selenium.webdriver.remote.webelement.WebElement (session="4eabe4f404fb3885f85c1142eb8bd621", element="b97ad028-8fee-40fb-a2ee-669763f7cca0")>]
【B.find_elements】の場合は、[要素1,要素2,要素3…]のように、該当する要素すべてがリスト(配列)として返されます。
戻り値の型
入力コード
type(driver.find_elements_by_xpath('//a[@class="link"]')) #戻り値の型を取得
出力結果
<class 'list'> #listオブジェクト
リストの要素
【B.find_elements】で要素を操作するには、返されたlist(配列)から、個々の要素を取得する必要があります。
入力コード
driver.find_elements_by_xpath('//a[@class="link"]')[0]
戻り値
<selenium.webdriver.remote.webelement.WebElement (session="4eabe4f404fb3885f85c1142eb8bd621", element="8ca5f5d4-5e0a-4567-b769-9f90f6b5a902")>
WebElementが返されます。
ケース3(find_elementsで0件)
【B.find_elements】で要素が取得できない(0件)の場合は、どうなるでしょうか?
入力コード
driver.find_elements_by_xpath('//a[@class="xxxx"]')
戻り値
[]
このように空のリスト(配列)が戻ってきます。この時点では、例外は発生しません。
リスト要素の取得
この空のリストから要素を取り出そうとすると、例外が発生します。
入力コード
driver.find_elements_by_xpath('//a[@class="xxxx"]')[0]
出力結果
IndexErrorlist index out of range<traceback object at 0x000001EB8EAF21C8>
これはSeleniumの例外ではなく、listオブジェクトの例外です。
ケース4(find_elementで要素なし)
なお、【A.find_element】で要素を取得できない場合は、例外が発生します。
入力コード
driver.find_element_by_xpath('//a[@class="xxxx"]')
出力結果
NoSuchElementExceptionMessage: no such element: Unable to locate element: {"method":"xpath","selector":"//a[@class="xxxx"]"}
(Session info: chrome=83.0.4103.116)
<traceback object at 0x000001EB8EAF2348>
Seleniumの例外です。
ケース5(要素の操作)
find_element
【A.find_element】で要素を操作するには、返されたWebElementを操作します。
入力コード
driver.find_element_by_xpath('//a[@id="link1"]').click()
find_elements
【B.find_elements】で要素を操作するには、返されたlistオブジェクトから要素を取得します。
入力コード
driver.find_elements_by_xpath('//a[@id="link1"]')[0].click()
find_elementsの例外
【B.find_elements】で返されたリストをそのまま扱うことはできません。
入力コード
driver.find_elements_by_xpath('//a[@id="link1"]').click()
出力結果
AttributeError'list' object has no attribute 'click'<traceback object at 0x000001EB8EAF2F88>
WebElementではなく、listオブジェクトにはclickメソッドは存在しないので、例外が発生します。
要素の存在チェック
【B.find_elements】は、指定したロケータに該当する要素が存在しない場合(0件)でも、例外が発生しません。よって、要素の存在チェックに使用できます。
入力コード
list1 = driver.find_elements_by_xpath('//a[@class="xxxx"]')
print(len(list1))
if len(list1) == 0:
print("No Element")
出力結果
0
No Element
繰り返し
【B.find_elements】は要素をlist(配列)に格納するのでループ処理で利用できます。
サンプル1
入力コード
list1 = driver.find_elements_by_xpath('//a[@class="link"]')
for element in list1:
print(element.text)
出力結果
Link1
Link2
Link3
Link4
Link5
サンプル2
入力コード
list1 = driver.find_elements_by_xpath('//a[@class="link"]')
i=0
while i < len(list1):
print(list1[i].text)
i += 1
出力結果
Link1
Link2
Link3
Link4
Link5
Java
サンプルコード
package example.test; import java.util.*; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; public class App { public static void main( String[] args ) { System.setProperty("webdriver.chrome.driver", "D:\\Selenium\\driver\\chromedriver.exe"); WebDriver driver = new ChromeDriver(); driver.get("https://selenium-world.net/page/test_link1.html"); //findElement WebElement element = driver.findElement(By.xpath("//a[@class='link']")); //findElements ArrayList<WebElement> elements = new ArrayList<WebElement> (driver.findElements(By.xpath("//a[@class='link']"))); elements.get(0).click(); driver.quit(); } }
必要に応じてコードを書き換えて、動作確認します。
ケース1(findElement)
まず【A.findElement】でclassを指定します。
入力コード
System.out.println(driver.findElement(By.xpath("//a[@class='link']")));
System.out.println(driver.findElement(By.xpath("//a[@class='link']")).getClass().getName());
出力結果
[[ChromeDriver: chrome on WINDOWS (63c99009f44b79608809e2577a90fe8c)] -> xpath: //a[@class='link']]
org.openqa.selenium.remote.RemoteWebElement
該当する要素は5個ありますが、戻り値は1個のRemoteWebElementです。
このようにSeleniumの【A.findElement】は指定したロケータで複数の要素がヒットする場合、最初に見つかった要素を返します。
ケース2(findElements)
続いて【B.findElements】でclass指定します。
入力コード
System.out.println(driver.findElements(By.xpath("//a[@class='link']")));
System.out.println(driver.findElements(By.xpath("//a[@class='link']")).getClass().getName());
出力結果
[[[ChromeDriver: chrome on WINDOWS (63c99009f44b79608809e2577a90fe8c)] -> xpath: //a[@class='link']], [[ChromeDriver: chrome on WINDOWS (63c99009f44b79608809e2577a90fe8c)] -> xpath: //a[@class='link']], [[ChromeDriver: chrome on WINDOWS (63c99009f44b79608809e2577a90fe8c)] -> xpath: //a[@class='link']], [[ChromeDriver: chrome on WINDOWS (63c99009f44b79608809e2577a90fe8c)] -> xpath: //a[@class='link']], [[ChromeDriver: chrome on WINDOWS (63c99009f44b79608809e2577a90fe8c)] -> xpath: //a[@class='link']]]
java.util.ArrayList
【B.findElements】の場合は、該当する要素すべてがArrayListとして返されます。
リストの要素
【B.findElements】で要素を操作するには、返されたArrayListから、個々の要素を取得する必要があります。
入力コード
System.out.println(driver.findElements(By.xpath("//a[@class='link']")).get(0));
System.out.println(driver.findElements(By.xpath("//a[@class='link']")).get(0).getClass().getName());
出力結果
[[ChromeDriver: chrome on WINDOWS (38543984b6bf0654417de6d77dfa0a3e)] -> xpath: //a[@class='link']]
org.openqa.selenium.remote.RemoteWebElement
RemoteWebElementが返されます。
ケース3(findElementsで0件)
【B.findElements】で要素が取得できない(0件)の場合
入力コード
System.out.println(driver.findElements(By.xpath("//a[@class='xxxx']")));
System.out.println(driver.findElements(By.xpath("//a[@class='xxxx']")).getClass().getName());
出力結果
[]
java.util.ArrayList
空のArrayListが戻ってきます。この時点では、例外は発生しません。
リスト要素の取得
この空のリストから要素を取り出そうとすると、例外が発生します。
入力コード
driver.findElements(By.xpath("//a[@class='xxxx']")).get(0);
出力結果
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
これはSeleniumの例外ではなく、Javaの例外です。
ケース4(findElementで要素なし)
【A.findElement】で要素を取得できない場合は、例外が発生します。
入力コード
driver.findElement(By.xpath("//a[@class='xxxx']"));
出力結果
Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//a[@class='xxxx']"}
(Session info: chrome=84.0.4147.89)
For documentation on this error, please visit: https://www.seleniumhq.org/exceptions/no_such_element.html
Seleniumの例外です。
ケース5(要素の操作)
findElement
【A.findElement】で要素を操作するには、返されたWebElementを操作します。
入力コード
WebElement element = driver.findElement(By.xpath("//a[@class='link']"));
element.click();
findElements
【B.findElements】で要素を操作するには、返されたArrayListから要素を取得します。
入力コード
driver.findElements(By.xpath("//a[@class='link']")).get(0).click();
findElementsの例外
【B.findElements】で返されたArrayListをそのまま扱うことはできません。
入力コード
driver.findElements(By.xpath("//a[@class='link']")).click();
上記のコードはコンパイルできません。
要素の存在チェック
【B.findElements】は、指定したロケータに該当する要素が存在しない場合(0件)でも、例外が発生しません。よって、要素の存在チェックに使用できます。
入力コード
ArrayList<WebElement> elements = new ArrayList<WebElement>
(driver.findElements(By.xpath("//a[@class='xxxx']")));
if (elements.size() == 0){
System.out.println("No Element");
}
出力結果
No Element
繰り返し
【B.findElements】は要素をArrayListに格納するのでループ処理で利用できます。
サンプル1
入力コード
ArrayList<WebElement> elements = new ArrayList<WebElement>
(driver.findElements(By.xpath("//a[@class='link']")));
for(WebElement element:elements){
System.out.println(element.getText());
}
出力結果
Link1
Link2
Link3
Link4
Link5
サンプル2
入力コード
ArrayList<WebElement> elements = new ArrayList<WebElement>
(driver.findElements(By.xpath("//a[@class='link']")));
int i=0;
while(i < elements.size()){
System.out.println(elements.get(i).getText());
i++;
}
出力結果
Link1
Link2
Link3
Link4
Link5
C#
サンプルコード
using System; using System.Collections.ObjectModel; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; namespace SampleTest { class Program { static void Main(string[] args) { String path = @"D:\Selenium\driver"; //C#はフォルダを指定 IWebDriver driver = new ChromeDriver(path); driver.Navigate().GoToUrl ("https://selenium-world.net/page/test_link1.html"); //FindElement IWebElement element = driver.FindElement(By.XPath("//a[@class='link']")); //FindElements ReadOnlyCollection<IWebElement> elements = driver.FindElements(By.XPath("//a[@class='link']")); elements[0].Click(); driver.Quit(); } } }
必要に応じてコードを書き換えて、動作確認します。
ケース1(FindElement)
まず【A.FindElement】でclassを指定します。
入力コード
Console.WriteLine(driver.FindElement(By.XPath("//a[@class='link']")));
Console.WriteLine(driver.FindElement(By.XPath("//a[@class='link']")).GetType());
出力結果
Element (id = 912f4746-132d-492c-9b9d-848538848478)
OpenQA.Selenium.Remote.RemoteWebElement
該当する要素は5個ありますが、戻り値は1個のRemoteWebElementです。
このようにSeleniumの【A.FindElement】は指定したロケータで複数の要素がヒットする場合、最初に見つかった要素を返します。
ケース2(FindElements)
続いて【B.FindElements】でclass指定します。
入力コード
Console.WriteLine(driver.FindElements(By.XPath("//a[@class='link']")));
Console.WriteLine(driver.FindElements(By.XPath("//a[@class='link']")).GetType());
ReadOnlyCollection<IWebElement> elements = driver.FindElements(By.XPath("//a[@class='link']"));
foreach(IWebElement element in elements)
{
Console.WriteLine(element);
}
出力結果
System.Collections.ObjectModel.ReadOnlyCollection`1[OpenQA.Selenium.IWebElement]
System.Collections.ObjectModel.ReadOnlyCollection`1[OpenQA.Selenium.IWebElement]
Element (id = 3af8afc8-4292-45b2-bff5-bb4dec3f2dd0)
Element (id = e65f605b-70e8-4a2a-8da4-a662b232c7dc)
Element (id = e6f1c212-ffab-4356-ad8a-2d51f6ed7ebf)
Element (id = a04a78cf-9dd5-4aab-bbbd-398e92b5e64d)
Element (id = 8a539cea-6c9f-4f3b-8443-ab06ecaad4d5)
【B.FindElements】の場合は、該当する要素すべてが格納されたコレクション(データの集合クラス)として返されます。
コレクションの要素
【B.FindElements】で要素を操作するには、返されたコレクション(配列)から、個々の要素を取得する必要があります。
入力コード
Console.WriteLine(driver.FindElements(By.XPath("//a[@class='link']"))[0]);
Console.WriteLine(driver.FindElements(By.XPath("//a[@class='link']"))[0].GetType());
出力結果
Element (id = 27ba3021-0752-4ccd-b0b8-019ffbf914b9)
OpenQA.Selenium.Remote.RemoteWebElement
RemoteWebElementが返されます。
ケース3(FindElementsで0件)
【B.FindElements】で要素が取得できない(0件)の場合
入力コード
Console.WriteLine(driver.FindElements(By.XPath("//a[@class='xxxx']")).GetType());
Console.WriteLine(driver.FindElements(By.XPath("//a[@class='xxxx']")).Count());
出力結果
System.Collections.ObjectModel.ReadOnlyCollection`1[OpenQA.Selenium.IWebElement]
0
要素数0のコレクションが戻ってきます。この時点では、例外は発生しません。
要素の取得
このコレクションから要素を取り出そうとすると、例外が発生します。
入力コード
Console.WriteLine(driver.FindElements(By.XPath("//a[@class='xxxx']"))[0]);
出力結果
例外がスローされました: 'System.ArgumentOutOfRangeException' (mscorlib.dll の中)
型 'System.ArgumentOutOfRangeException' のハンドルされていない例外が mscorlib.dll で発生しました
追加情報:インデックスが範囲を超えています。負でない値で、コレクションのサイズよりも小さくなければなりません。
これはSeleniumの例外ではなく、C#の例外です。
ケース4(FindElementで要素なし)
【A.FindElement】で要素を取得できない場合は、例外が発生します。
入力コード
driver.FindElement(By.XPath("//a[@class='xxxx']"));
出力結果
例外がスローされました: 'OpenQA.Selenium.NoSuchElementException' (WebDriver.dll の中)
型 'OpenQA.Selenium.NoSuchElementException' のハンドルされていない例外が WebDriver.dll で発生しました
追加情報:no such element: Unable to locate element: {"method":"xpath","selector":"//a[@class='xxxx']"}
(Session info: chrome=84.0.4147.89)
Seleniumの例外です。
ケース5(要素の操作)
FindElement
【A.FindElement】で要素を操作するには、返されたWebElementを操作します。
入力コード
IWebElement element = driver.FindElement(By.XPath("//a[@class='link']"));
element.Click();
FindElements
【B.FindElements】で要素を操作するには、返されたコレクションから要素を取得します。
入力コード
driver.FindElements(By.XPath("//a[@class='link']"))[0].Click();
FindElementsの例外
【B.FindElements】で返されたコレクションをそのまま扱うことはできません。
入力コード
driver.FindElements(By.xpath("//a[@class='link']")).click();
上記のコードはコンパイルできません。
要素の存在チェック
【B.FindElements】は、指定したロケータに該当する要素が存在しない場合(0件)でも、例外が発生しません。よって、要素の存在チェックに使用できます。
入力コード
ReadOnlyCollection<IWebElement> elements = driver.FindElements(By.XPath("//a[@class='xxxx']"));
if (elements.Count() == 0)
{
Console.WriteLine("No Element");
}
出力結果
No Element
繰り返し
【B.FindElements】は要素をコレクション(データの集合クラス)に格納するのでループ処理で利用できます。
サンプル1
入力コード
ReadOnlyCollection<IWebElement> elements = driver.FindElements(By.XPath("//a[@class='link']"));
foreach (IWebElement element in elements)
{
Console.WriteLine(element.Text);
}
出力結果
Link1
Link2
Link3
Link4
Link5
サンプル2
入力コード
ReadOnlyCollection<IWebElement> elements = driver.FindElements(By.XPath("//a[@class='link']"));
int i = 0;
while (i < elements.Count())
{
Console.WriteLine(elements[i].Text);
i++;
}
出力結果
Link1
Link2
Link3
Link4
Link5
Ruby
サンプルコード
require "selenium-webdriver" Selenium::WebDriver::Chrome.driver_path = 'D:\Selenium\driver\chromedriver.exe' driver = Selenium::WebDriver.for :chrome driver.get("https://selenium-world.net/page/test_link1.html") #find_element element = driver.find_element(:xpath, '//a[@class="link"]') #find_elements elements = driver.find_elements(:xpath, '//a[@class="link"]') elements[0].click driver.quit
必要に応じてコードを書き換えて、動作確認します。
ケース1(find_element)
まず【A.find_element】でclassを指定します。
入力コード
puts driver.find_element(:xpath, '//a[@class="link"]')
puts driver.find_element(:xpath, '//a[@class="link"]').class
出力結果
#<Selenium::WebDriver::Element:0x0000000007064288>
Selenium::WebDriver::Element
該当する要素は5個ありますが、戻り値は1個のElementです。
このようにSeleniumの【A.find_element】は指定したロケータで複数の要素がヒットする場合、最初に見つかった要素を返します。
ケース2(find_elements)
続いて【B.find_elements】でclass指定します。
入力コード
puts driver.find_elements(:xpath, '//a[@class="link"]')
puts driver.find_elements(:xpath, '//a[@class="link"]').class
puts driver.find_elements(:xpath, '//a[@class="link"]').size
puts driver.find_elements(:xpath, '//a[@class="link"]').length
出力結果
#<Selenium::WebDriver::Element:0x000000000706eeb8>
#<Selenium::WebDriver::Element:0x000000000706ee40>
#<Selenium::WebDriver::Element:0x000000000706edc8>
#<Selenium::WebDriver::Element:0x000000000706ed50>
#<Selenium::WebDriver::Element:0x000000000706ecd8>
Array
5
5
【B.find_elements】の場合は、該当する要素すべてが格納された配列として返されます。
リストの要素
【B.find_elements】で要素を操作するには、返されたArrayクラス(配列)から、個々の要素を取得する必要があります。
入力コード
puts driver.find_elements(:xpath, '//a[@class="link"]')[0]
puts driver.find_elements(:xpath, '//a[@class="link"]')[0].class
出力結果
#<Selenium::WebDriver::Element:0x00000000070b7898>
Selenium::WebDriver::Element
Elementが返されます。
ケース3(find_elementsで0件)
【B.find_elements】で要素が取得できない(0件)の場合
入力コード
puts driver.find_elements(:xpath, '//a[@class="xxxx"]').class
puts driver.find_elements(:xpath, '//a[@class="xxxx"]')
puts driver.find_elements(:xpath, '//a[@class="xxxx"]').size
出力結果
Array
0
要素0の配列が返されます。この時点では、例外は発生しません。
要素の取得
このコレクションの、存在しない要素(NilClass)を操作すると、例外が発生します。
(要素を取り出すだけでは、例外は発生しません)
入力コード
puts driver.find_elements(:xpath, '//a[@class="xxxx"]')[0].class
puts driver.find_elements(:xpath, '//a[@class="xxxx"]')[0]
begin
puts driver.find_elements(:xpath, '//a[@class="xxxx"]')[0].click
rescue => error
puts error
puts error.class
end
出力結果
NilClass
undefined method `click' for nil:NilClass
NoMethodError
これはSeleniumの例外ではなく、Rubyの例外です。
ケース4(find_elementで要素なし)
【A.find_element】で要素を取得できない場合は、例外が発生します。
入力コード
begin
driver.find_element(:xpath, '//a[@class="xxxx"]').click
rescue => error
puts error
puts error.class
end
出力結果
no such element: Unable to locate element: {"method":"xpath","selector":"//a[@class="xxxx"]"}
(Session info: chrome=84.0.4147.89)
Selenium::WebDriver::Error::NoSuchElementError
Seleniumの例外です。
ケース5(要素の操作)
find_element
【A.find_element】で要素を操作するには、返されたElementを操作します。
入力コード
element = driver.find_element(:xpath, '//a[@class="link"]')
element.click
find_elements
【B.find_elements】で要素を操作するには、返された配列から要素を取得します。
入力コード
driver.find_elements(:xpath, '//a[@class="link"]')[0].click
find_elementsの例外
【B.find_elements】で返されたコレクションをそのまま扱うことはできません。
入力コード
begin
driver.find_elements(:xpath, '//a[@class="link"]').click
rescue => error
puts error
puts error.class
end
出力結果
undefined method `click' for #<Array:0x0000000007197600>
NoMethodError
WebDriver::Elementではなく、Arrayクラスですので、NoMethodErrorとなります。
要素の存在チェック
【B.find_elements】は、指定したロケータに該当する要素が存在しない場合(0件)でも、例外が発生しません。よって、要素の存在チェックに使用できます。
入力コード
elements = driver.find_elements(:xpath, '//a[@class="xxxx"]')
if elements.size == 0 then
puts "No Element"
end
出力結果
No Element
繰り返し
【B.find_elements】は要素を配列に格納するのでループ処理で利用できます。
サンプル1
入力コード
driver.find_elements(:xpath, '//a[@class="link"]').each{|element|
puts element.text
}
出力結果
Link1
Link2
Link3
Link4
Link5
サンプル2
入力コード
elements = driver.find_elements(:xpath, '//a[@class="link"]')
i=0
while i < elements.size do
puts elements[i].text
i += 1
end
出力結果
Link1
Link2
Link3
Link4
Link5
JavaScript
サンプルコード
let webdriver = require('selenium-webdriver'); let chrome = require('selenium-webdriver/chrome'); let By = webdriver.By; (async () => { var driver = await new webdriver.Builder() .withCapabilities(webdriver.Capabilities.chrome()) .setChromeService(new chrome.ServiceBuilder( "D:\\Selenium\\driver\\chromedriver.exe") ) .build(); await driver.get("https://selenium-world.net/page/test_link1.html"); //findElement var element = await driver.findElement(By.xpath("//a[@class='link']")); //findElements var elements = await driver.findElements(By.xpath("//a[@class='link']")); await elements[0].click(); await driver.quit(); })();
Node.jsは非同期で処理を行うので、「async/await」で処理の順番を制御しています。前の処理が終わってから、次の処理を動かすようにしています。
ケース1(findElement)
まず【A.findElement】でclassを指定します。
入力コード
console.log(await driver.findElement(By.xpath("//a[@class='link']")));
出力結果
WebElement {driver_: Driver, id_: Promise}
該当する要素は5個ありますが、戻り値は1個のWebElementです。
このようにSeleniumの【A.findElement】は指定したロケータで複数の要素がヒットする場合、最初に見つかった要素を返します。
ケース2(findElements)
続いて【B.findElements】でclass指定します。
入力コード
var elements = await driver.findElements(By.xpath("//a[@class='link']"));
console.log(elements)
console.log(elements.constructor);
出力結果
(5) [WebElement, WebElement, WebElement, WebElement, WebElement]
ƒ Array()
【B.findElements】の場合は、該当する要素すべてが返されます。
await
awaitは『console.log』ではなく『driver』の前に記述します。
入力コード
console.log(await driver.findElement(By.xpath("//a[@class='link']")));
console.log(await driver.findElements(By.xpath("//a[@class='link']")));
await console.log(driver.findElement(By.xpath("//a[@class='link']")));
await console.log(driver.findElements(By.xpath("//a[@class='link']")));
出力結果
WebElement {driver_: Driver, id_: Promise}
(5) [WebElement, WebElement, WebElement, WebElement, WebElement]
WebElementPromise {driver_: Driver, id_: Promise, then: ƒ, catch: ƒ, getId: ƒ}
Promise {<pending>}
配列の要素
【B.findElements】で要素を操作するには、返された配列から、個々の要素を取得する必要があります。
入力コード
var elements = await driver.findElements(By.xpath("//a[@class='link']"));
console.log(elements[0]);
出力結果
WebElement {driver_: Driver, id_: Promise}
WebElementが返されます。
Promise
以下の書き方では、要素は取得できません。
入力コード
console.log(await driver.findElements(By.xpath("//a[@class='link']")));
console.log(await driver.findElements(By.xpath("//a[@class='link']"))[0]);
出力結果
(5) [WebElement, WebElement, WebElement, WebElement, WebElement]
undefined
1行で書きたい場合は、thenメソッドを使う必要があります。
入力コード
console.log(await driver.findElements(By.xpath("//a[@class='link']")).then(elements => elements[0]));
出力結果
WebElement {driver_: Driver, id_: Promise}
ケース3(findElementsで0件)
【B.findElements】で要素が取得できない(0件)の場合
入力コード
console.log(await driver.findElements(By.xpath("//a[@class='xxxx']")));
出力結果
(0) []
空の配列が戻ってきます。この時点では、例外は発生しません。
要素の取得
この配列の、存在しない要素()を操作すると、例外が発生します。
(要素を取り出すだけでは、例外は発生しません)
入力コード
var elements = await driver.findElements(By.xpath("//a[@class='xxxx']"));
try{
console.log(elements[0]);
await elements[0].click();
}catch(e) {
console.log(e.name);
console.log(e.message);
}
出力結果
undefined
TypeError
Cannot read property 'click' of undefined
これはSeleniumの例外ではなく、JavaScriptの例外です。
ケース4(findElementで要素なし)
【A.findElement】で要素を取得できない場合は、例外が発生します。
入力コード
try{
await driver.findElement(By.xpath("//a[@class='xxxx']"));
}catch(e) {
console.log(e.name);
console.log(e.message);
}
出力結果
NoSuchElementError
find_element/index.js:34
no such element: Unable to locate element: {"method":"xpath","selector":"//a[@class='xxxx']"}
(Session info: chrome=84.0.4147.89)
Seleniumの例外です。
ケース5(要素の操作)
findElement
【A.findElement】で要素を操作するには、返されたWebElementを操作します。
入力コード
await driver.findElements(By.xpath("//a[@class='link']")).click();
findElements
【B.findElements】で要素を操作するには、返された配列から要素を取得します。
入力コード
var elements = await driver.findElements(By.xpath("//a[@class='link']"));
await elements[0].click();
//1行で書く場合
await driver.findElements(By.xpath("//a[@class='link']")).then(elements => elements[0].click());
findElementsの例外
【B.findElements】で返された配列をそのまま扱うことはできません。
入力コード
var elements = await driver.findElements(By.xpath("//a[@class='link']"));
try{
await elements.click();
}catch(e) {
console.log(e.name);
console.log(e.message);
}
出力結果
TypeError
elements.click is not a function
要素の存在チェック
【B.findElements】は、指定したロケータに該当する要素が存在しない場合(0件)でも、例外が発生しません。よって、要素の存在チェックに使用できます。
入力コード
var elements = await driver.findElements(By.xpath("//a[@class='xxxx']"));
if (elements.length == 0){
console.log("No Element");
}
出力結果
No Element
繰り返し
【B.findElements】は要素を配列に格納するのでループ処理で利用できます。
サンプル1
入力コード
let map = webdriver.promise.map;
var elements = await driver.findElements(By.xpath("//a[@class='link']"));
var vals = await map(elements, element => element.getText()).then();
vals.forEach(val => console.log(val));
出力結果
Link1
Link2
Link3
Link4
Link5
サンプル2
入力コード
let map = webdriver.promise.map;
var elements = await driver.findElements(By.xpath("//a[@class='link']"));
var vals = await map(elements, element => element.getText()).then();
i=0
while(i < vals.length){
console.log(vals[i]);
i++;
}
出力結果
Link1
Link2
Link3
Link4
Link5
まとめ
Pyhon
A.find_element
要素の取得 | driver.find_element_by_xpath(“XPath") |
戻り値の型 | WebElement |
要素が存在しない | 例外:NoSuchElementException |
要素が2個以上 | 最初に見つかった要素を返す |
B.find_elements
要素の取得 | driver.find_elements_by_xpath(“XPath")[0] |
戻り値の型 | list |
要素が存在しない | [](空のlist) |
要素の件数 | len(driver.find_elements_by_xpath(“XPath")) |
空のlistからの取り出し | 例外:IndexErrorlist index out of range |
listオブジェクトをclick | 例外:AttributeError’list’ object has no attribute 'click’ |
Java
A.findElement
要素の取得 | driver.findElement(By.xpath(“XPath")); |
戻り値の型 | RemoteWebElement |
要素が存在しない | 例外:NoSuchElementException |
要素が2個以上 | 最初に見つかった要素を返す |
B.findElements
要素の取得 | driver.findElements(By.xpath(“XPath")).get(0); |
戻り値の型 | ArrayList |
要素が存在しない | [](空のArrayList) |
要素の件数 | driver.findElements(By.xpath(“XPath")).size(); |
空のArrayListからの取り出し | 例外:IndexOutOfBoundsException |
ArrayListオブジェクトをclick | コンパイルエラー |
C#
A.FindElement
要素の取得 | driver.FindElement(By.XPath(“XPath")); |
戻り値の型 | IWebElement |
要素が存在しない | 例外:NoSuchElementException |
要素が2個以上 | 最初に見つかった要素を返す |
B.FindElements
要素の取得 | driver.FindElements(By.XPath(“XPath"))[0] |
戻り値の型 | Collection |
要素が存在しない | 空のコレクション |
要素の件数 | driver.FindElements(By.XPath(“XPath")).Count() |
空のコレクションからの取り出し | 例外:System.ArgumentOutOfRangeException |
コレクションをclick | コンパイルエラー |
Ruby
A.find_element
要素の取得 | driver.find_element(:xpath, 'XPath’) |
戻り値の型 | Selenium::WebDriver::Element |
要素が存在しない | NoSuchElementError |
要素が2個以上 | 最初に見つかった要素を返す |
B.find_elements
要素の取得 | driver.find_elements(:xpath, 'XPath’)[0] |
戻り値の型 | Array |
要素が存在しない | 空のArray |
要素の件数 | driver.find_elements(:xpath, 'XPath’).size |
driver.find_elements(:xpath, 'XPath’).length | |
空のArrayからの取り出し | NilClass |
Arrayオブジェクトをclick | 例外:NoMethodError:undefined method `click’ for #<Array> |
JavaScript
A.findElement
要素の取得 | await driver.findElement(By.xpath(“//a[@class=’link’]")); |
戻り値の型 | WebElement |
要素が存在しない | 例外:NoSuchElementError |
要素が2個以上 | 最初に見つかった要素を返す |
B.findElements
要素の取得 |
await driver.findElements (By.xpath(“//a[@class=’link’]")) .then(elements => elements[0].click()); |
var elements = await driver.findElements(By.xpath(“//a[@class=’link’]")); await elements[0].click(); |
|
戻り値の型 | Array |
要素が存在しない | 空のArray |
要素の件数 |
await driver.findElements (By.xpath(“//a[@class=’link’]")) .then(elements => elements.length) |
var elements = await driver.findElements(By.xpath(“//a[@class=’link’]")); elements.length;
|
|
空のArrayからの取り出し | undefined |
Arrayオブジェクトをclick | 例外:TypeError |
ディスカッション
コメント一覧
PerlでSeleniumを使っているのですが、Perlのサンプルはありませんでしょうか?
コメントありがとうございます。
残念ながらPerlのコードはございません。
木本様のサイトを拝見させて頂きましたが、Perlも進化しているのですね。
当時は、しばらくCOBOLの開発をしていたので、
classファイルやモジュールを置いただけで動作する
JavaやPerlの登場はインパクトがあったのを覚えています。