Guía completa de raspado web con XPath 2026: La esencia de la extracción precisa de datos en la web

He recopilado completamente cómo hacer web scraping con XPath desde cero hasta la práctica. Incluye ejemplos de Python lxml/requests, comparación con Selectores CSS y una referencia de expresiones clave, todo actualizado hasta el año 2026.

32
Guía completa de raspado web con XPath 2026: La esencia de la extracción precisa de datos en la web

웹 rastreo comienza aprendiendo principalmente el Selector CSS. Sin embargo, cuando te encuentras con páginas un poco más complejas en la práctica, a menudo te resulta difícil extraer los elementos deseados solo con el Selector CSS. Es cuando necesitas XPath.

XPath es un lenguaje de consulta estándar para explorar nodos específicos en documentos XML/HTML. Es más potente que el Selector CSS y en algunos casos te permite realizar selecciones que simplemente no son posibles con CSS. Hasta el año 2026, todas las principales herramientas de rastreo como Python lxml, Scrapy, Playwright, Selenium, admiten XPath.

En este artículo, cubriremos desde los conceptos básicos de XPath hasta el código práctico de rastreo y consejos de depuración.


1. ¿Qué es XPath?

XPath (Lenguaje de Ruta XML) es un estándar del W3C para consultar la estructura de árbol de documentos XML y HTML. Desde su introducción en 1999, se ha convertido en una tecnología central de los estándares web.

El HTML de una página web es una estructura de árbol. Comenzando desde la raíz html, se conectan los elementos body, varios div, span, etiquetas a en relaciones padre-hijo. XPath representa esta estructura de árbol de manera similar a una ruta de sistema de archivos, por ejemplo, /html/body/div/p para especificar un nodo en HTML.

Selector CSS vs XPath: ¿Cuándo usar cada uno?

Función Selector CSS XPath
Selección de elementos básicos Conciso Posible
Selección de elementos que contienen texto específico No es posible contains(text(), 'palabra clave')
Selección de nodos padres en dirección inversa No es posible .. o parent::
Acceso a nodos hermanos Limitado following-sibling::, preceding-sibling::
Filtrado condicional Básico Condiciones complejas posibles
Dificultad de aprendizaje Fácil Intermedia
Rendimiento del navegador Rápido Ligeramente más lento

En el rastreo web convencional, es efectivo utilizar el Selector CSS como base y complementarlo con XPath cuando CSS no sea suficiente.


2. Referencia de sintaxis clave de XPath

Expresiones de ruta básicas

/html/body/div          # 절대 경로 (루트부터 전체 경로)
//div                   # 문서 전체에서 모든 div 요소
//div[@class='title']   # class 'title' div
//a[@href]              # href 속성이 있는 모든 a 태그

El doble slash // es fundamental. En la práctica, se utiliza mucho más la ruta relativa con // que la ruta absoluta (/html/body/...) ya que es más estable ante cambios en la estructura de la página.

Selector de atributos

//div[@id='main']                    # id 'main' div
//input[@type='submit']              # type 'submit' input
//a[contains(@class, 'btn')]         # class 'btn' 포함된 a
//img[@src and @alt]                 # src alt 속성 모두 있는 img
//a[not(@href)]                      # href 없는 a 태그

contains() es similar a [class*="btn"] en CSS, pero se puede aplicar también al contenido de texto, lo que lo hace mucho más flexible.

Selector de texto

//h2[text()='이벤트 공지']                    # 정확히 '이벤트 공지' 텍스트인 h2
//p[contains(text(), '할인')]                  # '할인' 텍스트를 포함하는 p
//button[normalize-space(text())='구매하기']   # 공백 제거  '구매하기' 버튼

Esta es la ventaja clave de XPath. Mientras que el Selector CSS no puede seleccionar elementos basados en el contenido de texto, XPath permite la selección libre basada en texto combinando text() y contains().

Búsqueda de ejes (Axis)

//span[@class='price']/parent::div          # 특정 span 부모 div
//td[contains(@class, 'total')]/../td[1]    # 형제 td  번째
//h3/following-sibling::p                   # h3 다음에 오는 형제 p 태그
//li[last()]                                # 마지막 li 항목
//li[position() <= 5]                       #  5 li 항목

La búsqueda de nodos padres en dirección inversa es una característica exclusiva de XPath. Es útil, por ejemplo, cuando deseas obtener todo el contenedor de tarjetas que contienen un botón de una clase específica.


