Selenium CSSセレクタ・XPath早見表

投稿者: | 2022-01-27
  • 参考:『Selenium実践入門』より
  • 補足資料:『HTML&CSS全辞典』

目次

selen の最初の書き出し。忘れがち。

  • 公式が一番

https://www.selenium.dev/documentation/webdriver/

import time
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager # ドライバのインストール(https://www.selenium.dev/ja/documentation/webdriver/getting_started/install_drivers/)
from selenium.webdriver.chrome.service import Service as ChromeService # Serviceクラスはドライバーの起動と停止を管理
from selenium.webdriver.chrome.options import Options # オプション(https://www.selenium.dev/ja/documentation/webdriver/drivers/options/)
from selenium.webdriver.common.by import By # セレクタ-選択用
from selenium.webdriver.support.ui import WebDriverWait # 明示的な待機用
from selenium.webdriver.support.select import Select # selectタグ選択用
from selenium.webdriver.common.keys import Keys # キー操作だがよく理解してない

# オプション追加
options = Options()
options.add_argument('--start-maximized') # 画面最大化
options.page_load_strategy = 'normal' # デフォルト。きちんと読み込まれるまで待つ

# ドライバの自動インストール(自動)
service = ChromeService(executable_path=ChromeDriverManager().install())
# ドライバの自動インストール(手動)
service = ChromeService(executable_path=r"C:\Users\~~~\chromedriver")

# https://www.selenium.dev/documentation/webdriver/getting_started/first_script/

# <セッションを開始>
driver = webdriver.Chrome(service=service, options=options)

# <Webページを読み込む>
driver.get('https://www.yahoo.co.jp/')

# <ブラウザ情報を取得する>
# https://www.selenium.dev/documentation/webdriver/getting_started/first_script/

# <待機戦略>

# 明示的な待機
WebDriverWait(driver, timeout=10).until(document_initialised)
el = driver.find_element(By.TAG_NAME, "p")

# 暗黙的な待機(暗黙にその時間待ち続ける)(明示的な待機と併用しない)
driver.implicitly_wait(0.5)

# <要素を見つける>

# <要素にアクションを実行>

# <要素情報をリクエスト>

time.sleep(2)

# <セッションを終了する
driver.quit()

MEMO

# 中部電力の検針データ取得
from selenium import webdriver
import time

# Chromeドライバに環境変数が通っていない場合は引数で指定
driver_path = "/Users/***/chromedriver"
driver = webdriver.Chrome(driver_path)

# urlを開く
driver.get("https://miraiz.chuden.co.jp/home/electric/contract/payment/calendar/index.html")

kenshinbi_list = ['n01', 'n02', 'n04', 'n05', 'n06', 'n08', 'n09', 'n10', 'n11', 'n12', 'n13', 'n15', 'n16', 'n17', 'n18', 'n19']

nitteis = driver.find_elements_by_css_selector("h3.c-heading-3.mt-0")

for kenshinbi in kenshinbi_list:
    print(f"===検針日程:{kenshinbi[1:3]}===")
    # div要素>ID「n**」をもつ要素>と同階層にあるdivの1番目>の「下」にあるtd
    kenshinbi = driver.find_elements_by_css_selector(f"div #{kenshinbi} ~div:nth-of-type(1)  td")
    for day in kenshinbi:
        print(day.text)

ブラウザを操作するには

  • Selenium WebDriverのコマンド」を使って、「HTML要素を取得・操作」すればよい

基本の型

from selenium import webdriver
import time

# Chromeドライバに環境変数が通っていない場合は引数で指定
driver_path = "/Users/***/chromedriver"
driver = webdriver.Chrome(driver_path)

# urlを開く
driver.get("https://www.google.co.jp")
time.sleep(3)

driver.quit()
#ヘッドレスの場合
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time

chrome_options = Options()
chrome_options.add_argument("--headless")

