---
title: "¿Qué es el parsing de datos? Tipos, errores y ejemplos"
description: "El parsing de datos convierte HTML, JSON, CSV o logs en registros estructurados que tu código puede usar. Cómo funciona un parser, sus tipos y errores comunes."
url: https://proxynet.io/es/blog/what-is-data-parsing
date: 2026-09-28
author: "Acar Diveroli"
category: "Web scraping, Proxy 101"
lang: es
---

# ¿Qué es el parsing de datos? Tipos, errores y ejemplos

Un scraper descarga la página de un producto y la guarda en disco. El archivo tiene 180 KB de HTML y, en algún lugar dentro de él, están las cuatro cosas que de verdad querías: el nombre del producto, el precio, la disponibilidad y el SKU. Hasta que un programa encuentra esos valores, los comprueba y los escribe en campos con nombre, la descarga no es más que texto. Ese paso, del texto en bruto a los campos, es el análisis sintáctico de datos (parsing).

Este artículo explica qué significa el parsing, cómo trabaja un parser (dos etapas centrales y los pasos que las rodean) y qué tipo de parser conviene para HTML, JSON, CSV, logs y formatos propios. Separa el parsing del scraping y de la extracción, muestra un ejemplo breve y probado en Python con BeautifulSoup y el módulo `json`, repasa los errores que rompen los parsers en proyectos reales (HTML mal formado, JSON inválido, deriva de esquema) y termina con una guía para decidir entre construir o comprar.

> **Nota: Respuesta breve**
>
> El parsing de datos es el proceso de leer una entrada en bruto, como una página HTML, una respuesta JSON, un archivo CSV o una línea de log, y convertirla en una estructura con la que un programa puede trabajar: objetos, filas o pares clave-valor. Un parser primero divide la entrada en tokens y después los ordena según las reglas del formato. En web scraping, el scraper obtiene la página y el parser la convierte en registros limpios, que luego se validan y se almacenan.

## ¿Qué es el parsing de datos?

Hacer parsing significa analizar una entrada según un conjunto de reglas y producir una estructura que represente lo que esa entrada dice. La entrada suele ser una cadena de texto o un flujo de bytes. La salida es algo con nombres y tipos: un árbol de elementos HTML, un diccionario de Python, una lista de filas, un registro con un campo `price` que contiene un número en lugar del texto `"$1,249.00"`.

Tu navegador parsea HTML para mostrar una página, tu cliente de API parsea JSON en objetos, tu hoja de cálculo parsea CSV en celdas. Solo notas el parsing cuando la entrada no coincide con lo que el parser esperaba, y el programa se detiene con un error o, peor aún, sigue adelante con valores incorrectos.

En el trabajo con datos, la palabra se usa en dos niveles:

- **Parsing del formato.** Convertir bytes en la estructura propia del formato: HTML en un árbol DOM, JSON en objetos, CSV en filas. De esto se encargan las bibliotecas.
- **Parsing de datos en sentido estricto.** Tomar esa estructura y sacar los valores que necesitas, con el tipo correcto: el precio como decimal, la fecha como fecha, la disponibilidad como verdadero o falso. Esta parte normalmente la escribes tú.

## ¿Cómo funciona un parser?

Casi todos los parsers, desde una biblioteca JSON hasta el motor HTML de un navegador, siguen las mismas dos etapas centrales, el análisis léxico y el análisis sintáctico, con un paso de lectura antes y la selección de valores y la validación después.

1. **Leer la entrada como texto.** Los bytes se decodifican en caracteres con una codificación, normalmente UTF-8. Si aquí se elige mal, aparecen caracteres ilegibles antes incluso de empezar el parsing; [errores de codificación Unicode en Python](/es/blog/python-unicode-encoding-errors) trata ese fallo.
1. **Tokenizar (análisis léxico).** El parser corta el flujo de caracteres en tokens, las piezas mínimas con significado: una etiqueta de apertura, un atributo, una cadena, un número, una coma, una llave de cierre.
1. **Construir la estructura (análisis sintáctico).** Los tokens se ordenan según la gramática del formato. En HTML el resultado es un árbol de elementos anidados; en JSON, objetos y arrays anidados; en CSV, filas de campos.
1. **Seleccionar los valores.** Tu código recorre la estructura y elige los campos que necesita, por ejemplo con un selector CSS o XPath sobre un árbol HTML. [Selector CSS vs XPath](/es/blog/css-selector-vs-xpath) compara las dos formas de apuntar a un elemento.
1. **Convertir y validar.** El texto pasa a ser datos tipados: `"$34.50"` se convierte en `34.50`, `"In stock"` en `true`. Los registros a los que les falta un campo obligatorio se marcan en lugar de guardarse sin avisar.

