El web scraping permite extraer datos de sitios web de forma automática. Como sysadmin lo usarás para monitorizar páginas de estado, extraer información de paneles sin API, o automatizar la descarga de reportes. Con requests y BeautifulSoup puedes hacerlo en pocas líneas.
Instalación
pip install requests beautifulsoup4 lxml --break-system-packages
Hacer peticiones HTTP con requests
import requests
response = requests.get("https://httpbin.org/get")
print(response.status_code) # 200
print(response.headers)
print(response.text) # HTML o texto
print(response.json()) # si la respuesta es JSON
headers = {
"User-Agent": "Mozilla/5.0 (compatible; MiBot/1.0)",
"Accept-Language": "es-ES,es;q=0.9"
}
response = requests.get("https://ejemplo.com", headers=headers, timeout=10)
response.raise_for_status() # lanza excepción si el status no es 2xx
session = requests.Session()
session.headers.update(headers)
login_data = {"username": "admin", "password": "secreto"}
session.post("https://panel.ejemplo.com/login", data=login_data)
response = session.get("https://panel.ejemplo.com/dashboard")
Parsear HTML con BeautifulSoup
from bs4 import BeautifulSoup
import requests
html = requests.get("https://news.ycombinator.com").text
soup = BeautifulSoup(html, "lxml")
titulos = soup.find_all("span", class_="titleline")
for t in titulos[:5]:
enlace = t.find("a")
print(enlace.text, "→", enlace.get("href"))
contenido = soup.find(id="hnmain")
filas = soup.select("tr.athing")
for fila in filas[:3]:
print(fila.select_one(".titleline a").text)
imagenes = soup.find_all("img")
urls = [img.get("src") for img in imagenes if img.get("src")]
primer_parrafo = soup.find("p")
siguiente = primer_parrafo.find_next_sibling("p")
padre = primer_parrafo.parent
Ejemplo real: monitorizar el estado de un servicio web
import requests
from bs4 import BeautifulSoup
import smtplib
from email.mime.text import MIMEText
from datetime import datetime
SERVICIOS = [
("GitHub", "https://www.githubstatus.com"),
("Cloudflare", "https://www.cloudflarestatus.com"),
]
def verificar_estado(nombre, url):
try:
r = requests.get(url, timeout=10)
soup = BeautifulSoup(r.text, "lxml")
# Buscar el indicador de estado (varía por página)
estado = soup.select_one(".page-status .status")
if estado:
return estado.text.strip()
return "Desconocido"
except requests.RequestException as e:
return f"Error: {e}"
for nombre, url in SERVICIOS:
estado = verificar_estado(nombre, url)
simbolo = "✓" if "operational" in estado.lower() else "⚠"
print(f"{simbolo} {nombre}: {estado}")
Ejemplo real: extraer tabla de datos
import requests
from bs4 import BeautifulSoup
import csv
def scrape_tabla(url, tabla_id=None, clase=None):
response = requests.get(url, timeout=10)
soup = BeautifulSoup(response.text, "lxml")
if tabla_id:
tabla = soup.find("table", id=tabla_id)
elif clase:
tabla = soup.find("table", class_=clase)
else:
tabla = soup.find("table")
if not tabla:
return []
filas = []
for tr in tabla.find_all("tr"):
celdas = [td.get_text(strip=True) for td in tr.find_all(["th", "td"])]
if celdas:
filas.append(celdas)
return filas
datos = scrape_tabla("https://intranet.miempresa.local/servidores")
with open("servidores.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(datos)
Manejar JavaScript (Selenium para webs dinámicas)
BeautifulSoup solo ve el HTML estático. Para webs con contenido generado por JavaScript necesitas Selenium o Playwright:
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
options = webdriver.ChromeOptions()
options.add_argument("--headless") # sin ventana gráfica
options.add_argument("--no-sandbox")
driver = webdriver.Chrome(options=options)
driver.get("https://panel.ejemplo.com/login")
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "username")))
driver.find_element(By.ID, "username").send_keys("admin")
driver.find_element(By.ID, "password").send_keys("secreto")
driver.find_element(By.ID, "submit").click()
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CLASS_NAME, "dashboard")))
datos = driver.find_element(By.CLASS_NAME, "dashboard").text
driver.quit()
Buenas prácticas y ética
- Respeta el archivo
robots.txtdel sitio. - Añade un delay entre peticiones para no sobrecargar el servidor (
time.sleep(1)). - Identifícate con un User-Agent que incluya tu información de contacto.
- Verifica si el sitio ofrece API antes de hacer scraping; siempre es preferible.
- Nunca hagas scraping de datos personales sin permiso explícito.
Conclusión
Requests + BeautifulSoup es el dúo perfecto para scraping de HTML estático. Para la mayoría de necesidades de monitorización y extracción de datos internos, estas dos bibliotecas son más que suficientes. Cuando el sitio usa JavaScript, Playwright es la alternativa moderna a Selenium con una API más limpia.