3. Rastreo con XPath en Python (lxml)

Instalación básica y estructura

import requests
from lxml import html

url = "https://example.com/products"
response = requests.get(url, headers={
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
})

tree = html.fromstring(response.content)

# XPath로 데이터 추출
titles = tree.xpath('//h2[@class="product-title"]/text()')
prices = tree.xpath('//span[@class="price"]/text()')
links = tree.xpath('//a[@class="product-link"]/@href')

for title, price, link in zip(titles, prices, links):
    print(f"{title} | {price} | {link}")

Simplemente analiza el HTML con lxml.html.fromstring() y luego pasa la expresión XPath al método .xpath(). El resultado es una lista.

Selección de texto vs selección de @atributos

# 요소 텍스트 추출: /text()
titles = tree.xpath('//h1/text()')

# 속성값 추출: /@속성명
hrefs = tree.xpath('//a/@href')
images = tree.xpath('//img/@src')

# 요소 객체 자체를 가져올 때 (하위 탐색 필요 시)
product_cards = tree.xpath('//div[@class="product-card"]')
for card in product_cards:
    title = card.xpath('.//h2/text()')  # 점(.)은 현재 요소 기준
    price = card.xpath('.//span[@class="price"]/text()')
    print(title[0] if title else "N/A", price[0] if price else "N/A")

Importante saber: al iterar sobre objetos de elementos, debes agregar un punto (.) al usar .xpath() interno para buscar en relación al elemento actual. Si usas //h2/text() sin el punto, buscará en todo el documento nuevamente.

Selección flexible con contains()

# class에 특정 단어가 포함된 경우
items = tree.xpath('//*[contains(@class, "item")]')

# 텍스트에 특정 단어가 포함된 링크
discount_links = tree.xpath('//a[contains(text(), "할인")]/@href')

# 여러 조건 조합 (and/or)
main_buttons = tree.xpath('//button[contains(@class, "btn") and @type="submit"]')

4. Rastreo de páginas dinámicas: Playwright + XPath

El HTML estático se puede manejar con requests + lxml, pero para páginas dinámicas renderizadas con JavaScript, se necesitan herramientas como Playwright o Selenium. Ambas herramientas admiten XPath.

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto("https://target-site.com")

    # XPath로 요소 선택
    # locator 방식 (권장)
    price = page.locator('xpath=//span[@class="final-price"]').first.text_content()

    # evaluate로 XPath 직접 실행
    result = page.evaluate("""
        () => {
            const el = document.evaluate(
                '//h1[@class="product-name"]/text()',
                document,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;
            return el ? el.nodeValue : null;
        }
    """)

    print(price, result)
    browser.close()

Para Playwright, simplemente agrega el prefijo xpath= a la expresión XPath al usar locator('xpath=...').


5. Depuración de XPath: Prueba directamente en el navegador

Antes de escribir código de rastreo, puedes verificar si el XPath es correcto directamente en el navegador.

Cómo usar las herramientas de desarrollo de Chrome:
1. Presiona F12 o haz clic derecho → Inspeccionar
2. Selecciona la pestaña Consola
3. Ingresa el siguiente código:

// 단일 요소 찾기
$x('//h1[@class="title"]')

// 모든 매칭 요소 텍스트 출력
$x('//span[@class="price"]').map(e => e.textContent)

// 첫 번째 매칭 텍스트
$x('//div[@class="product-name"]')[0]?.textContent

$x() es una función de prueba XPath integrada que está disponible en Chrome y Firefox. Asegúrate siempre de que los elementos deseados se seleccionen correctamente antes de escribir el código.


6. Ejemplo práctico: Extracción de datos de productos de comercio electrónico

import requests
from lxml import html

def scrape_product_list(url):
    headers = {"User-Agent": "Mozilla/5.0 (compatible; DataCollector/1.0)"}
    resp = requests.get(url, headers=headers, timeout=10)
    tree = html.fromstring(resp.content)

    # 상품 카드 전체 목록 가져오기
    cards = tree.xpath('//li[contains(@class, "product-item")]')

    results = []
    for card in cards:
        name = card.xpath('.//strong[@class="product-name"]/text()')
        price = card.xpath('.//span[contains(@class, "price")]/text()')
        rating = card.xpath('.//span[@class="rating"]/text()')
        reviews = card.xpath('.//span[@class="review-count"]/text()')
        link = card.xpath('.//a[@class="product-link"]/@href')

        results.append({
            "name": name[0].strip() if name else None,
            "price": price[0].strip() if price else None,
            "rating": rating[0].strip() if rating else None,
            "reviews": reviews[0].strip() if reviews else None,
            "url": link[0] if link else None,
        })

    return results

