Volver al blog
Guías
Mihai MaximLast updated on May 7, 202612 min read

Web Scraping con Regex: Guía práctica

Web Scraping con Regex: Guía práctica
En resumen: el web scraping con expresiones regulares da lo mejor de sí cuando necesitas extraer patrones de texto breves y predecibles (precios, SKU, correos electrónicos, fechas) de código HTML en el que ya confías. Combina el módulo re con Beautiful Soup, limita tus patrones a un nodo analizado en lugar del marcado sin procesar y mantén las expresiones regulares al margen del análisis completo del árbol HTML. Esta guía repasa un rastreador funcional de títulos y precios, funciones avanzadas de expresiones regulares y los escollos que afectan a los rastreadores reales en producción.

Introducción

La mayoría de los extractores de Python acaban llegando a un punto en el que los selectores CSS y XPath dejan de ser suficientes. Tienes el <div>, pero dentro hay una cadena como "$1,299.00 USD (incl. VAT)" y solo necesitas el número. Ahí es donde el scraping web con expresiones regulares demuestra su valía: es una técnica de extracción de texto basada en patrones que se centra en formas específicas dentro del HTML sin procesar o del texto visible detrás de una página, en lugar de navegar por el árbol DOM.

Esta guía está dirigida a desarrolladores de Python de nivel intermedio que ya saben cómo recuperar una página con requests y analizarla con Beautiful Soup, y ahora quieren incorporar expresiones regulares a ese conjunto de herramientas sin que el scraper se vuelva inestable. Veremos cuándo es la mejor opción el web scraping con expresiones regulares (y cuándo realmente no lo es), una hoja de referencia de tokens centrada en el scraping, un scraper funcional de títulos y precios que genera CSV estructurado, y las re (grupos con nombre, lookarounds, indicadores, re.compile) que mantienen los patrones legibles a medida que el proyecto crece. También seremos sinceros sobre las limitaciones de las expresiones regulares con HTML dinámico y malformado, y sobre cuándo deberías recurrir a selectores o a una API de scraping gestionada.

Cuándo las expresiones regulares son la herramienta adecuada para el scraping (y cuándo no lo son)

Las expresiones regulares son excelentes para patrones de texto cortos y bien definidos: precios, fechas, ISBN, números de teléfono, hash, parámetros de consulta dentro de las URL. Son una mala elección para navegar por árboles HTML arbitrarios con etiquetas anidadas, atributos opcionales y espacios en blanco inconsistentes.

Una sencilla guía de decisión para el scraping web con expresiones regulares:

  • Recurre a las expresiones regulares cuando el campo tenga una forma estable (\d+\.\d{2}, un correo electrónico, un UUID), la página es HTML renderizado por el servidor y ya puedes aislar el nodo circundante con un analizador.
  • Evita las expresiones regulares cuando los datos estén ocultos en etiquetas profundamente anidadas, el marcado cambie los nombres de clase en cada implementación, o la página esté renderizada con JavaScript y los valores que buscas solo aparezcan después de que el navegador ejecute los scripts.

Hoja de referencia de tokens de expresiones regulares para el scraping

Solo necesitas un pequeño núcleo de tokens para casi cualquier tarea de scraping web con expresiones regulares. La tabla siguiente se centra en el scraping: cada ejemplo es algo que podrías extraer realmente del HTML.

Token

Con qué coincide

Ejemplo de scraping

\d

Cualquier dígito (0–9)

\d+ para un precio como 1299

\w

Caracteres de texto (letras, dígitos, _)

\w+ para un slug o SKU

\s

Cualquier espacio en blanco

Tolerancia al formato HTML irregular

.

Cualquier carácter excepto salto de línea

(.*?) dentro de una etiqueta, con re.DOTALL para varias líneas

^ / $

Inicio/fin de cadena (o línea)

Anclaje de un nodo de texto limpio

* + ?

0+, 1+, 0–1 repeticiones (codicioso)

\s* entre etiquetas

*? +?

Variantes no codiciosas

(.*?)</h2> para detenerse en la primera etiqueta de cierre

[...]

Clase de caracteres

[A-Z]{2,3} para un código de moneda

(...)

Grupo de captura

Extraer solo el precio de "$1,299.00 USD"

(?P<name>...)

Captura con nombre

(?P<price>\d+\.\d{2})

(?=...) / (?<=...)

Búsqueda hacia adelante/hacia atrás

\d+(?= USD) para que coincida con los dígitos anteriores USD

