参考:『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') # 起動時にウィンドウを最大化する
プロセスを殺す
Get-Process chromedriver
Stop-Process -Name chromedriver
# 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(セレクタ、属性)
<!-- 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
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 URL driver.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オブジェクトのメソッド(確認中)
メソッド 返り値 説明 getName String Cookieの名前を取得 getVaue String Cookieの値を取得 getExpiry Date Cookieの「expires」の値を取得 getDomain String Cookie「domain」の値を取得 getPath String Cookie「path」の値を取得 isSecure boolean Cookieの「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 Wait driver.implicitly_wait(30) 暗黙的な待機 Explicit Wait wait = 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タグの要素
間接セレクタ
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’]/ div id「root」のdiv要素の直下(次) にあるdiv要素 //div[@id=’root’]/div[1] id「root」のdiv要素の直下にあるdiv要素のうち1番目のもの。番号は1始まり //div[@id=’root’]/div[1]/a id「root」のdiv要素の直下にあるdiv要素の、さらに直下にあるa要素 (//div[@id=’root’]/div[@class=’content sub’])[1] id「root」のdiv要素の直下にある、class属性が「content sub」のdiv要素のうち、1番目のもの //div[@id=’root’]// a id「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要素とたどったところにある要素