Python
Tutorial Python: Web Scraping para ciencia de datos
Aprende Beautiful Soup para extraer y analizar datos web. Domina el web scraping y transforma datos en datasets listos para ciencia de datos.
Aprende Python GRATIS y certifícateIntroducción a la Integración de Beautiful Soup y Pandas
La integración de Beautiful Soup y Pandas es esencial para transformar datos extraídos de páginas web en estructuras organizadas y analizables. Mientras que Beautiful Soup es una biblioteca poderosa para parsear y navegar por documentos HTML, Pandas ofrece herramientas robustas para manipular y analizar datos en formato tabular.
Al extraer información de una página web usando Beautiful Soup, los datos suelen estar en formato no estructurado, lo que dificulta su análisis directo. Aquí es donde entra en juego Pandas, permitiéndonos convertir esos datos en DataFrames, estructuras que facilitan el manejo y análisis de la información.
Por ejemplo, consideremos que queremos extraer una tabla:
from bs4 import BeautifulSoup
import pandas as pd
# Tabla HTML de ejemplo
html_doc = """
<table>
<thead>
<tr>
<th scope="col">Breed</th>
<th scope="col">Average Lifespan</th>
<th scope="col">Characteristics</th>
</tr>
</thead>
<tbody>
<tr>
<td>Siberian</td>
<td>12-15 years</td>
<td>Playful and Affectionate</td>
</tr>
<tr>
<td>Bengal</td>
<td>10-16 years</td>
<td>Energetic and Vocal</td>
</tr>
<tr>
<td>Ragdoll</td>
<td>12-17 years</td>
<td>Calm and Friendly</td>
</tr>
</tbody>
</table>
"""
# Analizar el contenido HTML
soup = BeautifulSoup(html_doc, 'html.parser')
# Encontrar la tabla específica
tabla = soup.find('table')
# Extraer los encabezados
encabezados = [th.text.strip() for th in tabla.find_all('th')]
# Extraer las filas de la tabla
filas = []
for fila in tabla.find_all('tr')[1:]:
celdas = [celda.text.strip() for celda in fila.find_all('td')]
filas.append(celdas)
# Crear un DataFrame de Pandas
df = pd.DataFrame(filas, columns=encabezados)
# Mostrar el DataFrame
print(df)
En este ejemplo, usamos Beautiful Soup para extraer los datos de la tabla HTML y luego Pandas para organizar esos datos en un DataFrame. Este enfoque nos permite aprovechar las funciones de análisis y manipulación de datos que ofrece Pandas.
Es crucial manejar correctamente los datos durante este proceso. A menudo, los datos extraídos pueden contener caracteres especiales o espacios en blanco innecesarios. Usar métodos como str.strip()
ayuda a limpiar los datos antes de convertirlos en un DataFrame.
Además, al trabajar con múltiples tablas o fuentes de datos, Pandas facilita la concatenación y fusión de DataFrames, permitiéndonos combinar datos de diferentes orígenes de manera efectiva.
# Supongamos que tenemos otro DataFrame
df_otro = pd.DataFrame({'Columna1': [1, 2], 'Columna2': [3, 4]})
# Podemos concatenar los DataFrames
df_concatenado = pd.concat([df, df_otro], ignore_index=True)
La sinergia entre Beautiful Soup y Pandas es especialmente útil en proyectos de ciencia de datos, donde la obtención y el análisis de información precisa es fundamental. Al integrar estas herramientas, optimizamos el flujo de trabajo desde la extracción de datos hasta su análisis y visualización.
Extracción de datos y construcción de DataFrames
Al realizar web scraping con Beautiful Soup, es fundamental extraer los datos correctamente para luego estructurarlos en DataFrames de Pandas. Esto permite analizar y manipular la información de forma más efectiva.
Para comenzar, supongamos que deseamos extraer una lista de productos y sus precios de una página web. Primero, debemos enviar una solicitud a la página y crear un objeto BeautifulSoup:
import requests
from bs4 import BeautifulSoup
# Enviar solicitud HTTP a la página web
url = 'https://www.ejemplo.com/productos'
respuesta = requests.get(url)
soup = BeautifulSoup(respuesta.content, 'html.parser')
Una vez obtenido el objeto soup
, procedemos a localizar los elementos que contienen la información relevante. Si los productos están dentro de etiquetas <div>
con la clase producto
, podemos utilizar:
# Encontrar todos los contenedores de productos
productos = soup.find_all('div', class_='producto')
Ahora, iteramos sobre la lista productos
para extraer el nombre y el precio de cada uno. Podemos almacenar esta información en listas:
# Listas para almacenar los datos
nombres = []
precios = []
for producto in productos:
# Extraer el nombre del producto
nombre = producto.find('h2', class_='nombre').text.strip()
nombres.append(nombre)
# Extraer el precio del producto
precio = producto.find('span', class_='precio').text.strip()
precios.append(precio)
Es importante limpiar los datos extraídos usando strip()
para eliminar espacios en blanco innecesarios. Además, podemos convertir los precios a valores numéricos:
# Convertir precios a números decimales
precios = [float(precio.replace('€', '').replace(',', '.')) for precio in precios]
Con los datos preparados, procedemos a construir un DataFrame de Pandas:
import pandas as pd
# Crear un diccionario con los datos
datos = {'Nombre': nombres, 'Precio': precios}
# Crear el DataFrame
df = pd.DataFrame(datos)
# Mostrar el DataFrame
print(df)
De esta manera, hemos transformado los datos extraídos en una estructura tabular lista para su análisis.
Es frecuente que necesitemos extraer datos de múltiples páginas (paginación). Para ello, podemos implementar un bucle que recorra las páginas y acumule los datos:
nombres = []
precios = []
# Suponiendo que hay 5 páginas de productos
for pagina in range(1, 6):
# Actualizar la URL con el número de página
url_pagina = f'https://www.ejemplo.com/productos?page={pagina}'
respuesta = requests.get(url_pagina)
soup = BeautifulSoup(respuesta.content, 'html.parser')
productos = soup.find_all('div', class_='producto')
for producto in productos:
nombre = producto.find('h2', class_='nombre').text.strip()
nombres.append(nombre)
precio = producto.find('span', class_='precio').text.strip()
precios.append(float(precio.replace('€', '').replace(',', '.')))
Después de extraer todos los datos, construimos el DataFrame como antes.
Es esencial manejar errores y casos excepcionales durante la extracción. Por ejemplo, si algún producto no tiene precio:
try:
precio = producto.find('span', class_='precio').text.strip()
precios.append(float(precio.replace('€', '').replace(',', '.')))
except AttributeError:
# Si no se encuentra el precio, asignar un valor nulo
precios.append(None)
Al combinar Beautiful Soup para la extracción y Pandas para la estructuración, podemos enfrentar tareas más complejas de web scraping y análisis de datos.
Limpieza y preprocesamiento de datos scrapeados
Al extraer información con Beautiful Soup, es común enfrentarse a datos que requieren limpieza y preprocesamiento antes de ser utilizados efectivamente. Los datos scrapeados pueden contener espacios en blanco innecesarios, caracteres especiales o formatos inconsistentes que deben ser tratados.
Uno de los primeros pasos es eliminar espacios en blanco y saltos de línea que pueden interferir con el análisis. Utilizar el método strip()
es esencial para remover estos caracteres del inicio y fin de las cadenas.
texto_crudo = elemento.get_text()
texto_limpio = texto_crudo.strip()
Para eliminar caracteres especiales o no deseados, las expresiones regulares proporcionan una herramienta potente. El módulo re
de Python permite redefinir el texto según patrones específicos.
import re
texto_limpio = re.sub(r'[^a-zA-Z0-9\s]', '', texto_limpio)
La normalización del texto es crucial, especialmente cuando se trabaja con múltiples fuentes que pueden tener diferentes codificaciones. Convertir el texto a minúsculas y eliminar acentos garantiza una comparación uniforme.
texto_normalizado = texto_limpio.lower()
import unicodedata
def eliminar_acentos(cadena):
return ''.join(caracter for caracter in unicodedata.normalize('NFD', cadena)
if unicodedata.category(caracter) != 'Mn')
texto_sin_acentos = eliminar_acentos(texto_normalizado)
Al manejar números, es importante convertir cadenas numéricas que puedan incluir símbolos o comas decimales al formato adecuado. Esto facilita cálculos y análisis posteriores.
precio_crudo = elemento_precio.get_text().strip()
precio_formateado = precio_crudo.replace('€', '').replace('.', '').replace(',', '.')
precio_numerico = float(precio_formateado)
En el caso de fechas y horas, utilizar la librería datetime
ayuda a parsear y estandarizar diferentes formatos.
from datetime import datetime
fecha_cruda = elemento_fecha.get_text().strip()
fecha_formato = datetime.strptime(fecha_cruda, '%d/%m/%Y')
Cuando se extraen listas o tablas, es eficaz emplear comprensiones de listas para limpiar cada elemento de manera concisa.
filas = tabla.find_all('tr')
datos = [[celda.get_text().strip() for celda in fila.find_all('td')] for fila in filas]
Es crucial manejar los valores nulos o faltantes para evitar errores en el análisis. Se pueden asignar valores predeterminados o utilizar condiciones para verificar la existencia de datos.
titulo = elemento.find('h1').get_text().strip() if elemento.find('h1') else 'Sin título'
Para asegurar la consistencia de codificación, especialmente al trabajar con diferentes idiomas o caracteres especiales, es recomendable especificar la codificación apropiada al leer el contenido.
contenido = requests.get(url).content
soup = BeautifulSoup(contenido, 'html.parser', from_encoding='utf-8')
Al preparar los datos para un DataFrame de Pandas, es útil convertir listas de elementos limpios en un formato estructurado.
import pandas as pd
nombres = [item.get_text().strip() for item in soup.find_all('span', class_='nombre')]
precios = [float(item.get_text().strip().replace('€', '').replace(',', '.')) for item in soup.find_all('span', class_='precio')]
df = pd.DataFrame({'Nombre': nombres, 'Precio': precios})
La aplicación cuidadosa de estas técnicas de limpieza y preprocesamiento asegura que los datos extraídos sean de alta calidad y estén listos para su análisis en proyectos de ciencia de datos.
Enriquecimiento de datasets con datos de múltiples fuentes web
En el ámbito de la ciencia de datos, es común enfrentarse al desafío de enriquecer datasets existentes con información adicional proveniente de diversas fuentes web. Beautiful Soup, en combinación con Pandas, permite extraer y fusionar datos de múltiples sitios web para obtener un conjunto de datos más completo y valioso.
Al trabajar con datos de diferentes fuentes, es fundamental considerar la consistencia y compatibilidad de la información. Cada sitio web puede presentar sus datos en formatos y estructuras distintas, por lo que es necesario implementar estrategias para alinear y unificar estos datos antes de integrarlos en el dataset principal.
Por ejemplo, supongamos que disponemos de un dataset con una lista de productos y queremos enriquecerlo con reseñas y calificaciones obtenidas de diferentes tiendas en línea. Primero, utilizamos Beautiful Soup para extraer la información relevante de cada sitio web:
import requests
from bs4 import BeautifulSoup
def obtener_reseñas(url):
respuesta = requests.get(url)
soup = BeautifulSoup(respuesta.content, 'html.parser')
reseñas = []
elementos_reseña = soup.find_all('div', class_='reseña')
for elemento in elementos_reseña:
usuario = elemento.find('span', class_='usuario').get_text(strip=True)
calificación = float(elemento.find('span', class_='calificación').get_text(strip=True))
comentario = elemento.find('p', class_='comentario').get_text(strip=True)
reseñas.append({'usuario': usuario, 'calificación': calificación, 'comentario': comentario})
return reseñas
En este fragmento de código, extraemos las reseñas de un producto específico. Usamos el método get_text(strip=True)
para obtener el texto sin espacios innecesarios.
Una vez extraídos los datos de diferentes fuentes, necesitamos integrarlos en nuestro dataset. Esto implica mapear la información de cada fuente al esquema común del dataset. Pandas ofrece funciones como merge
y concat
para combinar DataFrames de manera eficiente.
import pandas as pd
# Dataset principal con información de productos
df_productos = pd.read_csv('productos.csv')
# DataFrame con reseñas de la fuente A
reseñas_a = obtener_reseñas('https://tiendaA.com/producto123/reseñas')
df_reseñas_a = pd.DataFrame(reseñas_a)
df_reseñas_a['fuente'] = 'Tienda A'
# DataFrame con reseñas de la fuente B
reseñas_b = obtener_reseñas('https://tiendaB.com/producto123/reseñas')
df_reseñas_b = pd.DataFrame(reseñas_b)
df_reseñas_b['fuente'] = 'Tienda B'
# Unir las reseñas de ambas fuentes
df_reseñas = pd.concat([df_reseñas_a, df_reseñas_b], ignore_index=True)
# Agregar las reseñas al dataset principal
df_enriquecido = df_productos.merge(df_reseñas, on='producto_id', how='left')
Aquí, hemos utilizado pd.concat
para combinar las reseñas de diferentes fuentes en un solo DataFrame. La columna adicional 'fuente'
nos permite identificar el origen de cada reseña.
Es importante manejar las diferencias en los formatos de datos entre las fuentes. Por ejemplo, si las calificaciones están en escalas distintas (por ejemplo, de 1 a 5 en una fuente y de 1 a 10 en otra), debemos normalizar los valores antes de fusionarlos.
# Normalizar calificaciones de la fuente B (escala de 1 a 10 a escala de 1 a 5)
df_reseñas_b['calificación'] = df_reseñas_b['calificación'] / 2
Además, es recomendable implementar mecanismos para controlar la calidad de los datos. Esto incluye detectar y eliminar duplicados, manejar valores nulos y validar la coherencia de la información.
Para enriquecer aún más nuestro dataset, podemos extraer datos de APIs públicas o fuentes abiertas. Por ejemplo, obtener información meteorológica para analizar cómo las condiciones climáticas afectan las ventas de ciertos productos.
# Obtener datos meteorológicos de una API
def obtener_clima(fecha, ubicación):
url_api = f'https://api.clima.com/datos?fecha={fecha}&ubicación={ubicación}'
respuesta = requests.get(url_api)
datos_clima = respuesta.json()
return {'fecha': fecha, 'ubicación': ubicación, 'temperatura': datos_clima['temperatura']}
# Aplicar la función para enriquecer el dataset
df_productos['fecha'] = pd.to_datetime(df_productos['fecha'])
df_productos['ubicación'] = 'Madrid' # Suponiendo que la ubicación es Madrid para todos los registros
datos_clima = df_productos[['fecha', 'ubicación']].drop_duplicates().apply(
lambda fila: obtener_clima(fila['fecha'], fila['ubicación']), axis=1)
df_clima = pd.DataFrame(datos_clima.tolist())
# Fusionar los datos meteorológicos con el dataset principal
df_enriquecido = df_productos.merge(df_clima, on=['fecha', 'ubicación'], how='left')
La sincronización de datos es otro aspecto clave. Si los datos de las fuentes externas se actualizan con frecuencia, es posible que necesitemos diseñar un sistema de actualización periódica para mantener nuestro dataset al día.
Por último, al manejar múltiples fuentes, es útil emplear una arquitectura modular en nuestro código. Esto facilita el mantenimiento y la escalabilidad del proyecto, permitiendo agregar o modificar fuentes sin afectar significativamente el resto del sistema.
Como hemos visto, el enriquecimiento de datasets con datos de múltiples fuentes web requiere una combinación de habilidades en extracción de datos, procesamiento y manejo de datos, así como una atención cuidadosa a los detalles para garantizar la calidad y coherencia de los datos integrados.
Ejercicios de esta lección Web Scraping para ciencia de datos
Evalúa tus conocimientos de esta lección Web Scraping para ciencia de datos con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Polimorfismo
Clases y objetos
Listas
Estructuras de control
Diccionarios
Importar módulos y paquetes
Módulo math
Operadores
OOP en python
Estructuras de control
Instalación de Python y creación de proyecto
Listas
Estructuras de control
Encapsulación
Clases y objetos
Encapsulación
Tipos de datos
Crear módulos y paquetes
Herencia de clases
Tuplas
Crear módulos y paquetes
Herencia
Módulo datetime
Excepciones
Operadores
Funciones lambda
Importar módulos y paquetes
Clases y objetos
Diccionarios
Módulo os
Listas
Conjuntos
Funciones lambda
Tuplas
Módulo json
Operadores
Variables
Tipos de datos
Diccionarios en Python
Conjuntos
Módulo math
Excepciones
Módulo csv
Gestor de tareas CRUD
Funciones Python
Módulo json
Tipos de datos
Módulo datetime
Herencia
Análisis de datos de ventas con Pandas
Funciones
Funciones Python
Variables
Módulo csv
Introducción a Python
Polimorfismo
Módulo os
Todas las lecciones de Python
Accede a todas las lecciones de Python y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Python
Introducción Y Entorno
Instalación Y Creación De Proyecto
Introducción Y Entorno
Tipos De Datos
Sintaxis
Variables
Sintaxis
Operadores
Sintaxis
Estructuras De Control
Sintaxis
Funciones
Sintaxis
Funciones Lambda
Programación Funcional
Clases Y Objetos
Programación Orientada A Objetos
Excepciones
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
Listas
Estructuras De Datos
Tuplas
Estructuras De Datos
Diccionarios
Estructuras De Datos
Conjuntos
Estructuras De Datos
Módulo Csv
Biblioteca Estándar
Módulo Json
Biblioteca Estándar
Módulo Datetime
Biblioteca Estándar
Módulo Math
Biblioteca Estándar
Módulo Os
Biblioteca Estándar
Importar Módulos Y Paquetes
Paquetes Y Módulos
Crear Módulos Y Paquetes
Paquetes Y Módulos
Instalación Beautiful Soup
Web Scraping
Sintaxis General De Beautiful Soup
Web Scraping
Tipos De Selectores
Web Scraping
Web Scraping De Html
Web Scraping
Web Scraping Para Ciencia De Datos
Web Scraping
Autenticación Y Acceso A Recursos Protegidos
Web Scraping
Combinación De Selenium Con Beautiful Soup
Web Scraping
Acceso A Datos Con Mysql, Pymongo Y Pandas
Acceso A Bases De Datos
Certificados de superación de Python
Supera todos los ejercicios de programación del curso de Python y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.
Objetivos de aprendizaje de esta lección
- Entender cómo integrar Beautiful Soup con Pandas para manipulación de datos.
- Aprender a extraer datos no estructurados de páginas web.
- Dominar la limpieza y preprocesamiento de datos scrapeados.
- Enriquecer datasets con información de múltiples fuentes web.
- Manejar errores comunes en el web scraping y realizar un análisis eficaz.