Volver al blog
Guías
Suciu DanLast updated on Apr 29, 202611 min read

XPath Web Scraping: Guía práctica con ejemplos en Python

XPath Web Scraping: Guía práctica con ejemplos en Python
En resumen: XPath es un lenguaje de consulta que permite navegar por árboles HTML/XML mediante rutas, atributos o contenido de texto. Esta guía aborda la sintaxis, los ejes y las funciones de XPath, y a continuación muestra ejemplos prácticos de rastreadores en Python con lxml y Selenium. También encontrarás una hoja de referencia consolidada y una sección de resolución de problemas para los errores más comunes de XPath.

XPath (XML Path Language) es un lenguaje de consulta que selecciona nodos de documentos XML y HTML utilizando expresiones de ruta. Si los selectores CSS te parecen demasiado limitados para tus tareas de scraping, el scraping web con XPath es el siguiente paso lógico.

Mientras que los selectores CSS solo se desplazan hacia adelante y hacia abajo a través del DOM, XPath recorre el árbol en cualquier dirección: hacia arriba hasta un padre, lateralmente hacia un hermano o en profundidad hacia descendientes anidados. También puede hacer coincidir elementos por su texto visible, una capacidad de la que CSS carece por completo. Estas características hacen que XPath para el scraping web sea especialmente valioso en páginas complejas o mal estructuradas.

En este tutorial aprenderás la sintaxis básica de XPath (rutas, predicados, ejes, funciones), verás cómo probar expresiones en tu navegador y crearás rastreadores reales en Python con lxml y Selenium. También abordaremos los errores comunes que hacen fallar a los selectores XPath en producción y cómo evitarlos.

¿Qué es XPath y por qué utilizarlo para el web scraping?

XPath trata un documento HTML o XML como un árbol de nodos y te ofrece una sintaxis compacta para señalar exactamente los que necesitas. Piensa en ello como una ruta de archivo: al igual que /home/user/docs/file.txt se navega por los directorios, /html/body/div/p recorre el árbol DOM hasta un párrafo específico.

Tres razones por las que XPath destaca para el scraping:

  1. Recorrido bidireccional. XPath se desplaza hacia arriba, hacia elementos padres o ancestros, no solo hacia abajo. Los selectores CSS solo avanzan hacia adelante.
  2. Selección basada en texto. Puedes encontrar elementos por el texto visible (por ejemplo, la <a> etiqueta que dice «Página siguiente»), algo que CSS no puede hacer.
  3. Funciones integradas. contains(), starts-with(), y normalize-space() te permiten manejar marcado desordenado sin expresiones regulares.