driver_path = "/Users/mbp441/Desktop/github/PYTHON/chromedriver"
driver = webdriver.Chrome(executable_path = driver_path, options=chrome_options)
driver.get("http://〜〜〜〜")
time.sleep(3)
driver.quit()
driver.close()
  • その他、必須と言われているもの(?)
# Chrome Optionsの設定
options = Options()
options.add_argument('--headless')                 # headlessモードを使用する
options.add_argument('--disable-gpu')              # headlessモードで暫定的に必要なフラグ(そうち不要になる)
options.add_argument('--disable-extensions')       # すべての拡張機能を無効にする。ユーザースクリプトも無効にする
options.add_argument('--proxy-server="direct://"') # Proxy経由ではなく直接接続する
options.add_argument('--proxy-bypass-list=*')      # すべてのホスト名
options.add_argument('--start-maximized')          # 起動時にウィンドウを最大化する

プロセスを殺す

  • Win:
Get-Process chromedriver
Stop-Process -Name chromedriver
  • Mac
# chromedriverの残っているプロセスを確認
ps aux | grep chromedriver
...
# プロセスIDを指定して終了させてもよいが、プロセス名で一括終了が楽
killall chromedriver
# プロセスは死んだが、画面はのこる(CPUが唸ったまま→落としたら収まる)
# →違う。driver.close()が"できてない"ため。

前提知識(HTML・CSS)

  • あらかじめ知っておくと理解がはやくなる

HTML

<a href="https://aaa.com/">テスト</a>
キーワード説明
タグWebページを作るための命令a
要素内容に「意味」を与える名前a
属性要素に具体的な意味や機能を与える名前href
属性値“https://aaa.com/”

CSS

  • CSS:HTMLの見た目を整えるテキストファイル。要素に対してスタイルを定義する。
  • どこの(セレクタ){ 何を(プロパティ):どうする(値);}
h1 {color: red;}

h1 {
    color: red;
    background-color: yellow;
}

ul,
ol {
    font-size: 1.2em;
    font-weight: normal;
}
キーワード説明
セレクタスタイルを適用する対象を表す(要素、class属性、id属性)
対象の指定方法は多数あり(P210~249)
h1,ul,ol
プロパティ適用するスタイルの種類color,等
id,class,name
(セレクタ)
同じ要素でも別々にCSSを適用するために利用する。タグみたいなもの
(下部参照)

id(セレクタ、属性)

  • 同じwebページで1回のみ
  • 「#」+属性値
  <!-- html -->
  <p id='aaa'>テスト</b>

  <!-- css -->
  #aaa {font-size: 24px;}

class(セレクタ、属性)

  • 同じWebページで複数利用可
  • .(ドット)」+属性値
  <!-- html -->
  <p class='bbb'>テスト1</p>
  <div class='bbb'>テスト2</p>

  <!-- css -->
  .bbb {font-size: 24px;}

name

  • form要素、input要素、等で利用される

CSSの組込み方

  • CSSをHTML文書に組込むには複数ある(P507〜)
    • link要素を使う(外部スタイルシート)
    • link要素を使う(優先・代替スタイルシート)
    • style要素を使う
    • style属性を使う
    • style属性を使う(Webでよく使われている)
  <p>
  私は、<span style="color: green">緑色</span>と<span style="color: red">赤色</span>の組み合わせが好きです。
  </p>

WebDriverコマンド

ブラウザの生成と破棄

操作スクリプト
ChromeDriverの生成driver = webdriver.Chrome(‘ChromeDriverのパス’)
ブラウザの破棄driver.quit()

要素の取得(ロケータ)←ver4から記法が変わった

  • driverで、find_elementする。つまり、要素を検索する
  • 何を使って探すのかが「by_〜」にあたる
  • ここで要素(変数:element)を取得し、それに対し「何をするか」を別で指示する(次項)

公式HPを参照

https://selenium-python.readthedocs.io/locating-elements.html#locating-elements

  • 戻り値:一致する最初の要素
  • ない場合は、NoSuchElementException が起きる
