Seleccione iframe usando Python + Selenium

Entonces, estaba absolutamente desconcertado sobre cómo hacer esto en Selenium, y no pude encontrar la respuesta en ningún lugar, así que estoy compartiendo mi experiencia.

Estaba tratando de seleccionar un iframe y no tuve suerte (o no repetiblemente de todos modos). El HTML se veía así:

      

El código de Python (usando la biblioteca de selenium) estaba tratando de encontrar este iframe usando esto:

  @timed(650) def test_pedometer(self): sel = self.selenium ... time.sleep(10) for i in range(5): try: if sel.select_frame("css=#upload_file_frame"): break except: pass time.sleep(10) else: self.fail("Cannot find upload_file_frame, the iframe for the device upload image buttons") 

Repite fallos con cada combinación de comandos de Selenium que pude encontrar. El éxito ocasional no sería reproducible, entonces ¿tal vez fue una condición de raza o algo así? Nunca encontré la manera correcta de obtenerlo en selenium propiamente dicho.

Esto me funcionó con Python (v. 2.7), webdriver y Selenium al probar con iframes e intentar insertar datos dentro de un iframe:

 self.driver = webdriver.Firefox() ## Give time for iframe to load ## time.sleep(3) ## You have to switch to the iframe like so: ## driver.switch_to.frame(driver.find_element_by_tag_name("iframe")) ## Insert text via xpath ## elem = driver.find_element_by_xpath("/html/body/p") elem.send_keys("Lorem Ipsum") ## Switch back to the "default content" (that is, out of the iframes) ## driver.switch_to.default_content() 

Lo que finalmente me funcionó fue:

  sel.run_script("$('#upload_file_frame').contents().find('img[alt=\"Humana\"]').click();") 

Básicamente, no use selenium para encontrar el enlace en el iframe y haga clic en él; usa jQuery. Selenium tiene la capacidad de ejecutar una pieza arbitraria de javascript aparentemente (esto es python-selenium, supongo que el comando original de selenium es runScript o algo así), y una vez que pueda usar jQuery puedo hacer algo como esto: seleccionar una forma que sea en un iframe usando jQuery

Si iframe es un nodo dynamic, también es posible esperar explícitamente a la aparición del iframe y luego cambiarlo usando ExpectedConditions :

 from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait as wait driver = webdriver.Chrome() driver.get(URL) wait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it("iframe_name_or_id")) 

Si iframe no tiene @id o @name se puede encontrar como WebElement común usando driver.find_element_by_xpath() , driver.find_element_by_tag_name() , etc.:

 wait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it(driver.find_element_by_xpath("//iframe[@class='iframe_class']"))) 

Para volver a cambiar desde iframe :

 driver.switch_to.default_content() 

No necesitas usar JavascriptExecutor. Todo lo que tenía que hacer era cambiar al marco y luego volver a salir, así:

 // do stuff on main window driver.switch_to.frame(frame_reference) // then do stuff in the frame driver.switch_to.default_content() // then do stuff on main window again 

Mientras tenga cuidado con esto, nunca tendrá un problema. La única vez que uso un JavascriptExecutor es enfocarme en la ventana ya que creo que usar Javascript es más confiable en ese caso.

El comando selectFrame de Selenium acepta todos los localizadores estándar como css= , pero también tiene un conjunto adicional de localizadores que trabajan específicamente con los elementos FRAME e IFRAME.

Como dice el doc :

selectFrame (localizador) Selecciona un marco dentro de la ventana actual. (Puede invocar este comando varias veces para seleccionar marcos nesteds). Para seleccionar el marco principal, use “relative = parent” como localizador; para seleccionar el marco superior, use “relative = top”. También puede seleccionar un cuadro por su número de índice basado en 0; seleccione el primer cuadro con “índice = 0”, o el tercer cuadro con “índice = 2”.

También puede usar una expresión DOM para identificar el marco que desea directamente, como esto: dom=frames["main"].frames["subframe"]

Argumentos: localizador – un localizador de elementos que identifica un marco o iframe

En general, tendrá más suerte con los localizadores especializados, especialmente si primero establece el contexto correcto ( por ejemplo , select_frame("relative=top"); select_frame("id=upload_file_frame"); ).