Web Scraping (BeautifulSoup, Selenium)

 Existen dos enfoques principales:

  • BeautifulSoup → para analizar HTML estático

  • Selenium → para interactuar con páginas dinámicas (JavaScript)

Vamos paso a paso.

1. Web Scraping con BeautifulSoup

Ideal para páginas estáticas donde el contenido ya está en el HTML.

Instalación

pip install requests beautifulsoup4

Ejemplo básico: extraer títulos de una web

import requests
from bs4 import BeautifulSoup

url = "https://example.com"
respuesta = requests.get(url)

soup = BeautifulSoup(respuesta.text, "html.parser")

titulos = soup.find_all("h2")

for t in titulos:
    print(t.text)

Selección de elementos

Por etiqueta

soup.find("p")
soup.find_all("a")

Por clase

soup.find_all("div", class_="producto")

Por id

soup.find(id="precio")

Con selectores CSS

soup.select("div.item > a.link")

2. Web Scraping con Selenium

Selenium permite controlar un navegador real (Chrome, Firefox…) y es ideal para páginas con JavaScript.

Instalación

pip install selenium

Ejemplo básico: abrir una página y extraer texto

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://example.com")

titulo = driver.find_element(By.TAG_NAME, "h1").text
print(titulo)

driver.quit()

Interacciones comunes

Escribir en un campo

driver.find_element(By.ID, "busqueda").send_keys("python")

Hacer clic

driver.find_element(By.CLASS_NAME, "boton").click()

Esperas (muy importante)

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CLASS_NAME, "resultado"))
)

3. Diferencias entre BeautifulSoup y Selenium

CaracterísticaBeautifulSoupSelenium
VelocidadMuy rápidoMás lento
JavaScriptNo lo ejecuta
InteracciónNoSí (clics, formularios…)
Uso idealWeb estáticaWeb dinámica

ACTIVIDAD PRÁCTICA: “Scraper de precios con Selenium + BeautifulSoup”

Objetivo: que tus alumnos construyan un scraper real que:

  1. Abra una página de productos con Selenium

  2. Espere a que cargue el contenido dinámico

  3. Obtenga el HTML final

  4. Use BeautifulSoup para extraer:

    • Nombre del producto

    • Precio

    • Enlace

  5. Guarde los datos en un archivo JSON

Pistas

  • Usa driver.page_source para obtener el HTML final

  • Usa soup.find_all() para recorrer productos

  • Usa json.dump() para guardar los datos

Solución propuesta

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
import json
import time

driver = webdriver.Chrome()
driver.get("https://example.com/productos")

# Esperar a que carguen los productos
WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CLASS_NAME, "producto"))
)

# Obtener HTML final
html = driver.page_source
driver.quit()

# Analizar con BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
productos_html = soup.find_all("div", class_="producto")

productos = []

for p in productos_html:
    nombre = p.find("h2").text.strip()
    precio = p.find("span", class_="precio").text.strip()
    enlace = p.find("a")["href"]

    productos.append({
        "nombre": nombre,
        "precio": precio,
        "enlace": enlace
    })

# Guardar en JSON
with open("productos.json", "w", encoding="utf-8") as f:
    json.dump(productos, f, indent=4, ensure_ascii=False)

print("Scraping completado. Datos guardados en productos.json")

Resultado esperado

Un archivo productos.json con contenido como:

[
    {
        "nombre": "Teclado Mecánico",
        "precio": "29.99€",
        "enlace": "/producto/teclado"
    },
    {
        "nombre": "Ratón Inalámbrico",
        "precio": "14.50€",
        "enlace": "/producto/raton"
    }
]