Escribir expresiones XPath sólidas es una habilidad práctica que da sus frutos rápidamente en cualquier cosa que vaya más allá de páginas triviales. XPath es compatible con muchos lenguajes (Python, JavaScript, C#, PHP), por lo que el conocimiento de la sintaxis se transfiere directamente independientemente de tu pila tecnológica.

Cómo se conecta el DOM a las expresiones XPath

El Modelo de Objetos de Documento (DOM) estructura cada elemento HTML, atributo y nodo de texto en un árbol donde cada nodo tiene un padre, hijos y hermanos. Considera este marcado:

<ul id="menu">
  <li class="active">Home</li>
  <li>About</li>
</ul>

Aquí <ul> es el padre. Los <li> elementos son sus hijos y hermanos entre sí. El XPath //ul[@id='menu']/li[1] dice: busca cualquier <ul> con id="menu", y luego toma su primer <li> hijo. Toda consulta XPath es, en última instancia, un conjunto de instrucciones a través de esta estructura padre-hijo-hermano, por lo que es importante comprender el DOM antes de escribir cualquier selector.

Fundamentos de la sintaxis XPath

Las rutas XPath pueden ser de dos tipos. Las rutas absolutas comienzan desde la raíz (/html/body/div/p) y son precisas pero frágiles: un solo cambio estructural las invalida. Las rutas relativas comienzan con // y recorren todo el árbol, lo que las hace mucho más resistentes para los flujos de trabajo de web scraping con XPath.

Operador

Significado

Ejemplo

/

Hijo directo

/html/body/div

//

Cualquier descendiente

//div[@class='price']

..

Nodo padre

//span/..

@

Acceso a atributos

//a[@href]

Selección de nodos con predicados

Los predicados son filtros entre corchetes que restringen un conjunto de nodos:

//ul/li[1]                  ← first <li>
//ul/li[last()]              ← last <li>
//input[@type='email']       ← by attribute
//a[text()='Next Page']      ← by exact text
//span[contains(text(),'$')] ← by partial text

Los predicados son lo que hace que las expresiones XPath sean realmente potentes para la extracción de datos. Sin ellos, necesitarías código de posprocesamiento para filtrar las coincidencias no deseadas de tus resultados.

Ejes de XPath: navegación en todas las direcciones

Los ejes definen la dirección de recorrido con respecto al nodo actual, y son la razón principal por la que los selectores de XPath para el scraping web pueden llegar a elementos a los que el CSS simplemente no puede acceder.

Eje

Dirección

Caso de uso de scraping

child::

Hijos directos

Seleccionar <li> elementos dentro de un <ul>

descendant::

Todos los nodos anidados

Obtener todos los enlaces dentro de un contenedor

parent::

Subir un nivel

A partir de un precio <span>, llegar a su producto <div>

ancestor::

Cualquier antecesor

Desde una celda, encuentra <table> al que pertenece

following-sibling::

Siguientes hermanos

Después de una <dt> etiqueta, toma el <dd> valor

preceding-sibling::

Hermanos anteriores

Desde un elemento conocido, busca hacia atrás un encabezado

Ejemplo práctico para extraer una lista de definiciones:

undefined//dt[text()='Price']/following-sibling::dd[1]

Esto extrae el primer <dd> después del <dt> que contenga «Precio». El following-sibling hace que esto sea trivial, mientras que CSS requeriría JavaScript adicional o lógica de envoltura.

Potentes funciones XPath para el scraping

El HTML del mundo real es desordenado. Las funciones de XPath te ayudan a escribir selectores que sobreviven a clases dinámicas, espacios en blanco ocultos y valores de atributos cambiantes.

contains(@class, 'product')       ← matches "product-card", "product_item"
starts-with(@id, 'listing-')      ← matches "listing-001", "listing-002"
text()                             ← targets visible text content
normalize-space()='In Stock'       ← collapses whitespace before comparing
not(contains(@class, 'ad'))        ← excludes ad containers

contains() es especialmente útil en páginas donde los marcos añaden sufijos generados a los nombres de clase. normalize-space() resuelve el frustrante problema en el que un selector XPath parece correcto pero falla porque el texto está rodeado de tabulaciones o saltos de línea ocultos. En conjunto, estas funciones hacen que tus expresiones XPath sean resistentes en sitios web reales donde la consistencia del marcado nunca está garantizada.

Hoja de referencia rápida de XPath

Añade esta referencia consolidada a tus favoritos para consultarla rápidamente mientras escribes tus selectores XPath de scraping web.

Categoría

Sintaxis

Qué hace

Ruta

//tag

Todas las etiquetas coincidentes en cualquier lugar

Ruta

/parent/child

Hijo directo

Ruta

..

Nodo padre

Predicado

[n]

Enésimo elemento (a partir de 1)

Predicado

[@attr='val']

Filtrar por atributo

Eje

ancestor::tag

Cualquier antecesor

Eje

following-sibling::tag

Siguiente hermano

Función

contains()

Coincidencia parcial de cadena

Función

normalize-space()

Recortar espacios en blanco

Función

text()

Seleccionar contenido de texto

Para obtener información más detallada sobre los operadores y las expresiones compuestas, nuestra hoja de referencia de XPath ofrece una guía ampliada.

Probar XPath en las herramientas de desarrollo del navegador

Antes de escribir código, valida tus expresiones XPath en el navegador. Abre DevTools (F12), ve al panel Elementos y pulsa Ctrl+F (Cmd+F en Mac). La barra de búsqueda acepta XPath y resalta los nodos coincidentes en tiempo real.

También puedes hacer clic con el botón derecho en cualquier elemento y seleccionar Copiar > Copiar XPath. Ten cuidado: el navegador genera rutas absolutas como /html/body/div[3]/section[1]/ul/li[2]/a que se rompen ante cualquier cambio estructural. Reescribe siempre las rutas generadas automáticamente en expresiones relativas ancladas en atributos estables (ID, data-* nombres de clases semánticas) en lugar de índices posicionales.

Extracción de datos web con XPath en Python: paso a paso

Pongamos en práctica XPath con Python. Las dos bibliotecas más comunes para el web scraping con XPath en Python son lxml (HTML estático) y Selenium (páginas renderizadas en JavaScript). A continuación, nos centramos en el mismo sitio con ambas para que puedas comparar directamente la ergonomía de las API.

Uso de XPath con lxml

lxml es una biblioteca rápida, basada en C y construida sobre libxml2. Si la página no requiere JavaScript, lxml es la elección adecuada.

import requests
from lxml import html

response = requests.get("https://books.toscrape.com/")
tree = html.fromstring(response.content)
titles = tree.xpath('//article[@class="product_pod"]/h3/a/@title')
for title in titles:
    print(title)

Recupera el HTML con requests, analízalo con html.fromstring(), y consulta con .xpath(). El resultado es una lista simple de Python. Para patrones de scraping de Python más amplios, nuestra guía sobre scraping web con Python trata en profundidad el manejo de solicitudes y el almacenamiento de datos.

Uso de XPath con Selenium

Cuando las páginas muestran contenido mediante JavaScript, necesitas un motor de navegador. Selenium controla un navegador sin interfaz gráfica y expone XPath a través de find_elements. A partir de Selenium 4, según se informa, WebDriver viene incluido en el paquete (compruébalo en las notas de la versión actual de Selenium antes de darlo por hecho).

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://books.toscrape.com/")
elements = driver.find_elements(By.XPATH, '//article[contains(@class,"product_pod")]/h3/a')
for el in elements:
    print(el.get_attribute("title"))
driver.quit()

El XPath es casi idéntico a la versión de lxml. La diferencia está en la API: .xpath() frente a find_elements(By.XPATH, ...). Para obtener más información sobre los flujos de trabajo de navegadores sin interfaz gráfica, nuestro tutorial de scraping con Selenium y Python repasa los patrones de automatización. Elige lxml para páginas estáticas y recurre a un navegador sin interfaz gráfica solo cuando la ejecución de JavaScript sea realmente necesaria.

Selector XPath frente a selector CSS: cuándo usar cada uno

Criterios

XPath

Selectores CSS

Dirección

Arriba, abajo, lateralmente

Solo hacia adelante

Coincidencia de texto

Nativo (text(), contains())

No compatible

Legibilidad

Detallado pero explícito

Conciso

Rendimiento

Aproximadamente igual en la práctica

Ligeramente más rápido en las pruebas de rendimiento

Curva de aprendizaje

Más pronunciada

Más fácil

Utiliza CSS cuando los objetivos sean accesibles solo por clase o ID. Utiliza XPath para tareas de scraping que requieran recorrido de elementos padres, coincidencia de texto o navegación multieje. Muchos scrapers experimentados combinan ambos libremente. Para una comparación más detallada, nuestra página sobre selectores XPath frente a CSS aborda casos extremos adicionales y estrategias de selección.

En cuanto al rendimiento, a veces se dice que XPath es más lento, aunque la diferencia suele ser insignificante cuando la latencia de la red domina tu carga de trabajo de scraping. La velocidad del selector rara vez se convierte en el cuello de botella en proyectos reales.

Errores comunes de XPath y cómo solucionarlos

Rutas autogeneradas inestables. Los XPath copiados del navegador utilizan índices absolutos. Reescríbelos para anclarlos a atributos estables como @id o @data-testid.

Colisiones de espacios de nombres. Si XPath no devuelve ningún resultado en páginas XHTML, es probable que los prefijos de los espacios de nombres estén interfiriendo. Utiliza local-name() para evitarlos: //*[local-name()='div'].

Discrepancias en los espacios en blanco. text()='In Stock' falla cuando el código fuente contiene saltos de línea ocultos o tabulaciones. Envuelve la comprobación en normalize-space() para eliminar primero los espacios en blanco.

Nombres de clase dinámicos. Los marcos como React generan nombres de clase con hash (p. ej., card__a3xK2). Usa contains(@class, 'card') para hacer coincidir solo el prefijo estable.

Prueba tus selectores XPath en una pequeña muestra antes de escalar a miles de páginas. Depurar un selector defectuoso en una sola página es sencillo; depurarlo tras una ejecución por lotes a gran escala supone una pérdida de tiempo y ancho de banda.

Conclusiones clave

  • XPath navega por el HTML en cualquier dirección, lo que lo hace más versátil que los selectores CSS para tareas complejas de scraping.
  • Prefiere siempre las rutas relativas (//) en lugar de las rutas absolutas para que los selectores sean resistentes a los cambios en el DOM.
  • Utilice funciones como contains(), normalize-space(), y text() para gestionar el marcado desordenado del mundo real.
  • Para HTML estático, lxml es la opción más rápida en Python. Reserva Selenium para páginas que requieran renderización con JavaScript.
  • Prueba primero cada expresión XPath en las herramientas de desarrollo del navegador y reescribe las rutas generadas automáticamente para utilizar anclajes estables.

Preguntas frecuentes

¿Es XPath mejor que los selectores CSS para el web scraping?

Ninguno de los dos es universalmente mejor. XPath destaca cuando se necesita recorrer elementos padres, realizar coincidencias basadas en texto o aplicar filtrados complejos. Los selectores CSS son más rápidos de escribir para selecciones sencillas de clases o ID y suelen ofrecer un rendimiento ligeramente superior en pruebas sintéticas. La mayoría de los rastreadores en producción utilizan ambos, eligiendo el que mejor se adapte a cada tarea de selección específica.

¿Puede XPath extraer páginas renderizadas con JavaScript?

XPath es un lenguaje de consulta, no un motor de renderizado. Opera sobre cualquier DOM que reciba. Para extraer contenido renderizado con JavaScript, primero necesitas una herramienta que ejecute el JavaScript de la página (como un navegador sin interfaz gráfica), y luego aplicar expresiones XPath al DOM resultante. Los analizadores estáticos solo ven la respuesta sin procesar del servidor antes de cualquier renderizado del lado del cliente.

¿Qué biblioteca de Python es la mejor para el scraping web con XPath?

Para páginas estáticas, lxml es el estándar: rápido, bien documentado y respaldado por bibliotecas C de probada eficacia. Para páginas dinámicas, Selenium ofrece compatibilidad con XPath a través de su find_elements API. Scrapy también ofrece compatibilidad nativa con XPath a través de su clase Selector, lo que la convierte en una opción sólida para procesos completos de rastreo.

¿Por qué el XPath copiado de Chrome DevTools a veces falla en el código?

Chrome genera rutas absolutas con índices posicionales basados en el DOM en tiempo real, que puede incluir elementos inyectados por JavaScript o extensiones del navegador. Cuando tu analizador procesa el HTML sin procesar (antes de que se ejecute JS), la estructura difiere, por lo que los índices posicionales apuntan a elementos incorrectos. Reescribe la expresión utilizando atributos estables en lugar de posiciones.

Conclusión

El web scraping con XPath te ofrece un nivel de precisión que los métodos de selección más simples no pueden igualar. Con la sintaxis, los ejes, las funciones y los patrones de Python tratados aquí, deberías estar preparado para manejar todo, desde la selección básica de atributos hasta la navegación por páginas profundamente anidadas y con estructuras inconsistentes.

La clave para mejorar es la práctica: empieza con un objetivo sencillo, prueba las expresiones en DevTools y añade complejidad gradualmente. Mantén los selectores relativos, recurre a las funciones para la variabilidad del marcado y valida siempre en un pequeño lote antes de escalar.

Cuando las protecciones antibots, los CAPTCHAs o la gestión de proxies empiecen a consumir más tiempo que tu lógica XPath real, WebScrapingAPI se encarga de la capa de solicitudes por ti, gestionando la rotación de proxies y las contramedidas de bloqueo detrás de un único punto final para que puedas centrarte en selectores limpios y en el procesamiento de datos.

Acerca del autor
Suciu Dan, Cofundador @ WebScrapingAPI
Suciu DanCofundador

Suciu Dan es cofundador de WebScrapingAPI y escribe guías prácticas dirigidas a desarrolladores sobre el scraping web con Python, el scraping web con Ruby y las infraestructuras de proxy.

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.