Selenium+Pythonにて、アラートが出る新規ウインドウに遷移したい
※Teratailで私が質問した問題を、結局自分で解決した際のメモです
Python - Selenium+Pythonにて、アラートが出る新規ウインドウに遷移したい(125969)|teratail
※2018/06/03追記
どうやらヘッドレスモード(GUI、ウインドウを表示しないモード)にすると、いちいち前のウインドウに遷移する必要がなくなるようです。 記事の最期の方に記載しておきます。
※2018/06/27追記 ↑とか書いちゃったのですが、実際には
- 新規ウインドウが出るようなボタンをクリック
- (新規ウインドウでアラートが出るまで待つ。)
switch_to_window()
で新規ウインドウをアクティブにする
の流れで処理すると動くようです
やりたいこと
- リンクをクリックする→新規ウインドウが開く(※ただしウインドウが開くと即アラートが出る)
という動きをSelenium+Pythonで実現したいと考えています。
実際にはその先のボタンを押したいのですけどね。
下記のリンクで例を見ることが出来ます。
問題点
調べているとどうも
- アラートを消すためには、アラートが出ているウインドウに遷移しなければならない
- ウインドウに遷移するためには、アラートを消さなければならない
と、デッドロックみたいな状況になっているようです。
以下ソースの★1、★2の部分です。
ソース
# -*- coding: utf-8 -*- """ Created on Wed Mar 7 22:16:01 2018 @author: """ from selenium import webdriver from selenium.webdriver.common.alert import Alert from selenium.webdriver.support import expected_conditions from selenium.webdriver.support.ui import WebDriverWait from selenium.common.exceptions import TimeoutException import datetime import traceback ########################################################################### def waitOpenWindow(driver, beforeWinNum, maxWaitSec = 10): """ 指定された時間まで、ウインドウが開くのを待つ """ beginTime = datetime.datetime.now() endTime = beginTime + datetime.timedelta(seconds=maxWaitSec) while(datetime.datetime.now() <= endTime): afterWinNum = len(driver.window_handles[-1]) if afterWinNum == beforeWinNum: continue elif afterWinNum > beforeWinNum: #ウインドウ数が増える=新規ウインドウが開いた return True , "指定時間内に新規ウインドウが開きました" else: return False, "ウインドウが外部から閉じられた可能性があります" return False, "指定時間内に新規ウインドウが開きませんでした" ########################################################################### def waitAlert(driver, maxWaitSec = 10): """ 指定された時間まで、アラートが開くのを待つ """ try: wait = WebDriverWait(driver, maxWaitSec) wait.until(expected_conditions.alert_is_present()) except TimeoutException as time_e: return 0, "アラート表示待機中にタイムアウトしました" except Exception as e: print(traceback.print_exc) return -1, "アラート表示待機中に予期しないエラーが発生しました" return 1, "アラートが表示されています : " + Alert(driver).text ########################################################################### #関数定義 def access(): try : print("begin process") driver = webdriver.Chrome("chromedriver_win32\chromedriver.exe") driver.implicitly_wait(10) driver.get("https://gologius.github.io/test.html") print("画面名", driver.title) winNum = len(driver.window_handles) #リンクをクリック driver.find_element_by_link_text("javascriptによる小ウインドウ表示").click() #ウインドウ表示待機 print("画面遷移待機中") waitResult, msg = waitOpenWindow(driver, winNum) if waitResult == False: return False, "ウインドウ表示に失敗しました" print(msg) #新規ウインドウに遷移する ★1 win = driver.window_handles[-1] #リストの最後=最後に開いたウインドウ driver.switch_to.window(win) print("画面名", driver.title) winNum = len(driver.window_handles) #アラート待機 ★2 print("アラート表示待機中") resultCode, msg = waitAlert(driver) if resultCode == 1: Alert(driver).accept() print(msg) print("end process") except: print("予期しないエラーが発生しました") print(traceback.format_exc()) #ログ出力 driver.quit() return True, "アクセス成功" ########################################################################### #実行 result, msg = access() print(msg)
解決方法
ボタンクリック後、「遷移前のウインドウ」にdriver.switch_to_window(win)で遷移すると、 その後のアラート処理、ウインドウ遷移が実行できるようです
win1 = driver.window_handles[-1] driver.find_element_by_link_text("javascriptによる小ウインドウ表示").click() #遷移前のウインドウに遷移する driver.switch_to_window(win1) #アラート処理 #ウインドウ遷移 win2 = driver.window_handles[-1] driver.switch_to_window(win2)
理由は不明ですが、推測するに、新規ウインドウが表示される際に、
- 新規ウインドウが開く際に、そのウインドウがアクティブになろうとする
- Alertのせいでアクティブになりきれない →無限ループの原因
- 遷移前のウインドウをアクティブに(
switch_to_window
)する Alert(driver).accept()
なども実行可能になる
みたいな気がします。
※2018/06/03追記↓
ヘッドレスモードで起動すると、この話は無視できる・・・?
chromeOptions = webdriver.ChromeOptions() chromeOptions.add_argument('--headless') #ブラウザのGUIが表示されなくなる driver = webdriver.Chrome("hogehoge/chromedriver.exe", chrome_options=chromeOptions)
雑感
上記のような不具合を抜きにしてもSelenium便利。
ちなみに検証用サイトはgithubioで作成しました。 テストページ | gologiusのページ
JavaScript使えるのでこういう際にサクッと作れるので便利。 ただJSの書き方を忘れていたのはナイショ...(/ω\)