Automatización del navegador web con Selenium y Java

Varias herramientas pueden controlar el navegador web de la forma en que un usuario real navegaría a diferentes páginas, interactuando con los elementos de la página y capturando...

Introducción

Varias herramientas pueden controlar el navegador web de la forma en que un usuario real navegaría a diferentes páginas, interactuando con los elementos de la página y capturando algunos datos. Este proceso se llama Automatización del navegador web. Lo que puede hacer con la automatización del navegador web depende totalmente de su imaginación y necesidades.

Algunos de los casos de uso comunes de la automatización del navegador web podrían ser:

  • Automatización de las pruebas manuales en una aplicación web
  • Automatizar las tareas repetitivas como eliminar información de sitios web
  • Rellenar los formularios HTML, hacer algunos trabajos administrativos, etc.

En este tutorial, exploraremos una de las herramientas de automatización de navegadores web más populares: [Selenio] (https://www.seleniumhq.org). Aprenderemos sobre sus características, la API y cómo podemos usarla con Java para automatizar cualquier sitio web.

¿Qué es el selenio?

Selenium es una colección de herramientas que incluye Selenium IDE, Selenium RC y Selenium WebDriver.

Selenium IDE es puramente una herramienta de reproducción de registros que se presenta como un complemento de Firefox y una extensión de Chrome. Selenium RC era la herramienta heredada que ahora está depreciada. Selenium WebDriver es la herramienta más reciente y ampliamente utilizada.

Nota: Los términos Selenium, Selenium WebDriver o simplemente WebDriver se usan indistintamente para referirse a Selenium WebDriver.

Es importante tener en cuenta aquí que Selenium está diseñado para interactuar solo con componentes web. Entonces, si encuentra algún componente basado en el escritorio, como un cuadro de diálogo de Windows, Selenium por sí solo no puede interactuar con ellos. Hay otros tipos de herramientas como autoit o Automa que se pueden integrar con Selenium para estos fines.

¿Por qué usar Selenio? {#por qué se utiliza el selenio}

Selenium es una de las herramientas de automatización de navegadores más populares. No depende de un lenguaje de programación en particular y es compatible con Java, Python, C#, Ruby, PHP, Perl, etc. También puede escribir su implementación para el lenguaje si aún no es compatible.

En este tutorial, aprenderemos a usar los enlaces Java de Selenium WebDriver. También exploraremos la WebDriver API.

El éxito de Selenium también se puede atribuir al hecho de que las especificaciones de WebDriver se han convertido en la recomendación W3C para navegadores.

Requisitos previos:

WebDriver proporciona enlace para todos los idiomas populares como se describe en la sección anterior. Dado que estamos utilizando el entorno de Java, necesitamos descargar e incluir los enlaces de Java en la ruta de compilación. Además, casi todos los navegadores populares proporcionan un controlador que se puede usar con Selenium para controlar ese navegador.

En este tutorial, manejaremos Google Chrome.

WebDriver

Antes de seguir adelante, es útil comprender algunos conceptos que generan confusión entre los principiantes. WebDriver no es una clase, es una interfaz.

Todos los controladores dependientes del navegador como ChromeDriver, FirefoxDriver, InternetExplorerDriver son clases de Java que implementan la interfaz WebDriver. Esta información es importante porque si desea ejecutar su programa en un navegador diferente, no necesita cambiar gran parte de su código para que funcione, solo necesita cambiar el ‘WebDriver’ por el navegador que desee.

Primero, especifiquemos la ruta al controlador del navegador. A continuación, crearemos una instancia del "controlador correcto" para ese navegador, ChromeDriver en nuestro caso:

1
2
System.setProperty("webdriver.chrome.driver", "path/to/chromedriver");
WebDriver driver = new ChromeDriver();

Como podemos ver, el driver contiene una referencia a ChromeDriver y, por lo tanto, puede usarse para controlar el navegador. Cuando se ejecute la declaración anterior, debería ver una nueva ventana del navegador abierta en su sistema. Pero el navegador aún no ha abierto ningún sitio web. Necesitamos indicarle al navegador que lo haga.

Nota: Para usar un ‘WebDriver’ diferente, debe especificar la ruta del controlador en el sistema de archivos y luego crear una instancia. Por ejemplo, si desea utilizar IE, esto es lo que debe hacer:

1
2
System.setProperty("webdriver.ie.driver", "path/to/IEDriver");
WebDriver driver = new InternetExplorerDriver();

De aquí en adelante el código será exactamente el mismo para todos los navegadores. Para mantener nuestro aprendizaje enfocado, automatizaremos wikihtp.com.

Como se mencionó anteriormente, primero debemos navegar a nuestro sitio web de destino. Para hacer esto, simplemente enviamos una solicitud GET a la URL del sitio web:

1
driver.get("https://wikihtp.com");

elemento web

El primer paso en la automatización del navegador web es ubicar los elementos en la página web con los que queremos interactuar, como un botón, entrada, lista desplegable, etc.

La representación de Selenium de dichos elementos HTML es WebElement. Al igual que WebDriver, WebElement también es una interfaz Java. Una vez que tenemos un WebElement podemos realizar cualquier operación sobre él que un usuario final pueda hacer, como hacer clic, escribir, seleccionar, etc.

Es obvio que intentar realizar operaciones no válidas, como intentar ingresar texto en un elemento de botón, dará como resultado una excepción.

Podemos usar los atributos HTML de un elemento como ‘id’, ‘clase’ y ’nombre’ para ubicar un elemento. Si no existen tales atributos, podemos usar algunas técnicas de localización avanzadas como Selectores de CSS y XPath.

Para verificar los atributos HTML de cualquier elemento, podemos abrir el sitio web en nuestro navegador Chrome (otros navegadores también lo admiten), hacer clic derecho sobre el elemento que desea seleccionar y hacer clic en Inspeccionar elemento. Esto debería abrir las Herramientas de desarrollador y mostrar los atributos HTML de ese elemento:

Inspecting an element

Como podemos ver, el elemento tiene una etiqueta <input> y múltiples atributos como id, class, etc.

WebDriver admite 8 localizadores diferentes para ubicar elementos:

  • identificación
  • nombre de clase
  • nombre
  • NombreEtiqueta
  • texto del enlace
  • texto de enlace parcial
  • cssSelector*
  • xpath

Exploremos todos ellos uno por uno mediante la automatización de los diferentes elementos en nuestro sitio web de destino.

Localización de elementos a través de id

Si inspeccionamos el cuadro de entrada del boletín de nuestro sitio web de destino, podemos encontrar que tiene un atributo id:

1
<input type="email" id="email" value name="email" class="required email input-lg" placeholder="Enter your email...">

Podemos ubicar este elemento usando el localizador id:

1
WebElement newsletterEmail = driver.findElement(By.id("email"));

Localización de elementos a través de className

Si inspeccionamos el mismo cuadro de entrada, podemos ver que también tiene un atributo clase.

Podemos ubicar este elemento usando el localizador className:

1
WebElement newsletterEmail = driver.findElement(By.className("required email input-lg"));

Nota: El nombre del localizador es className, no class. Pero el atributo HTML es clase.

Localización de elementos a través del nombre

Para este ejemplo, imaginemos una lista desplegable, donde un usuario debe seleccionar su rango de edad. La lista desplegable tiene un atributo nombre, que podemos buscar:

1
2
3
4
5
6
7
8
9
<select name="age">
    <option value="Yet to born">Not Born</option>
    <option value="Under 20">Under 20</option>
    <option value="20 to 29">Under 30</option>
    <option value="30 to 39">Under 40</option>
    <option value="40 to 50">Under 50</option>
    <option value="Over 50">Above 60</option>
    <option value="Ghost">Not Defined</option>
</select>

Podemos ubicar este elemento usando el localizador name:

1
WebElement age = driver.findElement(By.name("age"));

Localización de elementos a través de xpath

Sin embargo, a veces, estos enfoques son obsoletos, ya que hay varios elementos con el mismo atributo:

1
2
3
4
5
<p>
    <input name="gender" type="Radio" value="Female">Female<br>
    <input name="gender" type="Radio" value="Male">Male<br>
    <input name="gender" type="Radio" value="donotknow">Still Exploring
</p>

En este ejemplo podemos ver que los tres elementos input tienen el mismo atributo name, "gener", pero no todos tienen el mismo valor. A veces, los atributos básicos como ‘id’, ‘clase’ o ’nombre’ no son únicos, en cuyo caso necesitamos una forma de definir exactamente qué elemento nos gustaría obtener.

En estos casos, podemos utilizar localizadores XPath. Los XPath son localizadores muy poderosos y son un tema completo por sí solos. El siguiente ejemplo puede darle una idea de cómo construir un XPath para los fragmentos HTML anteriores:

1
WebElement gender = driver.findElement(By.xpath("//input[@value='Female']"));

Localización de elementos mediante cssSelector

Nuevamente, imaginemos una lista de casillas de verificación donde el usuario selecciona su lenguaje de programación preferido:

1
2
3
4
5
6
7
<p>
    <input name="language_java" type="Checkbox" value="java">Java<br>
    <input name="language_python" type="Checkbox" value="python">Python<br>
    <input name="language_c#" type="Checkbox" value="c#">C#<br>
    <input name="language_c" type="Checkbox" value="c">C<br>
    <input name="language_vbs" type="Checkbox" value="vbscript">Vbscript
</p>

Técnicamente, para este fragmento de HTML, podemos usar fácilmente el localizador nombre ya que tienen valores distintos. Sin embargo, en este ejemplo, usaremos cssSelectors para ubicar este elemento, que se usa ampliamente en el front-end con bibliotecas como jQuery.

El siguiente ejemplo puede darle una idea de cómo construir selectores CSS para el fragmento HTML anterior:

1
2
WebElement languageC = driver.findElement(By.cssSelector("input[value=c]"));
WebElement languageJava = driver.findElement(By.cssSelector("input[value=java]"));

Evidentemente, es muy similar al enfoque XPath.

Localización de elementos a través de linkText

Si el elemento es un enlace, es decir, tiene una etiqueta <a>, podemos ubicarlo usando su texto. Por ejemplo, el enlace "Abuso de pila":

Inspecting an element

1
<a href="/">Stack Abuse</a>

Podemos localizar el enlace usando su texto:

1
WebElement homepageLink = driver.findElement(By.linkText("Stack Abuse"));

Localización de elementos a través de texto de enlace parcial {#localización de elementos a través de texto de enlace parcial}

Digamos, tenemos un enlace con el texto - "random-text-xyz-i-wont-change-random-digit-123". Como se mostró anteriormente, podemos ubicar este elemento usando el localizador linkText.

Sin embargo, la API de WebDriver ha proporcionado otro método parcialLinkText. A veces, una parte del texto del enlace puede ser dinámica y cambiar cada vez que vuelve a cargar la página, por ejemplo, "Pedido #XYZ123".

En estos casos podemos usar el localizador partialLinkText:

1
WebElement iWontChangeLink = driver.findElement(By.partialLinkText("i-wont-change"));

El código anterior seleccionará con éxito nuestro enlace "texto-aleatorio-xyz-no-cambiaré-dígito-aleatorio-123" ya que nuestro selector contiene una subcadena del enlace.

Localización de elementos a través de tagName

También podemos ubicar un elemento usando su nombre de etiqueta, p. <a>, <div>, <input>, <select>, etc. Debe utilizar este localizador con precaución. Como puede haber varios elementos con el mismo nombre de etiqueta y el comando siempre devuelve el primer elemento coincidente en la página:

1
WebElement tagNameElem = driver.findElement(By.tagName("select"));

Esta forma de encontrar un elemento suele ser más útil cuando llama al método findElement en otro elemento y no en todo el documento HTML. Esto reduce su búsqueda y le permite encontrar elementos usando localizadores simples.

Interactuando con Elementos

Hasta ahora hemos localizado los elementos HTML en la página y podemos obtener el ‘WebElement’ correspondiente. Sin embargo, aún no hemos interactuado con esos elementos como lo haría un usuario final: hacer clic, escribir, seleccionar, etc. Exploraremos algunas de estas acciones simples en las próximas secciones.

Elementos para hacer clic {#elementos para hacer clic}

Realizamos la operación de clic usando el método click(). Podemos usar esto en cualquier WebElement si se puede hacer clic en él. Si no, lanzará una excepción.

En este caso, hagamos clic en homepageLink:

1
homepageLink.click();

Dado que esto realmente hace clic en la página, su navegador web seguirá el enlace en el que se hizo clic mediante programación.

Introducción de texto

Ingresemos algo de texto en el cuadro de entrada newsletterEmail:

1
newsletterEmail.sendkeys("[correo electrónico protegido]");

Selección de botones de radio

Dado que simplemente se hace clic en los botones de opción, usamos el método click() para seleccionar uno:

1
gender.click();

Selección de casillas de verificación

Lo mismo ocurre con la selección de casillas de verificación, aunque en este caso, podemos seleccionar varias casillas de verificación. Si seleccionamos otro radio button, el anterior quedará deseleccionado:

1
2
languageC.click();
languageJava.click();

Selección de elementos de un menú desplegable

Para seleccionar un elemento de la lista desplegable, tendríamos que hacer dos cosas:

Primero, necesitamos instanciar Select y pasarle el elemento de la página:

1
Select select = new Select(age);

Es importante señalar aquí que Select es una clase de Java que implementa la interfaz ISelect.

A continuación, podemos seleccionar un elemento usando su:

Texto mostrado:

1
select.selectByVisibleText("Under 30");

Valor (el atributo valor):

1
select.selectByValue("20 to 30");

Índice (comienza con 0):

1
select.selectByIndex(2);

Si la aplicación admite selección múltiple, podemos llamar a uno o más de estos métodos varias veces para seleccionar diferentes elementos.

Para comprobar si la aplicación permite selecciones múltiples podemos ejecutar:

1
select.isMultiple();

Hay muchas otras operaciones útiles que podemos realizar en la lista desplegable:

  • Obtener la lista de opciones:
1
java.util.List<WebElement> options = select.getOptions();
  • Obtener la lista de opciones seleccionadas:
1
java.util.List<WebElement> options = select.getAllSelectedOptions();
  • Obtener la primera opción seleccionada
1
java.util.List<WebElement> options = select.getFirstSelectedOption();
  • Deseleccionar todas las opciones
1
select.deselectAll();
  • Deseleccionar por texto mostrado:
1
select.deselectByVisibleText("Under 30");
  • Deseleccionar por valor:
1
select.deselectByValue("20 to 30");
  • Deseleccionar por índice:
1
select.deselectByIndex(2);

Nota: También podemos combinar los dos pasos de encontrar el elemento e interactuar con él en una sola declaración a través del encadenamiento. Por ejemplo, podemos buscar y hacer clic en el botón Enviar de esta manera:

1
driver.findElement(By.id("submit_htmlform")).click();

También podemos hacer esto con Select:

1
Select select = new Select(driver.findElement(By.name("age")));

Obtener valores de atributos

Para obtener el valor de un atributo particular en un elemento:

1
driver.findElement(By.id("some-id")).getAttribute("class")

Configuración de valores de atributos

También podemos establecer el valor de un atributo particular en un elemento. Podría ser útil donde queramos habilitar o deshabilitar algún elemento:

1
driver.findElement(By.id("some-id")).setAttribute("class", "enabled")

Interacción con el mouse y el teclado {#interacción con el mouse y el teclado}

La API de WebDriver ha proporcionado la clase Actions para interactuar con el mouse y el teclado.

Primero, necesitamos instanciar Actions y pasarle la instancia WebDriver:

1
Actions builder = new Actions(driver);

Mover el ratón

A veces, es posible que tengamos que pasar el cursor sobre un elemento del menú para que aparezca el elemento del submenú:

1
2
WebElement elem = driver.findElement(By.id("some-id"));
builder.moveToElement(elem).build().perform();

Arrastrar y soltar

Arrastrando un elemento sobre otro elemento:

1
2
3
WebElement sourceElement = driver.findElement(By.id("some-id"));
WebElement targetElement = driver.findElement(By.id("some-other-id"));
builder.dragAndDrop(sourceElement, targetElement).build().perform();

Arrastrando un elemento por algunos píxeles (por ejemplo, 200 px en horizontal y 0 px en vertical):

1
2
WebElement elem = driver.findElement(By.id("some-id"));
builder.dragAndDropBy(elem, 200, 0).build().perform();

Presionando teclas

Mantenga presionada una tecla en particular mientras escribe algún texto como la tecla Shift:

1
2
3
4
5
6
WebElement elem = driver.findElement(By.id("some-id"));
builder.keyDown(Keys.SHIFT)
    .sendKeys(elem,"some value")
    .keyUp(Keys.SHIFT)
    .build()
    .perform();

Realice operaciones como Ctrl+a, Ctrl+c, Ctrl+v y TAB:

1
2
3
4
5
6
7
8
// Select all and copy
builder.sendKeys(Keys.chord(Keys.CONTROL,"a"),Keys.chord(Keys.CONTROL,"c")).build().perform();

// Press the tab to focus on the next field
builder.sendKeys(Keys.TAB).build().perform();

// Paste in the next field
builder.sendKeys(Keys.chord(Keys.CONTROL,"v")).build().perform();

Interactuando con el Navegador

Obtener la fuente de la página

Lo más probable es que use esto para las necesidades de web scraping:

1
driver.getPageSource();

Obtener el título de la página

1
driver.getPageTitle();

Maximización del navegador

1
driver.manage().window().maximize();

Salir del controlador

Es importante salir del controlador al final del programa:

1
driver.quit();

Nota: la API de WebDriver también proporciona un método close() y, a veces, esto confunde a los principiantes. El método close() simplemente cierra el navegador y se puede volver a abrir en cualquier momento. No destruye el objeto WebDriver. El método quit() es más apropiado cuando ya no necesita el navegador.

Tomando capturas de pantalla {#tomando capturas de pantalla}

Primero, necesitamos convertir WebDriver al tipo TakesScreenshot que es una interfaz. A continuación, podemos llamar a getScreenshotAs() y pasar OutputType.FILE.

Finalmente, podemos copiar el archivo en el sistema de archivos local con las extensiones apropiadas como *.jpg, *.png, etc.

1
2
3
4
File fileScreenshot=((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);

// Copy screenshot in local file system with *.png extension
FileUtils.copyFile(fileScreenshot, new File("path/MyScreenshot.png"));

Ejecutando JavaScript

También podemos inyectar o ejecutar cualquier pieza válida de JavaScript a través de Selenium WebDriver. Esto es muy útil ya que le permite hacer muchas cosas que no están integradas directamente en Selenium.

Primero, necesitamos convertir WebDriver al tipo JavaScriptExecutor:

1
JavaScriptExecutor js = (JavaScriptExecutor)driver;

Podría haber varios casos de uso relacionados con JavaScriptExecutor:

  • Realizar operaciones de la forma natural de hacerlo si falla la API de WebDriver, como click() o sendKeys().
1
js.executeScript("driver.getElementById('some-id').click();");

También podemos encontrar primero el elemento usando los localizadores de WebDriver y pasar ese elemento a executeScript() como segundo argumento. Es la forma más natural de usar JavaScriptExecutor:

1
2
3
4
5
// First find the element by using any locator
WebElement element = driver.findElement(By.id("some-id"));

// Pass the element to js.executeScript() as the 2nd argument
js.executeScript("arguments[0].click();", element);

Para establecer el valor de un campo de entrada:

1
2
3
String value = "some value";
WebElement element = driver.findElement(By.id("some-id"));
js.executeScript("arguments[0].value=arguments[1];", element, value);
  • Desplazando la página hasta el fondo:
1
js.executeScript("window.scrollTo(0, document.body.scrollHeight);");
  • Desplazar el elemento para llevarlo a la ventana:
1
2
3
4
WebElement element = driver.findElement(By.id("some-id"));

// If the element is at the bottom pass true, otherwise false 
js.executeScript("arguments[0].scrollIntoView(true);", element);
  • Alterar la página (agregar o quitar algunos atributos de un elemento):
1
2
WebElement element = driver.findElement(By.id("some-id"));
js.executeScript("arguments[0].setAttribute('myattr','myvalue')", element);

Acceso a cookies {#acceso a cookies}

Dado que muchos sitios web utilizan cookies para almacenar el estado del usuario u otros datos, puede resultarle útil acceder mediante programación mediante Selenium. Algunas operaciones comunes de cookies se describen a continuación.

Obtener todas las cookies:

1
driver.manage().getCookies();

Obtener una cookie específica:

1
driver.manage().getCookieNamed(targetCookie);

Añadir una galleta:

1
driver.manage().addCookie(mySavedCookie);

Eliminar una cookie:

1
driver.manage().deleteCookie(targetCookie);

Conclusión

Hemos cubierto todas las funciones principales de Selenium WebDriver que podemos necesitar usar al automatizar un navegador web. Selenium WebDriver tiene una API muy extensa y cubrir todo está más allá del alcance de este tutorial.

Es posible que haya notado que Selenium WebDriver tiene muchos métodos útiles para simular casi todas las interacciones de los usuarios. Dicho esto, las aplicaciones web modernas son realmente inteligentes. Si quieren restringir su uso automatizado, hay varias formas de hacerlo, como usar captcha. Desafortunadamente, Selenium no puede pasar por alto el captcha. Utilice esta herramienta teniendo en cuenta los Términos de uso del sitio web de destino. ino.