\\

Escapar

Coincidir con un literal . o $ en HTML

Para cualquier cosa más allá de esto, consulta la documentación del módulo re de Python y el manual oficial de expresiones regulares, en lugar de copiar y pegar de blogs aleatorios.

Paso a paso: extraer títulos y precios de productos con Python

Para concretar esto, extraeremos datos de una página estática de listado de productos y obtendremos dos campos: el título del producto y el precio. Elige cualquier entorno de pruebas o tienda de demostración en la que tengas permiso para extraer datos; el patrón que se muestra a continuación asume un HTML generado por el servidor con una ficha por producto. Los cuatro pasos secundarios abarcan la configuración del entorno, la obtención y el aislamiento de las fichas, la escritura de patrones y el guardado de la salida estructurada.

Configurar Python, requests y Beautiful Soup

Un entorno virtual limpio mantiene las dependencias controladas y el historial de tu shell en orden. El re se incluye en la biblioteca estándar, por lo que las únicas instalaciones de terceros son el cliente HTTP y el analizador. Si estás evaluando diferentes herramientas de extracción, nuestro resumen de clientes HTTP para Python es una buena lectura complementaria.

python -m venv .venv
source .venv/bin/activate     # Windows: .venv\Scripts\activate
pip install requests beautifulsoup4
import csv
import re
import requests
from bs4 import BeautifulSoup

Recupera la página y aísla las fichas de producto

Limita siempre el alcance antes de usar expresiones regulares. Aplicar patrones a un documento HTML completo es la forma de coincidir accidentalmente con la etiqueta equivocada dos mil líneas más abajo. Usa Beautiful Soup para extraer las fichas de productos y, a continuación, opera sobre el HTML de cada ficha de forma aislada. Si requests.get devuelve una <body> y los datos se encuentran en una <script> o solo se carga tras la ejecución de JS, las expresiones regulares sobre la respuesta sin procesar no te servirán; necesitas un navegador sin interfaz gráfica o una API de renderizado.

URL = "https://example.com/products"  # replace with a target you are allowed to scrape
html = requests.get(URL, timeout=15).text
soup = BeautifulSoup(html, "html.parser")
cards = soup.find_all("div", attrs={"data-testid": "product-card"})

Escribe patrones de expresiones regulares para títulos y precios

Ancla tus patrones a atributos estables, no a nombres de clases CSS con hash como css-7u5e79. Esos hash de clases se regeneran en cada implementación del front-end y tu scraper dejará de funcionar sin avisar. Prefiere data-* , etiquetas semánticas (<h4>, <h2>) o itemprop el marcado cuando el sitio lo exponga.

TITLE_RE = re.compile(r'<h4[^>]*itemprop="name"[^>]*>(.*?)</h4>', re.DOTALL)
PRICE_RE = re.compile(r'<span[^>]*itemprop="price"[^>]*>\s*\$?([\d,]+\.\d{2})\s*</span>')

Hay tres cosas que vale la pena destacar cuando se utiliza el scraping web con expresiones regulares en esta capa:

  • (.*?) no es «non-greedy»; sin el ? tu coincidencia de título se extendería alegremente a través de varias tarjetas.
  • [^>]* permite que la etiqueta tenga cualquier otro atributo (class, id, enlaces de análisis) sin romper la coincidencia.
  • re.DOTALL permite . coincidir con los saltos de línea, de modo que un título que se ajuste a una nueva línea siga siendo capturado.

Recorre los resultados y guárdalos en un archivo estructurado

Los volcados de texto sin formato están bien para la depuración, pero casi siempre se prefiere CSV o JSON para el trabajo posterior. El CSV con encabezados explícitos hace que la salida sea autodocumentada y fácil de cargar en pandas o en una hoja de cálculo. Mantén el HTML sin procesar, el CSV analizado y los registros de ejecución en carpetas separadas para que las repeticiones no se sobrescriban entre sí.

rows = []
for card in cards:
    html_chunk = str(card)
    t = TITLE_RE.search(html_chunk)
    p = PRICE_RE.search(html_chunk)
    rows.append({
        "title": t.group(1).strip() if t else "",
        "price_usd": p.group(1) if p else "",
    })