El estándar HTML describe el parser de un navegador exactamente con estas etapas. El [capítulo de parsing de WHATWG](https://html.spec.whatwg.org/multipage/parsing.html) lo divide en tokenización y construcción del árbol, y además define cómo debe recuperarse un parser de los errores; por eso los navegadores muestran páginas rotas en lugar de rechazarlas.

## Parsing, scraping y extracción: diferencias

Las tres palabras se usan a menudo como sinónimos, pero nombran pasos distintos de una misma cadena.

| Término | Qué hace | Entrada | Salida |
|---|---|---|---|
| Crawling | Encuentra páginas siguiendo enlaces | Una URL inicial | Una lista de URL |
| Scraping | Descarga el contenido de esas páginas | URL | HTML, JSON o archivos en bruto |
| Parsing | Convierte el contenido en bruto en estructura | Texto en bruto | Árboles, objetos, filas |
| Extracción | Elige los valores necesarios dentro de la estructura | Un árbol u objeto | Campos con nombre |
| Validación y limpieza | Comprueba tipos, elimina duplicados, corrige formatos | Campos | Registros fiables |
| Almacenamiento | Escribe los registros en algún sitio | Registros | CSV, JSON Lines, una base de datos |

En el habla cotidiana, "parsing" abarca a la vez el parsing, la extracción y parte de la validación, y así se usa en el resto de este artículo. El crawling y el scraping son la parte de obtención; [web scraping vs web crawling](/es/blog/web-scraping-vs-web-crawling) explica esa división. Dónde acaban los registros se trata en [cómo guardar datos de scraping en CSV, JSON y SQLite](/es/blog/save-scraped-data-csv-json-sqlite), y la cadena completa como un proceso repetible es el tema de [¿Qué es ETL?](/es/blog/what-is-etl).

## Tipos de parsers

Cada entrada pide un parser distinto. Usar el tipo equivocado, por ejemplo una expresión regular sobre HTML anidado, es el origen de muchos scrapers frágiles.

| Tipo de parser | Ideal para | Ejemplos | Punto débil |
|---|---|---|---|
| Parser HTML / DOM | Páginas web, incluso con marcado roto | BeautifulSoup con `html.parser`, `lxml` o `html5lib`; Cheerio en Node.js | Necesita selectores que cambian cuando cambia el diseño de la página |
| Parser JSON | Respuestas de API, datos incrustados en la página | `json` de Python, `JSON.parse` en JavaScript | Estricto: una coma de más invalida todo el documento |
| Parser CSV / delimitado | Exportaciones, hojas de cálculo, informes | `csv` de Python, `read_csv` de pandas | Comillas, delimitadores y codificaciones varían según quién genera el archivo |
| Parser XML | Feeds, sitemaps, API empresariales antiguas | `lxml`, `xml.etree.ElementTree` | Los espacios de nombres hacen verbosos los selectores |
| Expresiones regulares | Patrones pequeños y planos dentro de un campo conocido: precios, fechas, ID | `re` de Python | No siguen el anidamiento; se rompen con cambios de diseño |
| Parser basado en gramática | Formatos propios, lenguajes de consulta, archivos de configuración | Generadores de parsers como ANTLR, Lark | Escribir la gramática lleva tiempo |
| Parser basado en modelos | Texto desordenado sin estructura fija | Modelos de lenguaje que devuelven JSON | La salida debe validarse; los resultados pueden variar entre ejecuciones |

Dos filas merecen una nota. **Los parsers HTML no son iguales:** BeautifulSoup funciona sobre un parser que tú eliges, y su [documentación](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) muestra cómo el fragmento roto `<a></p>` produce tres árboles distintos en `html.parser`, `lxml` y `html5lib`. Indica el parser de forma explícita, o tu salida puede cambiar en una máquina que tenga otro instalado. **El parsing basado en modelos** es la forma en que los scrapers con IA leen páginas cuyo diseño cambia constantemente; cambia reglas exactas por flexibilidad, así que la validación importa todavía más, como explica [cómo funcionan los web scrapers con IA](/es/blog/ai-web-scraper-how-it-works-2026).

## Un ejemplo breve de parsing en Python

El ejemplo parsea una pequeña página de productos con un parser HTML, selectores CSS, una expresión regular para el campo del precio, una comprobación de campos obligatorios y un parsing JSON aparte para los datos incrustados en la página. Guarda esto como `page.html`; la segunda tarjeta tiene un `<span>` sin cerrar y la tercera no tiene precio:

```html
<!doctype html>
<html lang="en">
<head>
  <title>Desk lamps</title>
  <script type="application/ld+json">
  {"@context": "https://schema.org", "@type": "ItemList",
   "itemListElement": [
     {"@type": "ListItem", "position": 1, "url": "/p/arc-lamp"},
     {"@type": "ListItem", "position": 2, "url": "/p/clip-lamp"}
   ]}
  </script>
</head>
<body>
  <div class="product" data-sku="L-100">
    <h2 class="name">Arc Desk Lamp</h2>
    <span class="price">$1,249.00</span>
    <span class="stock">In stock</span>
  </div>
  <div class="product" data-sku="L-200">
    <h2 class="name">  Clip Lamp </h2>
    <span class="price">$34.50</span>
    <span class="stock">Out of stock
  </div>
  <div class="product" data-sku="L-300">
    <h2 class="name">Floor Lamp</h2>
    <span class="stock">In stock</span>
  </div>
</body>
</html>
```

Instala las dos bibliotecas con `pip install beautifulsoup4 lxml` y guarda esto como `parse_products.py` junto a la página:

```python
import json
import re
from decimal import Decimal
from pathlib import Path

from bs4 import BeautifulSoup

PRICE_RE = re.compile(r"[\d.,]+")

def parse_price(text):
    """'$1,249.00' -> Decimal('1249.00'); None si no hay ningún número."""
    match = PRICE_RE.search(text or "")
    if not match:
        return None
    return Decimal(match.group().replace(",", ""))

def parse_products(html):
    soup = BeautifulSoup(html, "lxml")
    rows, problems = [], []

    for card in soup.select("div.product"):
        name = card.select_one(".name")
        price = card.select_one(".price")
        stock = card.select_one(".stock")
        row = {
            "sku": card.get("data-sku"),
            "name": name.get_text(strip=True) if name else None,
            "price": parse_price(price.get_text()) if price else None,
            "in_stock": stock is not None and stock.get_text(strip=True) == "In stock",
        }
        missing = [key for key in ("sku", "name", "price") if row[key] is None]
        if missing:
            problems.append({"sku": row["sku"], "missing": missing})
            continue
        rows.append(row)

    # Datos estructurados incrustados en la página: se parsean como JSON, no como HTML.
    urls = []
    for tag in soup.select('script[type="application/ld+json"]'):
        try:
            data = json.loads(tag.string or "")
        except json.JSONDecodeError as err:
            problems.append({"json_ld": f"line {err.lineno}, col {err.colno}: {err.msg}"})
            continue
        urls += [item.get("url") for item in data.get("itemListElement", [])]

    return rows, urls, problems

if __name__ == "__main__":
    html = Path("page.html").read_text(encoding="utf-8")
    rows, urls, problems = parse_products(html)
    print(json.dumps(rows, indent=2, default=str))
    print("urls:", urls)
    print("problems:", problems)
```

Al ejecutar `python parse_products.py` con BeautifulSoup 4.15.0, lxml 6.1.3 y Python 3.13 se obtiene:

```text
[
  {
    "sku": "L-100",
    "name": "Arc Desk Lamp",
    "price": "1249.00",
    "in_stock": true
  },
  {
    "sku": "L-200",
    "name": "Clip Lamp",
    "price": "34.50",
    "in_stock": false
  }
]
urls: ['/p/arc-lamp', '/p/clip-lamp']
problems: [{'sku': 'L-300', 'missing': ['price']}]
```

El `<span>` sin cerrar no rompió nada porque `lxml` reparó el árbol, el nombre con espacios salió limpio y la lámpara sin precio fue a `problems` en lugar de guardarse vacía. Cuando, como prueba, añadimos una coma final al bloque JSON-LD, el script siguió funcionando e informó `line 5, col 64: Illegal trailing comma before end of object`, que señala directamente el fallo. [JSONDecodeError: Expecting Value](/es/blog/jsondecodeerror-expecting-value) recoge los demás mensajes que lanza este parser y qué causa cada uno.

El mismo parser escrito para Node.js usa Cheerio en lugar de BeautifulSoup; consulta [web scraping con Cheerio](/es/blog/cheerio-web-scraping). Para un scraper completo con peticiones, paginación y guardado, empieza por el [tutorial de BeautifulSoup](/es/blog/beautifulsoup-tutorial).

## Errores de parsing comunes y sus causas

- **HTML mal formado.** Etiquetas sin cerrar, etiquetas de cierre sueltas y etiquetas fuera de lugar son normales en la web. Los navegadores y los parsers HTML las reparan, pero cada parser a su manera, así que un selector que funciona con `html5lib` puede fallar con `html.parser`. Fija la elección del parser y prueba con páginas guardadas.
- **JSON inválido.** JSON es estricto. [RFC 8259](https://www.rfc-editor.org/rfc/rfc8259) define la gramática, y las comas finales, las comillas simples y los comentarios no forman parte de ella. Una causa frecuente ni siquiera es JSON: el servidor devolvió una página de error HTML o un cuerpo vacío, y el parser JSON falla en el primer carácter.
- **Claves duplicadas.** RFC 8259 dice que, cuando los nombres de un objeto se repiten, el comportamiento del receptor es impredecible. El [módulo json](https://docs.python.org/3/library/json.html) de Python se queda con el último valor sin lanzar ningún error, así que `{"price": 10, "price": 12}` se convierte en `12` sin avisar.
- **Comillas y delimitadores en CSV.** Una coma dentro del nombre de un producto divide un campo en dos si no va entre comillas. [RFC 4180](https://www.rfc-editor.org/rfc/rfc4180) describe la convención habitual de comillas, pero es solo informativa y muchas exportaciones usan punto y coma o tabuladores. Usa una biblioteca CSV, nunca `line.split(",")`.
- **Números y fechas según el idioma.** `1.249,00` supera los mil en Alemania y es algo más de uno para un parser ingenuo; `03/04/2026` es marzo o abril según el país. Parsea con un formato explícito por fuente.
- **Deriva de esquema (schema drift).** El sitio cambia el nombre de una clase o mueve el precio a otro elemento, y el parser sigue funcionando pero devuelve `None` o un valor incorrecto. Nada falla, y por eso este es el error más caro. Las comprobaciones de campos obligatorios, como la lista `problems` de arriba, convierten la deriva silenciosa en un recuento visible.
- **Contenido que no está en el HTML.** Algunas páginas construyen su contenido con JavaScript después de cargar, así que los datos nunca estuvieron en el archivo descargado. [Páginas estáticas vs dinámicas](/es/blog/static-vs-dynamic-pages) muestra cómo distinguirlas.

## ¿Construir o comprar un parser?

Para los formatos estándar nunca escribes el parser de bajo nivel; las bibliotecas están maduras. La decisión afecta a la capa de extracción que va encima: selectores, conversiones y comprobaciones por sitio.

**Constrúyelo tú cuando** tengas un número limitado de fuentes que cambian poco. Tu propio código es transparente, no cuesta nada por página y es fácil de probar con muestras guardadas.

**Usa una herramienta o un servicio ya hecho cuando** sigas cientos de sitios cuyo diseño cambia a menudo, o cuando la entrada no tenga ninguna estructura fija, como correos electrónicos y PDF. Pagas por volumen o por usuario y aceptas menos control sobre la salida.

**Lo habitual es un enfoque híbrido:** API oficiales o JSON incrustado donde existan, parsers escritos a mano para las fuentes clave, un respaldo basado en modelos para la larga cola y el mismo paso de validación antes del almacenamiento para los tres.

## Dónde se usa el parsing

- **Recopilación de datos a escala.** Todo pipeline de scraping hace parsing entre la descarga y la base de datos; consulta [data scraping](/es/data-scraping).
- **Crawlers y auditorías de sitios.** Un crawler parsea cada página para obtener enlaces y metadatos; consulta [web crawler](/es/web-crawler).
- **Seguimiento de precios.** Los precios convertidos en números se pueden comparar a lo largo del tiempo, como en el [seguimiento de precios de la competencia](/es/blog/competitor-price-tracking).
- **Monitorización de cambios.** Comparar campos parseados en lugar del HTML en bruto evita falsas alarmas por anuncios y marcas de tiempo; consulta [monitorización de cambios en sitios web](/es/blog/website-change-monitoring).
- **Analítica.** Los registros tipados son el punto de partida para buscar patrones; consulta [¿Qué es la minería de datos?](/es/blog/what-is-data-mining).
- **Logs y seguridad.** Las líneas de log se parsean en marca de tiempo, dirección IP, estado y ruta antes de que nadie pueda contar errores.

## Errores habituales

- **Parsear el sitio en vivo mientras desarrollas.** Guarda en disco unas cuantas páginas reales y escribe el parser contra ellas: menos peticiones al sitio y pruebas repetibles.
- **Usar regex sobre documentos HTML completos.** Parsea primero el árbol y usa regex solo dentro del texto de un único campo.
- **Guardar los precios como texto o como float.** Convierte pronto a `Decimal` o a céntimos enteros y conserva la cadena original para depurar.
- **Tragarte todas las excepciones.** Un `try/except: pass` desnudo oculta la deriva de esquema. Recoge los fallos con el ID del registro y revisa el recuento después de cada ejecución.
- **Ignorar el JSON incrustado.** Muchas páginas de producto incluyen JSON-LD con los mismos valores en una forma más limpia que el HTML visible.
- **Culpar al parser de las peticiones bloqueadas.** Cuando el "HTML" es una página de bloqueo o un error 429, ningún selector coincidirá. Comprueba el código de estado antes de parsear y reduce el ritmo si el sitio te lo pide.

## Guía de decisión

| Tu entrada | Enfoque recomendado |
|---|---|
| Una API que devuelve JSON | Usa la API; parsea con la biblioteca JSON estándar y valida los campos obligatorios |
| Páginas HTML estáticas de pocos sitios | BeautifulSoup con `lxml`, o Cheerio en Node.js, más selectores CSS |
| Páginas que generan el contenido con JavaScript | Busca primero JSON incrustado o la API del sitio; usa un navegador headless solo si hace falta |
| Exportaciones CSV u hojas de cálculo | Una biblioteca CSV o pandas, con el delimitador y la codificación indicados de forma explícita |
| Logs de servidor con formato fijo | Una regex por línea o un parser de logs, y después convertir los campos a sus tipos |
| Un formato de texto propio que controlas | Un parser basado en gramática (ANTLR, Lark) |
| Correos, PDF, texto libre sin estructura | Un extractor basado en modelos con validación estricta de la salida |
| Cientos de sitios con diseños cambiantes | Un servicio comercial de parsing o una configuración híbrida |

## Preguntas frecuentes

### ¿Qué es el parsing de datos en palabras sencillas?

Es leer texto en bruto y convertirlo en piezas etiquetadas que un programa puede usar. Entra una página web y sale un registro con un nombre, un precio y la disponibilidad.

### ¿Qué diferencia hay entre parsing y scraping?

El scraping descarga contenido de un sitio web; el parsing convierte ese contenido en datos estructurados. Un scraper sin parser te deja con archivos HTML en bruto.

### ¿Qué biblioteca de Python se usa para parsear HTML?

BeautifulSoup es la más usada y funciona sobre `html.parser`, `lxml` o `html5lib`. `lxml` también puede usarse directamente y admite XPath. Para JSON basta con el módulo integrado `json`.

### ¿Puedo parsear HTML con expresiones regulares?

Solo para fragmentos de texto muy pequeños y planos. El HTML está anidado y a menudo roto, y una expresión regular no puede seguir el anidamiento. Parsea la página con un parser HTML y, si lo necesitas, usa regex dentro de un único campo.

### ¿Por qué mi parser devuelve de repente valores vacíos?

Normalmente porque el sitio cambió su marcado y tus selectores ya no coinciden. Otras causas: una página de error en lugar del contenido, o contenido que JavaScript carga más tarde.

### ¿Necesito un proxy para parsear datos?

El parsing en sí se ejecuta en tu propia máquina y no necesita proxy. Los proxies importan en la parte de obtención, cuando un scraper recopila páginas públicas en volumen o necesita ver una página como la ven los visitantes de otro país. Las direcciones de [Proxies residenciales](https://proxynet.io/es/residential-proxy) te permiten elegir país y ciudad, y [Proxies rotativos](https://proxynet.io/es/rotating-proxy) reparte las peticiones entre varias direcciones; en ambos casos, respeta las condiciones y los límites de velocidad de cada sitio.

## En resumen

El parsing de datos convierte una entrada en bruto en registros estructurados y tipados: un tokenizador corta el texto en piezas, un parser las ordena según las reglas del formato y tu código elige, convierte y comprueba los valores que necesita. Elige el parser según la entrada y deja la regex dentro de campos individuales. La mayor parte del trabajo en un proyecto real se va en los fallos, sobre todo en la deriva de esquema que ningún mensaje de error anuncia, así que valida cada registro y cuenta los fallos después de cada ejecución. Cuando la parte de obtención necesite direcciones en países concretos, consulta nuestros [servicios de proxy](/es/proxy).
