各言語でのfind_elementとfind_elementsの違い

概要

Seleniumには、PythonやRubyでは

  1. find_element
  2. find_elements

Java系では

  1. findElement
  2. 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