Curso de Python / Extraer datos de HTML con Beautiful Soup
Un analizador HTML permite seleccionar elementos y leer su texto o sus atributos. Comprueba los campos y recuentos esperados: un cambio de marcado puede romper la extracción y producir una lista vacía que parezca válida si no se controla.
Empezar con un documento estático controlado
Este ejercicio analiza una cadena incluida en el programa y no envía peticiones a sitios web. Analizar HTML y recopilar páginas externas son pasos distintos. Para una recopilación externa también debes revisar el acceso permitido, las condiciones del servicio, la frecuencia de peticiones y el tratamiento de datos personales.
Instala Beautiful Soup en el entorno virtual del proyecto:
python -m pip install beautifulsoup4
El paquete se distribuye como beautifulsoup4, pero se importa como bs4. Aquí utiliza html.parser, incluido en Python, como analizador subyacente. La documentación oficial de Beautiful Soup describe sus selectores CSS y métodos de extracción.
Ejecutar la extracción completa
Guarda el programa como parse_html.py y ejecútalo con python parse_html.py. El documento contiene dos gastos y el código exige encontrar exactamente esas dos filas.
from bs4 import BeautifulSoup
html = """<ul id="expenses">
<li data-amount="3500"><span class="name">coffee</span></li>
<li data-amount="8000"><span class="name">lunch</span></li>
</ul>"""
soup = BeautifulSoup(html, "html.parser")
rows = soup.select("#expenses > li")
if len(rows) != 2:
raise ValueError("unexpected row count")
total = 0
for row in rows:
name = row.select_one(".name")
amount_text = row.get("data-amount")
if name is None or not amount_text or not amount_text.isascii() or not amount_text.isdecimal():
raise ValueError("missing or invalid field")
amount = int(amount_text)
print(name.get_text(" ", strip=True), amount)
total += amount
print("total:", total)
coffee 3500
lunch 8000
total: 11500
Se extraen café y comida, con importes 3500 y 8000; sus etiquetas de datos son coffee y lunch. El total esperado es 11500. Las comprobaciones preceden a la conversión a entero para evitar interpretar campos ausentes o texto no numérico como importes.
Leer selectores, texto y coincidencias opcionales
#expenses > li selecciona hijos li directos del elemento con ese identificador. .name selecciona por clase. select_one devuelve None si no encuentra el elemento, por lo que debes comprobar el resultado antes de llamar a get_text.
El separador de get_text controla la unión de nodos de texto y strip=True elimina espacios en sus extremos. Estas opciones importan cuando el nombre contiene etiquetas anidadas. El atributo data-amount es otra fuente de datos, independiente del texto visible.
Beautiful Soup ve el HTML que recibe. Si JavaScript crea después una fila que no existe en la respuesta HTTP, ese elemento no aparecerá al analizar la descarga original. Compara el código de respuesta con la página renderizada antes de asumir que el selector es incorrecto. El cliente HTTP ayuda a distinguir la respuesta recibida del resultado posterior en el navegador.
Detectar cambios sin aceptar resultados engañosos
Cero coincidencias puede indicar una colección realmente vacía o un selector roto. En este documento controlado se exige un recuento de dos. Un recopilador real necesita una política de cantidad y campos compatible con su fuente, en vez de imponer siempre ese número.
- Cambia la clase
namey comprueba el fallo de campo obligatorio. - Cambia un importe a
-1oabcy observa el rechazo. - Añade una etiqueta dentro de un nombre, inspecciona el texto y restaura el marcado.
La lección de expresiones regulares distingue coincidencias de texto y análisis de un formato estructurado. Elige el analizador por la estructura que necesitas comprender, no por la brevedad aparente de un patrón.




