Xpath: Encuentra cualquier elemento en una pƔgina web
GuĆa de como utilizar XPath para encontrar cualquier elemento en una pĆ”gina web y optimizar tus robots
Hey, por acĆ” Danilo š
Bienvenido a una nueva ediciĆ³n de Robotipy. En este articulo te enseƱarĆ© que es un Xpath, como construirlos y como puedes optimizar tus bĆŗsquedas al hacer webscraping.
Si quieres recibir estas publicaciones desde tu correo electrĆ³nico, te invito a suscribirte.
Cuando comencĆ© a construir mis primeros robots, uno de mis mayores dolores de cabeza eran las pĆ”ginas donde cambiaban los identificadores o la posiciĆ³n de sus elementos. Siempre tenĆa que recurrir a bucles + algĆŗn truco con javascript.
Cuando realicĆ© el rpachallenge, construĆ un robot que leĆa los labels y luego escribĆa en el input que se encontraba debajo. Mi robot demoraba cerca de 10 segundos en completar el formulario. El robot de mi compaƱero JosĆ© lo hacĆa en 1 segundo.
La diferencia entre los dos robots? JosĆ© usĆ³ un xpath que iba directo al input que necesitaba. 10x mĆ”s rĆ”pido su robot.
//input[@ng-reflect-name="labelPhone"]
ĀæQue es un xpath?
Mi definiciĆ³n de xpath es ā el camino (path) de todas las etiquetas que tienes que recorrer para llegar a un elemento xml o html (Similar a las rutas para encontrar una carpeta o una pĆ”gina web) potenciado con funciones o una sintaxis similar a las expresiones regulares.
XPath (XML Path Language) es un lenguaje que permite construir expresiones que recorren y procesan un documento XML. La idea es parecida a las expresiones regulares para seleccionar partes de un texto sin atributos (plain text). XPath permite buscar y seleccionar teniendo en cuenta la estructura jerƔrquica del XML.
Fuente: Wikipedia
Un xpath, igual que las rutas hacia una carpeta en una terminal, tiene dos tipos de sintaxis. Absolutas y relativas
Xpath absoluto
TambiĆ©n llamado full Xpath, es la ruta completa, desde la etiqueta raĆz del documento (/html en web) e indica el paso a paso hasta llegar al elemento que se busca.
La mayorĆa de los navegadores tienen la opciĆ³n de copiar este xpath, por lo que no ahondaremos mucho en esta sintaxis.
/html/body/div[1]/div[1]/div/div/div[5]/div[1]/div[3]
Xpath Relativo
Es la ruta, comenzando desde cualquier lugar del documento y se utiliza comenzando con dos slash (//tag). Esta sintaxis es muy Ćŗtil porque te permite eliminar las partes variables de la pĆ”gina y puedes comenzar a buscar los elementos desde un punto fijo.
En los navegadores cuando copias el xpath, estƔs copiando un tipo de xpath relativo, basado en el identificador mƔs cercano.
//*[@id="publish-main"]/div/div[5]/div[1]/div[3]/div[1]/div[3]
Sintaxis de un xpath
La sintaxis bĆ”sica de un xpath se conforma por tres partes: tipo de bĆŗsqueda (/ o //), la etiqueta y filtros(opcional). Esta sintaxis la podemos ir uniendo para formar xpath mĆ”s complejos e ir āmoviendoteā entre etiquetas hasta llegar al elemento que buscas
š”Cuando hablo de etiqueta, me refiero a los tags o elementos en html. Puedes tomar un curso de bĆ”sico de 10 min de html para comprender los conceptos
//etiqueta[filtros]
š Tipo de bĆŗsqueda ā Define si queremos buscar de forma relativa o absoluta. Si indicamos un /, significa que el elemento que queremos buscar, estĆ” en el nivel siguiente de donde nos encontramos. Mientras que si usamos //, significa que el elemento puede estar en cualquier nivel de profundidad desde donde nos encontramos
š·ļø Etiqueta ā Es la etiqueta xml o html que buscamos. Ej. html, div, a, span, etc. TambiĆ©n puedes usar carĆ”cteres especiales, como * para buscar cualquier etiqueta, o .. para referenciar la etiqueta anterior a donde estĆ”s.
ā¬ Filtros ā Son las reglas y condiciones que aplicamos para diferenciar una etiqueta de otra. Ej, @id="value", contains(),text(), etc
Un xpath estƔ conformado por una secuencia de esta estructura bƔsica. Analicemos el siguiente Xpath:
//*[@id="publish-main"]/div/div[5]/div[1]
Comienza con //, lo que significa que lo que viene a continuaciĆ³n puede estar en cualquier lugar de la pĆ”gina
Tiene un *, lo que significa que puede ser cualquier etiqueta html
ContinĆŗa con informaciĆ³n entre [ ], esto significa que tendrĆ” un filtro para diferenciar la etiqueta del punto 2, ue hasta ahora puede ser cualquiera
@id="publish-main": Significa que la condiciĆ³n es que el atributo id del elemento, debe tener el valor de publish-main
Si leemos todo junto para la primera parte del xpath, tenemos que: busco en cualquier parte de la pƔgina, un elemento que puede ser de cualquier etiqueta, pero que su id sea publish-main
Luego tenemos otros xpath concatenados /div/div[5]/div[1].
Los / significan que serĆ”n bĆŗsquedas absolutas, o sea, /div es el siguiente div despuĆ©s de //*[@id="publish-main"]
Luego, y de forma repetitiva hasta el final, tenemos /div[numero]. Esto lo podemos leer como: de forma absoluta al div anterior, busco la etiqueta div siguiente y de todos los resultados, quiero el que estĆ© en la posiciĆ³n ānĆŗmeroā
Si vez la imagen de abajo, tenemos marcado el div con el id publish-main, luego la etiqueta siguiente es un div y dentro de Ć©ste, hay varios div mĆ”s. El xpath que estamos analizando, nos dice que el div por donde pasaremos, es el div nĆŗmero 5 y finalmente, llegaremos al div nĆŗmero 1 (el marcado en amarillo, con clase āpost typography containerā
El xpath que analizamos fue copiado directamente del navegador y usa el āidā como punto de inicio para crear el xpath. Una forma diferente para crear nuestro xpath es yendo directo a lo que queremos: //div[@class="post typography container"].
Tipos de filtros
Lo que llamaremos filtros, son funciones y/o condiciones que āfiltranā los resultados obtenidos al crear una xpath solo con etiquetas. Estas pueden combinarse para crear xpath muy complejos, igual como las expresiones regulares. A continuaciĆ³n los mĆ”s usados por mi.
Filtro por attributo
Este tipo de filtro es el mĆ”s comĆŗn o bĆ”sico y utiliza el atributo del elemento para condicionar la bĆŗsqueda. En los ejemplos anteriores utilizamos el atributo id y class.
//tag[@attributo=āvalueā]
Si tomamos como ejemplo el login de facebook, podemos filtrar el input de email por el atributo ānameā y usar un xpath como: //input[@name="email"]
Filtro por texto
Este filtro es similar al anterior, pero en lugar de usar un atributo, usaremos el texto que contiene la etiqueta. Para esto, en lugar de usar @attributo, usaremos el mƩtodo o keyword text().
//tag[text()=āvalueā]
Siguiendo con el ejemplo de Facebook, podemos encontrar el botĆ³n de iniciar sesiĆ³n con el xpath: //button[text()="Iniciar sesiĆ³n"]
ā ļø Para usar este xpath, tienes que asegurarte que el idioma de la pĆ”gina no cambie. Para la versiĆ³n de facebook en inglĆ©s, el texto es āLog Inā
Filtro con functiones
Existen muchas funciones para filtrar y todo el tiempo aprendo una nueva. AcƔ te enseƱarƩ las 3 que mƔs he usado
contains()
Esta funciĆ³n, como su nombre lo dice, permite buscar por un valor contenido en otro. Por ejemplo, la palabra "nacional" existe dentro de la palabra "internacional".
Esta funciĆ³n recibe dos parĆ”metros, el filtro (attributo, text(), etc.) y el sub valor a encontrar.
//etiqueta[contains(@atributo, āvalorā)]
Tomemos como ejemplo la pĆ”gina de ArenaRPA, y supongamos que la pĆ”gina puede estar en inglĆ©s o espaƱol. Si quisiĆ©ramos dar click en el botĆ³n para descargar el excel usando un filtro por texto, podrĆamos usar un xpath asĆ: //a[text()="Descargar Excel"]
Si la pĆ”gina cambia de idioma, el botĆ³n dirĆa algo como āDownload Excelā, haciendo que falle la bĆŗsqueda. Para este caso usamos el contains(), buscamos una etiqueta "a" que contenga la palabra "Excel", quedando un xpath asĆ: //a[contains(text(), "Excel")]
No solo funciona con text(), puedes usar atributos, como un href: //a[contains(@href, ā/crazy-formā)
not()
Esta funciĆ³n nos sirve para negar la condiciĆ³n que estemos usando, o en otras palabras, indica al xpath que haga lo contrario de lo que indicamos. Esta funciĆ³n se usa normalmente como complemento de otro filtro.
//etiqueta[not(filtro)]
Si seguimos tomando el ejemplo de ArenaRPA, y quisieramos encontrar todas las etiquetas a que no tengan el atributo href (como el botĆ³n "Descargar Excel" o "Iniciar Reto") podrĆamos usar un xpath asĆ: //a[not(@href)]
starts-with()
Esta funciĆ³n es similar al contains(), recibe los mismos parĆ”metro, pero en lugar de buscar un texto contenido en otro, busca un texto que comienza con lo que le indiquemos.
//etiqueta[starts-with(@attributo, "value")]
Como ejemplo, hagamos webscraping a Twitter y busquemos todos los tweets que comiencen con el texto "Web scraping".
Nuestro xpath quedarĆa asĆ: //*[starts-with(text(), 'Web scraping')]
Filtro por nombre de etiqueta
Este filtro puede parecer innecesario, ya que los xpath por si mismo ya contienen el nombre de la etiqueta, pero es muy Ćŗtil cuando se usa con otras funciones. Los casos de usos para este tipo de filtro son pĆ”ginas con etiquetas personalizadas
//*[name()="etiqueta"]
En la pĆ”gina de rpachallenge, tenemos una etiqueta propia de la pĆ”gina llamada "rpa1-field", el xpath para encontrarla es el siguiente: //rpa1-field. Si lo vemos asĆ, el keyword name() no es necesario.
Ahora supongamos que lo que estĆ” despuĆ©s del rpa1- es variable. Para estos casos nos sirve el filtro por etiqueta. En conjunto con el filtro starts-with, podemos crear un xpath asĆ: //*[starts-with(name(),"rpa1-")]
No confundir con el attributo name, que vimos para el ejemplo de facebook. Para buscar por el attributo se debe usar @name
Filtro con multiples condiciones
Cuando vimos la funciĆ³n contains(), tuvimos el caso de tener un botĆ³n en dos idiomas. Una alternativa para esos casos es usar el keyword or para buscar un elemento si cumple una condiciĆ³n u (or) otra.
//etiqueta[filtro1 or filtro2]
En el caso de ArenaRPA, podemos usar el xpath asĆ: //a[text()=" Descargar Excel " or text()="Download Excel"]
Al igual que un or, podemos usar un and, para crear un xpath que cumpla dos condiciones a la vez
//etiqueta[filtro1 and filtro2]
Este es el xpath para encontrar el botĆ³n de login de Facebook usando una condiciĆ³n and: //*[text()="Log In" and @name="login"]. Esto lo podemos leer como, un elemento que tenga el texto "Log In" y tenga el atributo name igual a "login"
Filtro por orden o posiciĆ³n
Este tipo de filtro lo vimos en los primeros ejemplos. Simplemente tenemos que indicar el orden del elemento que queremos buscar cuando existe mƔs de un mismo resultado.
/*/tag[orden]
Este tipo de filto se utiliza con una bĆŗsqueda absoluta, por lo que siempre viene despuĆ©s de un solo slash (/tag). Para encontrar el primer cuadro de resultados en una busqueda en google, este es el xpath: //*[@id="rso"]/div[1]/div/div/div/div[1].
La Ćŗtlima parte del xpath indica que se debe tomar el primer div que se encuentre. Si no se indica el 1, encontrarĆ” dos resultados
Axes o Ejes
Los Axes (o ejes en espaƱol) son una relaciĆ³n que se apoya del elemento actual y se utiliza para localizar nodos relativos a este. El uso de estos serĆa:
Buscas un elemento creando un xpath y luego en base a ese resultado, nos moveremos al nivel que queramos
//xpath//axe::tag
Existen mƔs de 10 axes diferentes, pero en este post veremos los que mƔs he utilizado.
š¶child::
Este axes te permite encontrar los elementos hijos del elemento donde te encuentras.
//*[@ng-reflect-dictionary-value="Phone Number"]//child::input
El xpath anterior es utilizado para encontrar el campo de nĆŗmero de telĆ©fono en el rpachallenge. Este se lee asĆ:
Encuentra una etiqueta que tenga el atributo ng-reflect-dictionary-value con el valor "Phone Number". Una vez encuentras ese elemento, busca los hijos con la etiqueta input
š§ancestor::
Este axes encuentra todos los ancestros (padre, abuelo, etc.) del elemento donde te encuentres
//h3[text()="text"]//ancestor::a
El xpath anterior es utilizado para encontrar el link del primer resultado de una bĆŗsqueda en google. Si la bĆŗsqueda es "robotipyā se leerĆa asĆ:
Encuentra una etiqueta h3 con el texto igual a "robotipy" y desde ese elemento, busca un ancestro con la etiqueta a
šØparent::
Este eje es similar a ancestor::, con la diferencia que solo encuentra el padre del elemento actual. Ignora cualquier otra ascendencia.
Siguiendo el ejemplo anterior, el xpath es el siguiente:
//h3[text()="robotipy"]//parent::a
āļøfollowing::
Este axes encuentra todo lo que hay en el documento despuĆ©s del elemento actual. Si se requiere encontrar un elemento en particular, se tiene que combinar con algĆŗn otro filtro.
//h3[text()="robotipy"]//following::a[1]
El xpath anterior, tambiĆ©n busca un h3 con el texto "robotipy", y una vez encontrado el elemento, buscarĆ” cualquier etiqueta "a" que venga a continuaciĆ³n. Para filtrar por un Ćŗnico valor, se utiliza [1] para encontrar el primer resultado
Y esto es todo lo que necesitas saber para comenzar con xpath. Faltan muchos otros mĆ©todos y axes que podrĆas aprender pero el post se harĆa eterno.
Te dejo algunos recursos que he utilizado para ir aprendiendo sobre esto y pronto publicarĆ© alguna ayuda resumida para que tengas como guĆa.
Si encontraste valor en este newsletter, considera compartirlo con tu equipo
Ten una gran semana! š
Danilo