操作スクリプト補足
要素の取得driver.find_element
複数要素の取得driver.find_elements戻り値:リスト
id指定★driver.find_element(By.ID, ‘loginForm’)
name指定driver.find_element(By.NAME, ‘username’)変更される可能性が低い。フォーム上の要素にはidよりnameロケータを使うこと
タグ名指定driver.find_element(By.TAG_NAME, ‘h1’)
クラス名指定driver.find_element(By.CLASS_NAME, ‘content’)
リンクテキスト指定★driver.find_element(By.LINK_TEXT, ‘Continue’)a 要素にのみ利用可。
a 要素以外の要素をテキストで指定して取得したい場合は xpath がよい

〃.get_attribute(‘href’) でURLを取得可
リンクテキスト指定(部分一致driver.find_element(By.PARTIAL_LINK_TEXT, ‘Conti’)
CSSセレクタ指定★→下部参照driver.find_element(By.CSS_SELECTOR, ‘p.content’)
XPath指定★→下部参照driver.find_element(By.XPATH, “/html/body/form[1]”)検索したい要素に適した id または name 属性がない場合に XPath を利用する。XPath はルートからの絶対PATHを示すため、HP構成が少し変わると失敗しやすい。そのため id または name 属性を持つ近くの要素(できれば親要素がよい)を使ったほうがより堅牢。

子孫要素の取得

  • find_elementで取得したelemに対し、さらにfind_element(s)を呼び出すこともできる
  driver.find_element(By.ID, '#root').find_element(By.LINK_TEXT, "次へ").click()

何をするか?

  • find_elementしたelement(要素)に対し、何をするか、をここで指示する

要素の操作

操作スクリプト
クリックするelement.click()
キーを入力するelement.send_keys(‘テスト’)
値をクリアするelement.clear()
プルダウンを選択する(value属性)select = Select(element)
select.select_by_value(‘ja’)
プルダウンを選択する(テキスト)select.select_by_visible_text(‘日本語’)
プルダウンを選択する(インデックス)select.select_by_index(0)
submit(同意、OK)するelement.submit()
  • クリックやキー入力により、PCのマウスやキーボード操作が奪われることはない
  • Ctrl+Vも可能だが、ALT+TABなどOSレベルのショートカットは基本的に効かないためため、HTML要素の外側へのキー入力は避ける

プルダウン選択

<!-- プルダウンHTML -->
<select name="num">
<option value="">プルダウン選択</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
# 手順
# 1.Selectをimport
# 2.プルダウン要素からSelectインスタンスを取得
# 3.select_by_value等のメソッドで操作

from selenium.webdriver.support.ui import Select

element = driver.find_element(By.NAME, "num")
select_num = Select(element)

# 複数選択も可
select_num.select_by_value('1')
select_num.select_by_value('2')

# select_by_index、select_by_visible_textもある(?)

# XPathだと項目の要素を直接指定し選択が可能+選択されているかの(事前)判定もできる
element = driver.find_element(By.XPATH, "html/body/form/select/option[2]")
element.click()

print(element.is_selected())

チェックボックス選択

<!-- HTML -->
<input type=radio name="hotice" value="hot">ホット
<input type=radio name="hotice" value="ice">アイス
# Xpath
element = driver.find_element(By.XPATH, "/html/body/form/input[1]")
element.click()

# cssセレクタ
element = driver.find_element(By.CSS_SELECTOR, "input[type=radio][value='hot']")
element.click()
# 判定(選択されていればTrue)
print(element.is_selected())

ラジオボタン選択

<!-- HTML -->
<input type=checkbox name="included" value="sugar">砂糖
<input type=checkbox name="included" value="milk">ミルク
chk_sugar = driver.find_element(By.CSS_SELECTOR, "input[name='included'][value='sugar']")
chk_sugar.click()

# 複数を選択する場合は、同じ書き方で複数記載すればよいが、elements_by〜を使用すると簡単
elements = driver.find_elements(By.CSS_SELECTOR, "input[name='included']")
elements[0].click()
elements[1].click()

要素情報の取得

https://selenium-python.readthedocs.io/api.html?highlight=element.is_displayed()#selenium.webdriver.remote.webelement.WebElement.is_displayed

操作スクリプト説明
表示・非表示element.is_displayed()要素がブラウザ上で表示されているかどうか
有効・無効element.is_enabled()要素が有効状態かどうか
選択状態element.is_selected()チェックボックス、ラジオボタン、プルダウンのoptionが選択されているかどうか
属性element.get_attribute(‘value’)要素の任意の属性を取得。存在しない場合はnullが返る
テキストelement.text要素のインナーテキストを取得
タグ名element.tag_name
CSSプロパティelement.value_of_css_property(‘float’)要素のCSSプロパティ値を取得
サイズelement.size[‘height’]
element.size[‘width’]
要素の高さと幅を取得
位置element.location[‘x’]
element.location[‘y’]
要素の位置を取得。Webページの左上からの座標で取得
  • 要素が存在するかどうか
  • 複数の場合。1つであればelem.is_enabledとかかな?
  • find_elementsで取得したリストの長さ > 0 →True
  if len(driver.find_elements_by_id('test') > 0) :
      # driver.find_elements_by_id('test'):でもいけるはず
      element = driver.find_element_by_id('test')
      # 存在する時の処理
  else:
      # 存在しない時の処理

表示・非表示

ブラウザ情報

操作スクリプト説明
タイトルdriver.title
URLdriver.current_url
HTMLソースdriver.page_source
ウィンドウ位置driver.get_window_position()[‘x’]
driver.get_window_position()[‘y’]
現在のブラウザウィンドウの位置を取得。画面の左上からの座標で取得。setPosition?で位置を移動できる?
ウィンドウサイズdriver.get_window_size()[‘height’]
driver.get_window_size()[‘width’]
setSize?を使うとサイズを変更できる?maximize?で最大化?
Cookieの取得driver.get_cookie(‘sessionId’)取得できるのは現在表示中のページからアクセスできるCookieのみ
Cookieの追加cookie = {‘name’: ‘sessionId’, ‘value’: ‘*‘}
driver.add_cookie(cookie)
Cookieの削除driver.delete_cookie(‘sessionId’)
Cookieの全削除driver.delete_all_cookies()

Cookieオブジェクトのメソッド(確認中)

メソッド返り値説明
getNameStringCookieの名前を取得
getVaueStringCookieの値を取得
getExpiryDateCookieの「expires」の値を取得
getDomainStringCookie「domain」の値を取得
getPathStringCookie「path」の値を取得
isSecurebooleanCookieの「secure」の有無を取得

ブラウザ操作

操作スクリプト説∫明
画面キャプチャdriver.get_screenshot_as_file(‘〜.png’)
driver.save_screenshot(‘〜.png’)
2つの違いが?
JSの実行driver.execute_script(“return arguments[0] + arguments[1];”, 1, 2)
URL遷移driver.get(‘http://***’)
戻るdriver.back()
進むdriver.forward()
リロードdriver.refresh()

スクリーンキャプチャ

from selenium import webdriver
import time
url = "http://www.aaa.co.jp/"
driver = webdriver.Chrome(〜〜〜)
driver.get(url)

# 画面キャプチャ(ファイル名のみの場合はカレントに保存される)
driver.save_screenshot("screenshot.png")
save_screenshot

time.sleep(3)
driver.quit()

# 縦に長いページを取得-------------------------------------------------------
# 1.headlessモードにする
# 2.ウィンドウサイズをブラウザ表示域にする

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

# headlessモードにする
options = Options()
options.add_argument('--headless')

url = "https://www.yahoo.co.jp"

drive_path = "/Users/mbp441/Desktop/github/PYTHON/chromedriver"

driver = webdriver.Chrome(drive_path, options=options)

driver.get(url)

# ウィンドウサイズをブラウザ表示域にする
w = driver.execute_script("return document.body.scrollWidth;")
h = driver.execute_script("return document.body.scrollHeight;")
driver.set_window_size(w,h)

driver.save_screenshot("/Users/mbp441/Desktop/screenshot_full.png")

time.sleep(3)
print("終了")
driver.quit()

JavaScriptの実行

  • executeScriptメソッドを使うとWebDriverスクリプト中からJSの処理を呼び出すことができる。
  • いったん割愛(P76〜)

待ち処理

操作スクリプト説明
Implicit Waitdriver.implicitly_wait(30)暗黙的な待機
Explicit Waitwait = WebDriverWait(driver, 60)
Wait.until(expected_conditions.visibility_of_element_located(By.ID, ‘message’)
明示的な待機

暗黙的な待機

  • 設定すると、全てのfind_elememt等の処理時に、要素が見つかるまで指定した最大時間待機する
  • 時間内に見つかった場合は、残りの時間を無視して次の処理に移る
# Chrome Driverを起動する
driver = webdriver.Chrome(executable_path=driver_path, chrome_options=options)

# 要素が見つかるまで、最大10秒間待機する
driver.implicitly_wait(10)

明示的な待機

  • 暗黙的な待機(implicitly_wait)で対応しきれなかった処理に対して、WebDriverWait.untilメソッドは、任意の要素が特定の状態になるまで待つ明示的な待機時間を設定する
  • 下記の例だと、指定した要素がDOM上に現れるまで10秒待機する、の意
from selenium import webdriver
from selenium.webdriver.comon.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.ChromeDriver(〜)
drive.get("http://www.aaa.co.jp/)

# 指定された条件に合致する要素が見つかるまで最大10秒待機
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()

〜するまで待つ

メソッド説明
alert_is_presentAlertが表示されるまで待機する
element_to_be_clickable要素がクリックできる状態になるまで待機する
visibility_of_element_located指定した要素が表示されるまで待機する
invisibility_of_element_located指定した要素が非表示になるまで待機する
text_to_be_present_in_element指定したテキストが表示されるまで待機する
presence_of_element_located指定した要素がDOM上に現れるまで待機する

ポップアップ・ウィンドウ・フレーム

操作スクリプト
Alert・ConfirmダイアログAlert(driver).accept()
Promptダイアログprompt_dialog = Alert(driver)
prompt_dialog.send_keys(‘入力テキスト’)
prompt_dialog.accept()
ウィンドウ変更driver.switch_to.window(‘reserveWindow’)
ウィンドウを閉じるdriver.close()
フレーム変更driver.swicth_to.frame(‘sample1’)
最上位ページまで戻るdriver.swicth_to.default_content()

アクション

操作スクリプト
WクリックActionChains(driver).double_click(element).perform()
右クリックActionChains(driver).context_click(element).perform()
マウス移動ActionChains(driver).move_to_element(element).perform()
ドラッグ&ドロップActionChains(driver).drag_and_drop(src_element,
target_element).perform()
キーを押しながらクリックActionChains(driver).key_down(Keys.SHIFT).click(element1).
click(element2).key_up(Keys.SHIFT).perform()
  • 上記の操作によりPCのマウスやキーボード操作が奪われることはない

要素の取得

CSSセレクタ

  • タグ > 属性(id、class、name、valueなど多数)
  • 対象の要素をどう選択するか?が大事。

タグ(型)セレクタ

CSSセレクタ説明(何を指すか)
inputタグが input の要素

idセレクタ 「#」

CSSセレクタ説明
# user属性が id「user」の要素

classセレクタ 「.」

CSSセレクタ説明
.logo属性が class=’logo’ の要素
div.logoタグが div で class=’logo’ の要素
div.logo.contentタグが div かつ 「属性が class=’logo’ と ‘content’ の両方を含む」要素

属性セレクタ […]

CSSセレクタ説明
input[value=’テスト’]input タグ かつ 属性が value=’テスト’ の要素
a[title=’テスト’]a タグ かつ 属性が title=’テスト’ の要素
[value=’テスト’]属性が value=’テスト’ の要素
input[value^=’テスト’]input タグ かつ 属性 value が「テスト」で始まる要素
input[value$=’テスト’]input タグ かつ 属性 value が「テスト」で終わる要素
input[value*=’テスト’]input タグ かつ 属性 value が「テスト」を含む要素
input[name=’radio’][value=’on’]input タグ かつ 属性 name=’radio’ かつ value=’on’ の要素

属性セレクタではHTMLの任意の属性を指定できる

子セレクタ

  • その下にある要素ではなく、直下の要素を指す
CSSセレクタ説明
#root > div属性 id が「root」の”直下“にあるdivタグの要素
#root > div > a属性 id が「root」の”直下”にあるdivタグ、その直下にあるaタグの要素

子孫セレクタ

  • その下側にある要素を指す
CSSセレクタ説明
#root div属性 id が「root」の”“にあるdiv タグの要素
#root div .content属性 id が「root」の “下”にある dvi タグ、その下にある属性 class 「content」の要素

隣接セレクタ

CSSセレクタ説明
#root + h1属性 id が「root」の要素と同階層の、直後にあるh1タグの要素

間接セレクタ

CSSセレクタ説明
#root ~h1

nth-of-type

CSSセレクタ説明
#root > div:nth-of-type(2)id「root」の要素の直下にあるdivタグの要素のうち2番目のもの。番号は1始まり

XPath

属性・テキスト指定

  • //から始まる
XPath説明
//imgすべてのimg要素
//*[@id=’next’]id「next」の要素
//a[@id=’next’]id「next」のa要素
//div[@class=’content main’]class属性の値が「content main」のdiv要素
//input[@name=’radio’][@value=’on’]name「radio」かつvalue「on」のinput要素
//div[text()=’テスト’]インナーテキストが「テスト」のdiv要素
//div[text()=’テスト’ and @id=’test’]インナーテキストが「テスト」かつid「test」のdiv要素
//a[starts-with(text(), ‘テスト’)]インナーテキストが「テスト」から始まるa要素
//a[contains(text(), ‘テスト’)]インナーテキストに「テスト」を含むa要素
//div[@class=”station” and contains(@title, “地点名:東京”)]class属性の値が「station」かつtitle属性の値に「地点名:東京」を含むdiv要素
(//div[text()=’テスト’])[1]インナーテキストが「テスト」のdiv要素のうち1番目のもの。番号は1始まり
  • 「@属性名」で任意の属性を、text()で要素のテキストを指定する。
  • 属性であれば何でも指定できるっぽい。例)@titleなど
  • 次のようなHTMLがあった場合、//div[text()=’テスト’]は、id「outer」の要素とid「inner」の要素の両方にマッチするので注意。
<div id='outer'>
    <div id='inner'>テスト</div>
</div>
  • 子孫要素の検索にXPathを使用する場合、「//」からパスを開始するとHTML全体が検索される
  • 「.//」からパスを開始すれば子孫要素だけを検索可能
<!-- id「root」の要素の子孫要素からさらにリンクテキストが「次へ」のa要素を検索しクリック -->
driver.find_element_by_id('#root').find_element_by_xpath(".//a[text()='次へ']").click()

パス指定

XPath説明
//div[@id=’root’]/divid「root」のdiv要素の直下(次)にあるdiv要素
//div[@id=’root’]/div[1]id「root」のdiv要素の直下にあるdiv要素のうち1番目のもの。番号は1始まり
//div[@id=’root’]/div[1]/aid「root」のdiv要素の直下にあるdiv要素の、さらに直下にあるa要素
(//div[@id=’root’]/div[@class=’content sub’])[1]id「root」のdiv要素の直下にある、class属性が「content sub」のdiv要素のうち、1番目のもの
//div[@id=’root’]//aid「root」のdiv要素の”下(以降)“にあるa要素
//div[@id=’root’]/..id「root」のdiv要素の’‘要素
//div[@id=’root’]/following-sibling::h1[2]id「root」の要素と同階層で、それよりも後ろにあるh1要素のうち2番目のもの
/html/body/div[2]HTMLのルート直下からhtml要素・body要素・2番目のdiv要素とたどったところにある要素