shaddow_rootという変数の型
selenium上で印刷ダイアログを表示させた場合は、下の画像のように、印刷元のページに#shadow-rootというIDが特別に差し込まれた形になります。
この#shadow-root配下の要素をどうやって取得するか...そのあたりの話が質問文中の①のページでされています。
調べたところ、XpathではShadow-root配下の要素を取得できないようです。
ただ、解決回答となっている
shadow_root = driver.execute_script(
'return arguments[0].shadowRoot', element)
については前後のコードがないため、何を意味しているのか明確にはわかりませんでした。
(おそらく#shadow-rootの要素をshadow-rootという変数に格納しているという意味だと思いますが、elementが何を意味するか分からず、手元環境で試してもエラーになりました。)
該当するコマンド(.querySelectorなど)がライブラリーから候補として出てきていないので、なにか参照設定にて読み込みをしなければいけないのか?
記載の「document.querySelector~」で始まるコマンドが、印刷ダイアログのOKボタンを指定してクリックするためのJavaScriptになっています。
このJavaScriptのうち.click()を除く部分は、下記の手順で取得できます。
・selenium の driver.get(url) で適当なページを表示させます。
・Ctrl+Pを押して印刷ダイアログを表示させます。
・印刷ダイアログの適当な部分で右クリックし、コンテキストメニューの一番下の「検証」をクリックすると、印刷ダイアログに対するDevToolsが起動します。
・「要素の選択」ボタン(下の画像のオレンジ色で囲まれたボタン)をクリックして要素選択モードにしたあと、印刷ダイアログのOKボタンを右クリックします。
・すると、OKボタンに対応するHTMLソースが選択されるので、選択されているソース部分を右クリックし「Copy → Copy JSPath」を選択します。
・クリップボードに、選択した要素のJSPathが格納されます。
driver.execute_script(JavaScript実行文)
と書くことにより、特に参照設定を行わなくとも、selenium内で任意のJavaScriptを実行できます。
色々なサイトを調べて試行錯誤した結果、手元の環境では下記スクリプトだとうまく行きました。
キモとなる点というか、たどり着くのに苦労した点は
・印刷ボタンをクリックさせるには、setTimeOut関数を使ってwindow.print()を呼び出さないといけない(理由不明)
・印刷ダイアログは別ウィンドウ扱いなので、SwitchToNextWindow で指定対象を切り替える必要がある。
・(当然ですが)印刷ダイアログの構築完了前にボタンクリックのJSを実行してしまうとボタンをクリックできないため、一定時間待つ必要がある。
の3点です。
あと現在のOKボタンのPathは、①のページに記載のPathとは若干変わっていました。
バージョンアップに伴って変わる可能性があるとすれば、Chromeのバージョンごとに確認とメンテナンスが必要かもしれませんね。
VBA
1Sub CommandButton1_Click()
2 Dim s As String
3 s = "document.querySelector(""body > print-preview-app"").shadowRoot.querySelector(""#sidebar"").shadowRoot.querySelector(""print-preview-button-strip"").shadowRoot.querySelector(""div > cr-button.action-button"").click();"
4
5 Dim Driver As New Selenium.WebDriver
6 Driver.Start "chrome", "http://www.selenium.jp/test-site"
7 Driver.Get "/"
8
9 Driver.ExecuteScript "setTimeout(function(){window.print();}, 0);"
10 'VBAの場合十分な時間待たないと失敗する。
11 Driver.Wait (10000)
12
13 Driver.SwitchToNextWindow
14 Driver.ExecuteScript s
15
16 'VBAの場合Closeで勝手に閉じるので十分な時間WAIT。
17 Driver.Wait (20000)
18 Driver.Close
19
20End Sub
(参考)下記は検証に用いた(上のVBAコードの元にした)pythonスクリプトです。
python
1from selenium import webdriver
2import chromedriver_binary # 手元環境で使っているため指定。chromedriver.exeを直接利用している場合は不要。
3import time
4
5driver = webdriver.Chrome()
6driver.get('http://www.selenium.jp/test-site')
7driver.implicitly_wait(10)
8
9# 印刷ダイアログを開く。
10driver.execute_script("setTimeout(function(){window.print();}, 0);")
11driver.implicitly_wait(10)
12
13'''印刷ダイアログの構築完了前に要素を選択してしまう場合があるため、
14下記time.sleepで印刷ダイアログの完全表示まで強制的
15にウェイトをかけています。
16driver.implicitly_wait(10)だけではうまく行かない場合があるため、time.sleepを使用して強制的に待機させています。
17なくてもうまく動くなら削除して構いません。
18本来なら WebDriverWait.untilを使うところですが、要素の指定にJSPathしか使えない状況での
19untilの使い方が分かりませんでした。
20'''
21time.sleep(3)
22
23# 指定対象を印刷ダイアログに切り替える。
24driver.switch_to.window(driver.window_handles[-1])
25
26# 印刷ダイアログのokボタンをクリックするJavaScript
27js = 'document.querySelector("body > print-preview-app").shadowRoot.querySelector("#sidebar").shadowRoot.querySelector("print-preview-button-strip").shadowRoot.querySelector("div > cr-button.action-button").click();'
28
29# OKボタンのクリックを実行。
30driver.execute_script(js)
31
検証環境:
Windows 10
Python 3.8.4
Chrome 89.0.4389.114(Official Build) (64 ビット)
chromedriver-binary 89.0.4389.23.0
selenium 3.141.0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/04/10 01:00
2021/04/12 00:40
退会済みユーザー
2021/04/12 03:07