rails - ¿Cómo hacer para que un robot Selenium/Ruby espere antes de realizar una acción?
selenium source (5)
Estoy construyendo un robot web Selenium / Ruby que hace clic en los elementos. El problema es que a veces no hay suficiente tiempo para cargar la página antes de que el bot decida que no puede encontrar el elemento.
¿Cuál es la forma Ruby de esperar a que el selenio espere antes de realizar una acción? Preferiría esperar explícitamente, pero estoy bien con la espera implícita también.
Traté de usar el método wait.until
:
require "selenium-webdriver"
require "nokogiri"
driver = Selenium::WebDriver.for :chrome
wait = Selenium::WebDriver::Wait.new(:timeout => 15)
driver.navigate.to "http://google.com"
driver.wait.until.find_element(:class, "gb_P").click
Pero me aparece el siguiente error:
Undefined method ''wait'' for <Selenium::WebDriver>
También probé:
require "watir-webdriver/wait"
...
driver.find_element(:class, "gb_P").wait_until.click
pero eso también me está dando un error de método indefinido:
undefined method `when_present'' for #<Selenium::WebDriver...>
Estás usando wait
como función WebDriver
, pero no es así. Prueba esto
element = wait.until { driver.find_element(:class => "gb_P") }
element.click
Una respuesta potencial está en tu stacktrace.
driver.element(:class, "gb_P").when_present.click
Bueno. Esta respuesta se ha preguntado muchas veces en muchos contextos diferentes. Así que solo quiero responder aquí de una vez por todas.
Hay tres formas en que esto se puede hacer. Y cada uno es útil en ciertos contextos.
Primero , puede usar una espera EXPLÍCITA. Esto no tiene nada que ver con si la página se carga o no. Simplemente le dice al script que espere. En otras palabras, si su página se carga en 11 segundos y su espera explícita es de 10 segundos, el elemento en el que se puede hacer clic todavía no estará disponible. Puede evitar esta ineficiencia utilizando una condición esperada. Ver, por ejemplo, las páginas de manual de Selenium:
require ''selenium-webdriver''
driver = Selenium::WebDriver.for :firefox
driver.get "http://google.com"
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
begin
element = wait.until { driver.find_element(:class => "gb_P") }
ensure
driver.quit
end
^ Esto esperará: 10 segundos O hasta que se encuentre el elemento.
En segundo lugar , puede usar una espera implícita. Esto es muy similar a la espera explícita con la condición esperada. Sin embargo, cuando la espera explícita se aplica al elemento que se consulta, la espera implícita se aplica al Objeto WebDriver . En otras palabras, si su script solo usa un único controlador de web, esperará: el tiempo de espera implícito para CADA elemento O hasta que se encuentre cada elemento (hasta que falle). Por ejemplo:
require ''selenium-webdriver''
driver = Selenium::WebDriver.for :firefox
driver.manage.timeouts.implicit_wait = 10 # seconds
driver.get "http://google.com"
element = driver.find_element(:class => "gb_P")
En tercer lugar , puede llamar a una función de Javascript para hacer clic en la página. La ventaja de esto es que una vez que se carga el Javascript de la página, se puede hacer clic en el elemento y no tienes que esperar a que la página se muestre . Cuando está "esperando la página", en realidad está esperando en el lado del cliente que el motor de representación construya la página. Puede omitir ese proceso simplemente haciendo clic en el elemento subyacente antes de que realmente se represente la página.
El inconveniente de esto es que no refleja un ser humano real al hacer clic en la página. Por ejemplo, si el botón que desea hacer clic está oculto por una ventana emergente. El selenio no le permitirá hacer clic en él, pero sí lo hará una función JS.
Puede usar este método haciendo:
click = driver.execute_script("document.getElementsByClassName(''gb_P'')[0].click();")
¿Has probado el presente para esperar el botón (también puedes esperar a que cierto div lo haga)
require "watir-webdriver/wait"
driver.button(:class => ''gb_P'').when_present.click
En cuanto a la espera explícita
sleep *seconds*
o una mejor manera de no perder el tiempo
sleep *seconds* until driver.element(:id/class/etc, ''value'').exists?
También puedes usar sleep (#) para esperar, y dependiendo de tu editor puedes ver qué variaciones puedes usar para que en lugar de segundos puedas ir a algo más bajo o más alto, en Ruby ni siquiera tienes declararlo
Simplemente escriba sleep y un número en el paréntesis y debería ver que se detiene durante ese tiempo en segundos, otros señalan por qué esta es una solución que podría no ser óptima, pero si solo lo necesita esperar un poco en una página eso nunca llevará tanto tiempo, es un gran código de una línea para usar.