问题
I am doing browser automation and I am blocked at a certain point: at a moment, I ask the browser to click on a button, which in turn open up a new window. But sometimes the Internet is too slow, and so this new window takes time to load. I want to know how can I ask Selenium to wait until this new fresh window is fully loaded.
Here's my code:
driver.switch_to.default_content()
Button = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, 'addPicturesBtn')))
Button.click()
newWindow = driver.window_handles
time.sleep(5)
newNewWindow = newWindow[1]
driver.switch_to.window(newNewWindow)
newButtonToLoad = driver.find_element_by_id('d')
newButtonToLoad.send_keys('pic.jpg')
uploadButton = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, 'uploadPics')))
uploadButton.click()
driver.switch_to.window(newWindow[0])
I get this error from time to time:
newNewWindow = newWindow[1]
IndexError: list index out of range
which make me think that a simple 'time.sleep(5)' doesn't do the work.
So, my question is, how can I wait until this new window is fully loaded before interacting with it?
thanks
回答1:
You can try to use following code to wait until new window appears:
WebDriverWait(driver, 20).until(EC.number_of_windows_to_be(2))
Your code should looks like
Button.click()
WebDriverWait(driver, 20).until(EC.number_of_windows_to_be(2))
newWindow = driver.window_handles
newNewWindow = newWindow[1]
driver.switch_to.window(newNewWindow)
Considering @JimEvans comment, try below:
current = driver.window_handles[0]
Button.click()
WebDriverWait(driver, 20).until(EC.number_of_windows_to_be(2))
newWindow = [window for window in driver.window_handles if window != current][0]
driver.switch_to.window(newWindow)
回答2:
What I'm using:
windows = set(driver.window_handles)
driver.execute_script("window.open()")
WebDriverWait(driver, 20).until(EC.new_window_is_opened(windows))
hwnd = list(set(driver.window_handles) - windows)[0]
You can create a function or a context manager like this answer for it if you find it necessary, but for essentially 3 lines (not counting the one that actually opens the window, which may be very different for each case), I prefer to just copy-paste.
To be thorough, here's a feature-enriched alternative:
@contextmanager
def wait_for_new_window(driver, timeout=10, switch=True):
"""Waits for a new window to open
Parameters:
driver: WebDriver.
Selenium WebDriver object.
timeout: int
Maximum waiting time
switch: bool
If `True` (default), switches to the window.
Exemplo:
>>> with wait_for_new_window(driver) as hwnds:
... driver.execute_script("window.open()");
... print("Window opened:", hwnds[0])
"""
windows = set(driver.window_handles)
handle = []
yield handle
WebDriverWait(driver, timeout).until(EC.new_window_is_opened(windows))
hwnds = list(set(driver.window_handles) - windows)
handle.extend(hwnds)
if switch:
driver.switch_to.window(hwnds[0])
来源:https://stackoverflow.com/questions/41571217/python-3-5-selenium-how-to-handle-a-new-window-and-wait-until-it-is-fully-lo