products = scrape_product_list("https://example-shop.com/category/shoes")
print(f"수집된 상품 수: {len(products)}")

7. Errores comunes y soluciones

IndexError: list index out of range

# 잘못된 방법
title = tree.xpath('//h1/text()')[0]  # 요소 없으면 에러 발생

# 올바른 방법
titles = tree.xpath('//h1/text()')
title = titles[0] if titles else None

Elemento visible pero no se puede seleccionar con XPath

La mayoría de las veces, el problema radica en el espacio de nombres o en problemas de renderización dinámica.

# 네임스페이스가 있는 경우
namespaces = {'ns': 'http://www.w3.org/1999/xhtml'}
result = tree.xpath('//ns:div[@id="content"]', namespaces=namespaces)

# 실제로 화면에는 있지만 XPath로 안 잡힐 때 → 동적 렌더링 확인
# requests로 받은 HTML에는 없고, 브라우저에서만 보이는 경우
# → Playwright/Selenium으로 전환 필요

Problemas de espacios en blanco al extraer texto

# normalize-space()로 앞뒤 공백 및 연속 공백 제거
clean_text = tree.xpath('normalize-space(//h1/text())')

# Python에서 후처리
texts = [t.strip() for t in tree.xpath('//p/text()') if t.strip()]

8. Límites de XPath y alternativas

Aunque XPath es poderoso, también tiene sus limitaciones.

Vulnerabilidad a cambios en la estructura: Si usas rutas absolutas (/html/body/div[2]/div[3]/ul/li), todo el XPath se vuelve inútil con un rediseño del sitio. Es preferible utilizar XPath basado en atributos como @id, @class.

Renderización JavaScript: XPath es una herramienta de análisis HTML, no de renderización. No puede recopilar contenido cargado dinámicamente solo con requests + lxml.

Rastreo a gran escala: Para recopilar miles de páginas, es mucho más eficiente utilizar Scrapy que administrar XPath por separado. Scrapy admite tanto XPath como Selector CSS, y ofrece manejo asíncrono, middleware y canalización.


Rastreo sin XPath con HashScraper

Aprender XPath es útil, pero mantener un rastreador de producción por tu cuenta puede ser costoso. Debes actualizar el XPath cada vez que cambie la estructura del sitio y ocuparte de problemas como la renderización JavaScript y la evasión de bloqueos de IP.

HashScraper maneja todo este proceso con una sola llamada de API. Simplemente proporciona la URL sin necesidad de XPath o Selector CSS, y obtendrás el HTML renderizado con JavaScript en formato Markdown, JSON o HTML.

import requests

response = requests.post(
    "https://api.hashscraper.com/v1/scrape",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "url": "https://target-site.com/products",
        "renderJs": True,
        "outputFormat": "markdown"
    }
)

data = response.json()
print(data["content"])  # 정제된 마크다운으로 반환

Si no quieres lidiar con la construcción de un rastreador por ti mismo o dedicar tiempo a administrar la infraestructura de rastreo, considera comenzar con la prueba gratuita de HashScraper.


Conclusión

  • XPath se utiliza para selecciones complejas que no se pueden lograr con Selector CSS
  • La selección basada en texto, la búsqueda de nodos padres en dirección inversa y el filtrado condicional son ventajas clave de XPath
  • Python: La combinación de lxml y .xpath() es la más común
  • Páginas dinámicas: Utiliza Playwright con locator('xpath=...')
  • Depuración: Prueba rápidamente con $x() en la consola de Chrome
  • Para rastreos a gran escala, considera utilizar la API de HashScraper en lugar de administrar XPath manualmente

Si este artículo te resultó útil, asegúrate de leer también la Guía completa de rastreo con Playwright y la Guía completa de rastreo con Scrapy.

Comments

Add Comment

Your email won't be published and will only be used for reply notifications.

Sigue leyendo

Get notified of new posts

We'll email you when 해시스크래퍼 기술 블로그 publishes new content.

Your email will only be used for new post notifications.