Si eres de los que tiene que repetir tareas en aplicaciones web una, y otra, y otra vez, un trabajo que no es ineficiente realizarlo manualmente, sino inhumano, tal vez quieras crear una macro en Excel VBA que te permita navegar de manera automática. Esta vez hablaré de Selenium 1.0.23.0.
Asumo que ya te leiste mi post anterior sobre twebst, y que dominas el tema de "nodos" y "xpath" de XML. Si no lo has hecho, puedes ingresar aquí.
ADVERTENCIA!!
- Hay varias versiones de Selenium. Yo me referiré a la versión Selenium Wrapper 1.0.23.0.
- Para este momento hay una versión mucho más nueva, la 2.0.7.0 que no se llama Selenium Wrapper 1.0.23.0, sino Selenium Basic 2.0.7.0.
- Como puedes notar Selenium Wrapper y Selenium Basic son totalmente distintos y el código de uno es muy distinto al código de otro. Selenium Wrapper fue un proyecto que estaba hospedado en Google, mientras que Selenium Basic es el mismo proyecto que se ha mudado a otro sitio.
- Ambos son add-ons que sirven para escribir código para Excel VBA.
- Yo NO me referiré a Selenium Basic.
- Puedes descargar Selenium Basic en el sitio web correspondiente. Aporto este enlace para tu información únicamente.
- Parece haber versiones posteriores de Selenium Wrapper en SeleniumHQ pero no estoy seguro de la compatibilidad con este tutorial.
Instalación de Selenium
Antes de poder usar Selenium en Excel, hay que descargarlo e instalarlo(solía estar hospedado en Selenium webpage). Usa la versión 1.0.23.0 si deseas usar este post como tutorial.
Para cada libro con macros donde vayas a escribir código de Selenium, debes seguir estos pasos una única vez.
- Entra a Excel, presiona Alt F11 para ir al IDE de VBA.
- Ve a Tools > Referencias
- Presiona el botón Browse
- Ve al directorio Program Files\Selenium Wrapper\
- Escoge el archivo SeleniumWrapper.tlb
- Asegúrate de que la librería de Selenium esté habilitada en la lista de referencias.
Nomenclatura
Usaré la siguiente notación para describir las direcciones de internet.
Cuando usas Selenium para automatizar, encontrarás que el código en muchos tutoriales está en Java, y la traducción a VBA no es literal. Trataré un poco de lo básico de Selenium en VBA.
Los localizadores sirven para ubicar un nodo, y puedes usarlo según el tipo de nodo de que se trate.
Hay varias maneras de accederles, de dar la dirección de un nodo para ser usado por Selenium:
- Por nombre. Ejemplo: name=NombreDeNodo
- Por ID. Ejemplo: id=01234XYZ
- Por clase. Ejemplo: @class='miclase'
- Por Xpath. Ejemplo: xpath=//*/body/div/div/div/form/div/div/div/table/tbody
Yo prefiero usar Xpath para dar direcciones de nodos. Puedes ver ejemplos de uso de localizadores en el sitio web de Selenium.
Declaraciones
Ingresa esto en las declaraciones al inicio del módulo.
Public Const Firefox = "firefox"
Public Const Chrome = "chrome"
Public Const InternetExplorer = "ie"
Public Const InternetExplorer64bits = "ie64"
Public Const Safari = "safari"
Dim selenium As New SeleniumWrapper.WebDriver
Dim acciones As SeleniumWrapper.actions
Dim elemento As SeleniumWrapper.WebElement
Dim opciones As SeleniumWrapper.WebElementCollection
Dim by As New SeleniumWrapper.by
Dim ContadorOpciones As Long
Dim ElementoActivo As String
Dim FileInpue As SeleniumWrapper.WebElement
Lanzar aplicación
selenium.Start Chrome, sURL1
sURL1 es el dominio.
Chrome es el navegador que elegí para este ejemplo.
Abrir página web
selenium.Open sURL2
sURL2 contiene la carpeta y la página web.
Fijar espera implicita
Fija el tiempo de espera máximo en milisegundos para cargar (loading time).
selenium.setImplicitWait 10000
Fijar espera
Fija tiempo de espera mínimo para cargar.
selenium.wait 1000
Detectar si elemento está habilitado
A veces cargas la página y se ve el elemento, pero el elemento no está habilitado.
Para descubrir si el elemento está habilitado. Imagina que has guardado el Xpath del elemento en la variable sXpath.
Set elemento = selenium.findElement(by.XPath(sXpath))
ElementoHabilitado = elemento.Enabled
Obtener direción URL actual
Si quieres saber cual es la dirección actual, porque a veces hay redireccionamientos, o quieres verificar que la carga tuvo éxito, puedes usar esto.
URL = selenium.url
Digitar datos
Deseas digitar texto en un campo de texto
selenium.Type sLocalizador, sTexto
Pinchar boton o enlace (Click izquierdo)
Hacer click izquierdo sobre un botón o enlace.
selenium.Click sLocalizador
Seleccionar elemento con múltiples opciones
Si tienes una tabla con múltiples filas, el nodo tbody es la tabla y tienes muchos nodos tr (table row) o si tienes un control dropdown (lista desplegable) con muchas opciones, no puedes usar directamente el control, sino que debes seleccionarlo primero antes de ser usado. A los elementos múltiples de la tabla o dropdown, les llamaré opciones. Veamos distintas maneras de seleccionar el elemento. Puedes usar la manera que se te antoje.
Set elemento = selenium.findElement(by.name(NodeName("nombre")))
Set elemento = selenium.findElement(by.ClassName(NodeClass("clase")))
Set elemento = selenium.findElement(by.Id(NodeId("IDnodoX")))
Set elemento = selenium.findElement(by.XPath("//*/body/div/div/div/form/div/div/div/table/tbody"))
Luego debes trabajar con las opciones. No olvides en alguna variable mantener el nombre del elemento activo que seleccionaste (nombre, id, clase o xpath) para uso futuro. En este ejemplo usaré un Xpath.
ElementoActivo = "//*/body/div/div/div/form/div/div/div/table/tbody"
En los siguientes pasos vamos a usar el elemento seleccionado.
Cantidad de opciones
Busquemos la cantidad de opciones. Pongamos a Selenium a contar
Set opciones = element.findElements(by.tagName("option"))
ContadorOpciones
= opciones
.count
Obtener nombre de opción actualmente seleccionada
TextoDeOpcionSeleccionada = elemento.AsSelect.SelectedOption.Text
Seleccionar opción
OpcionSeleccionada = 2
elemento.AsSelect.selectByIndex (Val(OpcionSeleccionada))
Obtener texto de un nodo
Si tienes un campo de datos en el sitio web, tal como una fecha o un monto o un nombre, sólo debemos indicar el Xpath (variable sXpath en este ejemplo, "s" en el nombre de la variable indica que la variable es de tipo String) para indicar qué nodo debe usarse.
Set elemento = selenium.findElement(by.XPath(sXpath))
ValorCampoDeTexto = elemento.Text
Cantidad de filas de una tabla
En este ejemplo obtenemos el Xpath de la fila (tr = table row). Ponemos a Selenium a contar.
sXpath = "//*[@class='mitabla']/tbody/tr"
CantidadDeFilas = selenium.findElements(by.XPath(sXpath)).count
Verificar que elemento existe
Brinda un valor boolean (falso/verdadero). Sirve para verificar que un nodo existe. Por ejemplo, si el botón on existe, al tratar de pincharlo, obtendrás error.
ExisteElemento = selenium.isElementPresent(by.XPath(sXpath))
Hacer "right click"
selenium.actions.contextClick(selenium.findElementByXPath(sXpath)).perform
Enviar teclazo "Enter"
selenium.findElement(by.XPath(sXpath)).SendKeys Keys.Enter
Obtener el texto que aparece en la página
TextoEnLaPagina = selenium.getBodyText
Moverse a un frame
selenium.SwitchToFrame selenium.findElement(by.XPath(XpathDelFrame))
Ingresar nombre de archivo que va a ser colgado
selenium.findElement(by.XPath(XpathDelCampoDondeVaNombreDeArchivo)).SendKeys (RutaCompleta)
Errores comunes
La mayoría de errores se deben a lo siguiente:
- Conexión lenta o tiempo de espera bajo, al terminar el tiempo de espera no ha cargado lo que deseas cargar.
- Redireccionamientos cuando las páginas te dicen que expiró, cuando no estabas logeado al sitio web, etc. Lo que tu código encuentra no es lo que se supone que debe encontrar.
- Elementos (controles) no encontrados, o inahbilitados. Sería bueno verificar que los elementos están presentes y habilitados.
- Direccionamiento a nodos incorrectos. Para ello es util grabar script en Twebst si quieres verificar que estás haciendo referencia a los nodos correctos.
- Error al seleccionar un nodo con múltiples elementos sin éxito y luego tratas de trabajar sobre sus opciones.
- Los Xpath no son iguales para distintos usuarios. De acuerdo con los privilegios o configuración que tengan los usuarios, puede que los Xpath o el orden o cantidad de opciones que funcionaban para un usuario, no sirvan para otro. Cuando esto sucede, es un verdadero dolor de cabeza.
Muchas veces la parte difícil de programar con Selenium puede ser la obtención de los Xpath y lidiar con conductas de la página web.
Aunque suene simple usar Selenium, a veces te costará solucionar algunos problemas. He aquí algunos trucos.
- Chrome a veces tiene problemas para darte los Xpath correctos, de modo que si no funciona, trata de obtener la ruta Xpath absoluta de manera manual. Por ejemplo, en lugar de //*[@class='mitabla']/tbody/tr querrías usar //html/body/div/div/div/form/div/div/div/table/tbody/tr. También puedes ayudarte grabando scripts de Twebst para ver si estás usando los Xpath correctos.
- Cuando tienes controles donde debes hacer "mouse hover" o pinchar una region de pantalla para que aparezca una lista desplegable, la respuesta no es nada obvia. Chrome te dará el Xpath del control a pinchar, pero con Twebst puedes obtener el nombre del nodo del dropdown. En realidad tienes dos nodos, uno para pinchar, y otro para seleccionar una opción, de modo que tendrás 3 pasos:
- Pinchar (hacer click izquierdo) en el control del mouse hover.
- Ir al elemento dropdown que es otro control.
- Seleccionar una opción en el dropdown
- El problema se complica aún más si el "mouse hover" no responde si tienes el cursor del mouse encima del browser, de modo que vas a tener que moverlo manualmente o buscar en Google cómo se mueve con código.
¿Problemas con Silverlight?
Si estabas automatizando navegación en Sharepoint para Chrome y tienes problemas con Silverlight, porque Chrome ya no soporta NPAPI, sólo debes modificar tu URL. Mientras que la galería de Sharepoint sí apunta al uso de Silverlight, hay otra vista con URL distinto que no lo usa. Veamos este ejemplo hipotético.
- https://MiSitioSharepoint.com/Forms/Gallery.aspx es un URL que SI usa Silverlight.
- https://MiSitioSharepoint.com/Forms/AllItems.aspx es un URL que NO usa Silverlight
Corolario
En muchas empresas pasar información de una aplicación web a otra suele ser una tarea muy aburrida, pesada, ineficiente y que no agrega valor. Con Selenium se puede automatizar este tipo de procesos. Se dice que existen complementos para grabar scripts de Selenium, pero no hay como hacer uno mismo el código. Cuando se trata de pasos a seguir, se puede grabar, pero cuando se necesita recoger información y reaccionar y tomar decisiones ante los valores encontrados, los scripts grabados pierden cierta utilidad.