概要
通常Seleniumで要素をクリックする際は、
driver.find_element(By.XPATH, **** ).click()
でクリックすることができるのですが、
画面外の要素をクリックする際に、エラーが起きることがあったので、以下の記述に書き換えてたところ解決しました。
clickElement = driver.find_element(By.XPATH, ****)
driver.execute_script("arguments[0].click();", clickElement)
経緯
社内で使っているグループウェアで、データのバックアップがシステムデータのフルパッケージでしか取れないために、保存しているファイルを間違って消したり、階層フォルダごと消したりした際に、ファイル単位で復元することができないことが問題になり、どうにか自動的にファイル単位でバックアップが取れないか相談されたため、無理やり作った際のメモ。
正直クソ案件でしたが、こういう動的なシステムでも取得できることがわかったので良しとします。
システム導入の際は、この辺のことはチェックして導入しましょう。
環境
Python3.11
selenium 4.6.0
ChromeDriver(お使いのGoogleChromeのVerに合わせてダウンロード)
内容
実際に実行した内容を説明します。
ご興味あれば、読んでってください。
対象のシステム
グループウェアの書類やファイルを共有する機能から実際のファイルを取り出します。
しかし、階層化しているフォルダ構成を開かないと下位の要素をクリックできない上にCLASS_NAME
で値を取得することがほぼできない困ったシステムでした。
XPATH
で取得するしかない部分が多くて泣きました。
画面イメージ
ちょっと見にくいかもしれませんが、概ねニュアンス伝わればと思います。
画面1
この画面では、左側の階層化しているフォルダ構成とその中身のファイルが格納されたシートが表示されます。
最初に画面を開いた際には、フォルダ構成は閉じているのがデフォルトなので、クリックするためには開いて表示させる必要があります。
右下に表示している件数が出ていますが、これがあったおかげでなんとかfor文で回せました。
画面2
この画面は、ファイルが格納されたシートを開いた画面です。
格納されたファイルを一括ダウンロードできるのですが、毎回ZIP化しているようで、その処理時間がものによって違うため、本当に厄介でした。
処理の流れ
ややこしいですが、以下のような流れになります。
- 画面1のフォルダ構成は最初に全て展開させるように処理をする
- 対象のフォルダ構成をクリックする
繰り返す
- 表示されたシートの件数を読み込む
- 1つずつシートをクリック
繰り返す
- 画面2にて、ファイルの一括ダウンロードをクリック
- 表示されたらダウンロードをクリック
- 閉じるをクリック
- 戻るをクリック
-
4以降を繰り返し
、3で読み込んだ件数分終わるまで続ける 2から繰り返す
1については特にコードは書きません。クリックの処理で開いておきます。
実際のコード
最初に定義しておきます。
row=要素の位置
は、フォルダ構成の上位部分が何番目なのか定義するものです。順番が変わることがあってもここで変えてあげればいいというものです。
k=フォルダ構成の個数
はフォルダ構成内の個数を取得する方法がなかったので、手動で無理やり値を入れています。
listCount = '//*[@id="listfrm"]/div[3]/div[2]/div'
zipPath = '//*[@id="dispfrm"]/div[1]/div[2]/div[2]/div/div[2]/div/div[1]/div[2]/div[1]/a'
closeBtn = '//*[@id="neodialog-message"]/div[3]/div/button'
backBtn = '//*[@id="dispfrm"]/div[1]/div[1]/div/a'
#
openA = '//*[@id="listfrm"]/div[2]/div[2]/div[3]/table/tbody/tr['
openB = "]/td[3]/a"
row = 9 # 要素の位置
k = 6 # フォルダ構成の個数
実際に走る処理としては、以下のようになります。
対象のシートをクリックするところで、フォルダ内のシートがたくさんある場合、画面外にあることがあり、エラーが出たので書き換えました。
# フォルダ構成下位で処理繰り返す
for j in range(1, k + 1):
open = (
'//*[@id="listfrm"]/div[2]/div[1]/div[3]/div[1]/ul/li/ul/li['
+ str(row) # 上位の階層ごとにしてしておく。
+ "]/ul/li[2]/ul/li[2]/ul/li["
+ str(j)
+ "]/a"
# ここの記述が階層によって違うので取得して、繰り返しで使えるように加工
)
# 対象のフォルダ構成をクリック
driver.find_element(By.XPATH, open).click()
time.sleep(2)
# 対象のフォルダ構成内のシートの件数を取得
listCountNumber = driver.find_element(By.XPATH, listCount).get_attribute(
"textContent"
)
CountNumber = listCountNumber.strip("全 件")
n = int(CountNumber)
# シート内の取得処理を繰り返す
for i in range(1, n + 1):
# 対象のシートをクリック
open = openA + str(i) + openB
clickElement = driver.find_element(By.XPATH, open)
driver.execute_script("arguments[0].click();", clickElement)
time.sleep(2)
# 「ファイルを一括ダウンロード」をクリック
driver.find_element(By.XPATH, zipPath).click()
time.sleep(10)
# 「ZIPダウンロード」をクリック
driver.find_element(By.CLASS_NAME, "co-attzip-download").click()
time.sleep(1)
# 「閉じる」をクリック
driver.find_element(By.XPATH, closeBtn).click()
time.sleep(2)
# 「戻る」をクリック
driver.find_element(By.XPATH, backBtn).click()
time.sleep(2)
if i == n: # 件数分の処理後に繰り返し終了
break
if j == k: # フォルダ構成の個数分の処理後に繰り返し終了
break
まとめ
execute_scriptでのクリックについて、書きました。
とりあえず、クリックなどの要素を選択して実行する処理でエラーが出て、画面外の要素を選んでいる際は、1度書き換えて解消するか見てみてください。
clickElement = driver.find_element(By.XPATH, ****)
driver.execute_script("arguments[0].click();", clickElement)
参照