with open("data/products.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["title", "price_usd"])
    writer.writeheader()
    writer.writerows(rows)

Para campos anidados (variantes, especificaciones), cambia a JSON.

Combina expresiones regulares con Beautiful Soup para una extracción más limpia

Las expresiones regulares y un analizador HTML real no son competidores; son capas. Beautiful Soup recorre el árbol y te proporciona una cadena específica, y el uso de expresiones regulares con Beautiful Soup convierte esa cadena en el campo exacto que deseas. Esto es mucho más seguro que realizar scraping web con expresiones regulares sobre la respuesta sin procesar.

Dos patrones que vale la pena memorizar. Primero, pasa una expresión regular compilada directamente a find_all o find para filtrar etiquetas por valor de atributo:

price_tags = soup.find_all("span", class_=re.compile(r"^price"))

Segundo, busca elementos cuyo texto visible coincida con un patrón:

in_stock = soup.find_all(string=re.compile(r"\bIn stock\b", re.IGNORECASE))

Si quieres profundizar en el lado del analizador, nuestro tutorial de Beautiful Soup cubre selectores, navegación y casos extremos.

Patrones avanzados de expresiones regulares que los creadores de rastreadores deberían conocer

Una vez superados los conceptos básicos, hay una serie de re características hacen que el scraping web con expresiones regulares sea mucho más fácil de mantener.

  • Los grupos con nombre ((?P<name>...)) sustituyen a la frágil indexación posicional. m.group("price") es autodocumentado y sobrevive a la reordenación de patrones.
  • Las búsquedas hacia adelante y hacia atrás te permiten realizar coincidencias sin consumir recursos. \d+(?= USD) captura un número solo si USD le sigue; (?<=Price:\s)\$\d+ captura $199 solo después de la etiqueta literal.
  • Los indicadores mantienen los patrones cortos. re.IGNORECASE para In Stock vs in stock, re.DOTALL así . cruza los saltos de línea, re.VERBOSE por lo que puedes escribir patrones de varias líneas con comentarios.
  • re.compile merece la pena cuando se rastrean miles de páginas: compila una vez, reutiliza en todo el bucle y consigue una mejora de velocidad pequeña pero real.
  • re.finditer procesa las coincidencias de forma diferida, lo que es más respetuoso con la memoria que findall en el caso de documentos enormes.
PRICE = re.compile(r"\$(?P<amount>[\d,]+\.\d{2})(?=\s*USD)", re.IGNORECASE)
for m in PRICE.finditer(page_text):
    print(m.group("amount"))

Errores comunes y límites del scraping web con expresiones regulares

Lista sincera de cosas que te pueden hacer tropezar:

  • Los nombres de clases con hash (css-7u5e79 eag3qlw7) cambian con cada implementación. Enlaza a data-*, itempropo en etiquetas semánticas.
  • Las etiquetas anidadas rompen las (.*?) cuando el HTML interno contiene la misma etiqueta que estás intentando cerrar.
  • El HTML mal formado (etiquetas sin cerrar, comillas que no coinciden) hace que las expresiones regulares sean frágiles; un analizador real lo tolera.
  • El contenido renderizado por JavaScript simplemente no se encuentra en el cuerpo de la respuesta. Las expresiones regulares no pueden conjurar datos que el servidor nunca ha enviado.
  • Los problemas de codificación se cuelan a través de &amp;, &#x27;y las comillas tipográficas; normaliza el texto antes de realizar la coincidencia.

Cuando se den dos de estos casos a la vez, cambia a selectores o a una API de renderizado que devuelva HTML post-JS.

Expresiones regulares frente a XPath y selectores CSS: cuál elegir

Utiliza selectores para la estructura y expresiones regulares para el texto dentro de esa estructura. Los selectores CSS son concisos y rápidos para búsquedas basadas en clases y etiquetas; XPath es más expresivo cuando necesitas ejes, posiciones o predicados de texto. Las expresiones regulares entran en juego una vez que tienes el nodo correcto y necesitas analizar su cadena. Nuestra guía de XPath y la comparación entre XPath y los selectores CSS profundizan más si estás eligiendo entre ambos.

Conclusiones clave

  • Considera el web scraping con expresiones regulares como una herramienta de precisión para patrones de texto cortos y predecibles; mantén la navegación completa por el árbol HTML en Beautiful Soup o lxml.
  • Ancla siempre los patrones a atributos estables (data-*, itemprop, etiquetas semánticas), no a nombres de clases CSS con hash que cambian en cada implementación.
  • Combina find/find_all con re.compile para que los patrones se ejecuten en nodos aislados en lugar de en todo el cuerpo de la respuesta.
  • Apóyate en grupos con nombre, lookaheads re.DOTALL, re.IGNORECASEy re.compile una vez que tu rastreador supere una sola página.
  • Guarda la salida como CSV (o JSON para datos anidados), con encabezados explícitos y una estructura de carpetas clara para garantizar la reproducibilidad.

Preguntas frecuentes

¿Puedo extraer páginas renderizadas con JavaScript solo con expresiones regulares?

No. Las expresiones regulares coinciden con caracteres que ya están en la respuesta. Si los valores que necesitas son inyectados en el DOM por JavaScript del lado del cliente, el HTML sin procesar devuelto por requests simplemente no los contiene. Necesitas un navegador sin interfaz gráfica (Playwright, Puppeteer, Selenium) o una API de renderizado que devuelva el HTML posterior a JavaScript; entonces podrás aplicar expresiones regulares a esa salida.

¿Cómo puedo probar los patrones de expresiones regulares antes de ponerlos en producción?

Utiliza un probador interactivo como regex101 o pythex para validar los patrones con fragmentos de HTML representativos, seleccionando la opción de Python. A continuación, añade pequeñas pruebas unitarias que ejecuten cada patrón contra un archivo de fixtures guardado y comprueben los grupos capturados. Los fixtures te protegen cuando el sitio cambia, ya que una prueba fallida señala el patrón exacto que ha fallado.

¿Debería usar re.compile() al rastrear muchas páginas?

Sí. re.compile() Analiza el patrón una vez y reutiliza el objeto compilado en todas las llamadas, lo que evita el coste de análisis repetido dentro de bucles intensivos. La ganancia de rendimiento en una sola coincidencia es pequeña, pero en miles de páginas se acumula. La mayor ventaja es la legibilidad: los patrones compilados pueden residir en el nivel superior del módulo con nombres claros en lugar de literales de cadena en línea.

¿Cuál es la diferencia entre la coincidencia codiciosa y no codiciosa al rastrear HTML?

Los cuantificadores codiciosos (*, +) coinciden con todo el texto posible, lo que puede abarcar contenido de varios registros. Las variantes no codiciosas (*?, +?) coinciden con el mínimo posible, deteniéndose en el primer cierre válido. Para la extracción de HTML, (.*?)</h4> captura correctamente un título; (.*)</h4> se tragaría todo el documento hasta el último </h4>.

¿Cómo gestiono las coincidencias de varias líneas y los espacios en blanco extraños en el HTML extraído?

Pasa re.DOTALL so . coincide con los saltos de línea, y re.MULTILINE si se ancla con ^ o $ por línea. Para los espacios irregulares dentro de las etiquetas, utiliza \s* (cero o más espacios en blanco, incluyendo saltos de línea) entre los tokens esperados en lugar de espacios literales. Normaliza las entidades (&amp;, &nbsp;) y las comillas Unicode antes de la coincidencia para que no rompan silenciosamente patrones que, de otro modo, serían correctos.

Conclusión y próximos pasos

El web scraping con expresiones regulares es una herramienta eficaz, pero no universal. Úsala donde realmente vale la pena: analizando cadenas cortas y predecibles dentro del HTML que ya has aislado con un analizador sintáctico. Mantén tus patrones basados en atributos estables, da preferencia a los grupos con nombre y a los patrones compilados, y cambia a selectores o a una capa de renderizado en cuanto la página contenga mucho JavaScript o el marcado se vuelva anidado. La mayoría de los scrapers de producción acaban utilizando expresiones regulares, Beautiful Soup y clientes HTTP juntos; elige la capa que se adapte al campo que estás extrayendo y quédate ahí.

Si prefieres no tener que ocuparte de proxies, reintentos y CAPTCHAs mientras te centras en los patrones, la WebScrapingAPI de nuestro equipo devuelve HTML renderizado y JSON estructurado tras un único punto final, de modo que tu re código de Python y Beautiful Soup siga funcionando mientras la capa de solicitudes se gestiona por ti. A partir de aquí, el siguiente paso lógico es leer nuestra guía más amplia sobre web scraping en Python y el manual de análisis de datos para convertir los campos extraídos en registros limpios.

Acerca del autor
Mihai Maxim, Desarrollador Full Stack @ WebScrapingAPI
Mihai MaximDesarrollador Full Stack

Mihai Maxim es desarrollador full stack en WebScrapingAPI, donde colabora en todas las áreas del producto y ayuda a crear herramientas y funciones fiables para la plataforma.

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.