Volver al blog

MechanicalSoup: Automatizar el raspado basado en formularios en Python

Alex Johnson
Alex Johnson

Senior Web Scraping Engineer

29-Jun-2026

Resumen:

  • MechanicalSoup automatiza sitios impulsados por formularios al combinar requests con BeautifulSoup. Un objeto StatefulBrowser abre una página, selecciona un formulario, llena sus campos, lo envía y analiza la respuesta: sin proceso de navegador y sin motor JavaScript.
  • El navegador mantiene las cookies y el estado de la sesión a través de las solicitudes por ti. Después de un inicio de sesión o un Set-Cookie, el mismo StatefulBrowser envía la cookie almacenada en cada solicitud posterior, por lo que los flujos de múltiples pasos se comportan como una sesión real.
  • select_form más la asignación de campo estilo diccionario es la totalidad de la superficie API. Seleccionas un formulario mediante un selector CSS, configuras browser["nombre_del_campo"] = valor, y llamas a submit_selected() — la biblioteca maneja la codificación y la redirección.
  • MechanicalSoup solo lee el HTML que devuelve el servidor — no ejecuta JavaScript. Una página que construye su contenido del lado del cliente regresa vacía, ya que no hay un paso de renderizado DOM entre la respuesta HTTP y BeautifulSoup.
  • Cuando una página necesita renderizado o activa un desafío anti-bot, entrega la carga a Scrapeless Scraping Browser y continúa analizando con BeautifulSoup. El SDK de Scrapeless genera una sesión en la nube, Playwright la controla a través de CDP para ejecutar el JavaScript, y el HTML renderizado fluye directamente de vuelta a los mismos selectores soup.select(...).
  • Gratis para empezar. Las nuevas cuentas de Scrapeless incluyen tiempo de ejecución gratis de Scraping Browser — regístrate en app.scrapeless.com.

Introducción: los formularios siguen siendo donde se oculta la mayor parte del trabajo de scraping

Una gran parte de datos útiles se encuentra detrás de un formulario: un cuadro de búsqueda, un inicio de sesión, un panel de filtros, un asistente de múltiples páginas. MechanicalSoup existe precisamente para ese tipo de sitio. Envuelve la biblioteca HTTP requests y BeautifulSoup en un solo objeto de navegador con estado: obtiene una página, te permite llenar y enviar formularios HTML en ella, sigue la redirección y analiza lo que regresa. Sin Selenium, sin Chromium, sin binario de controlador.

El minimalismo lo mantiene rápido y también establece una línea clara sobre lo que la biblioteca puede alcanzar. MechanicalSoup habla semántica HTTP y analiza HTML. Nunca ejecuta el JavaScript de la página, por lo que cualquier cosa renderizada del lado del cliente —un feed de desplazamiento infinito, una lista de resultados de React, un cuadro de búsqueda que obtiene resultados a través de XHR— regresa como la concha vacía que el servidor envió primero. Se mantiene rápido en un formulario renderizado por el servidor y se vuelve ciego en uno renderizado por el cliente.

Esta guía recorre un flujo de trabajo real de MechanicalSoup de principio a fin: instalar, abrir una página, llenar y enviar un formulario, llevar cookies a través de una sesión y raspar los resultados, y luego muestra el límite honesto. Cuando un objetivo se renderiza en el navegador o está detrás de un desafío anti-bot activo, la carga se mueve a Scrapeless Scraping Browser a través del Protocolo DevTools de Chrome, mientras tu código de análisis BeautifulSoup permanece exactamente como estaba.


Lo que puedes hacer con ello

  • Enviar formularios de inicio de sesión y mantener la autenticación. Completa los campos de nombre de usuario y contraseña, envía, y el StatefulBrowser mantiene las cookies de sesión para cada página después de ello.
  • Conducir formularios de búsqueda y filtro. Establece un campo de consulta, envía y analiza las filas de resultados que devuelve el servidor: el clásico bucle de búsqueda y raspado.
  • Recorrer flujos de múltiples páginas. Sigue enlaces y envía formularios sucesivos en un solo objeto de navegador, con la jarra de cookies y el referer llevados automáticamente.
  • Leer tablas y listas renderizadas por el servidor. Cualquier cosa presente en el HTML en bruto —tablas de precios, listados, páginas de directorio— está a un soup.select() de distancia.
  • Scripting de envíos repetitivos. Vuelve a ejecutar el mismo formulario con diferentes valores de campo para barrer un catálogo de consultas sin tocar un navegador real.

Por qué Scrapeless Scraping Browser

Scrapeless Scraping Browser es un navegador en la nube personalizable y anti-detección diseñado para rastreadores web y agentes de IA. Para las páginas que MechanicalSoup no puede alcanzar por sí solo, trae:

  • Renderizado de JavaScript del lado de la nube — los scripts de la página se ejecutan en el navegador remoto, así que el contenido construido por el cliente existe en el HTML para cuando lo analices.
  • Proxies residenciales en más de 195 países — ancla la salida con proxy_country para que las páginas geográficamente restringidas y los formularios bloqueados por región sirvan el contenido que ofrecerían a un visitante local.
  • Huella anti-detección — la sesión se presenta como un navegador real, por lo que el formulario o página de resultados se renderiza en lugar de devolver un intersticial de desafío.
  • Persistencia de sesión — las cookies y el estado de autenticación permanecen activos a través de las navegaciones dentro de una sesión, la misma propiedad que MechanicalSoup te ofrece localmente.
  • Un endpoint CDP estándarbrowser_ws_endpoint es una URL WebSocket ordinaria, por lo que Playwright (o cualquier cliente CDP) se conecta con una sola llamada y tu código de análisis permanece sin cambios.

Obtén tu clave API en el plan gratuito en app.scrapeless.com.


Requisitos previos

  • Python 3.10 o superior
  • Una cuenta de Scrapeless y clave API: regístrate en app.scrapeless.com (solo necesaria para la sección del navegador en la nube)
  • Familiaridad básica con selectores CSS y la terminal

Instalación

MechanicalSoup es un paquete único que incluye requests y beautifulsoup4 como dependencias:

bash Copy
pip install mechanicalsoup

Confirma la instalación y la versión:

bash Copy
python -c "import mechanicalsoup; print(mechanicalsoup.__version__)"
# 1.4.0

Configuración: abrir una página con un StatefulBrowser

Todo en MechanicalSoup se ejecuta a través de un StatefulBrowser. Mantiene la página actual, la sesión y la jarra de cookies. Establece un agente de usuario al crear el objeto para que las solicitudes lleven una identidad razonable:

python Copy
import mechanicalsoup

browser = mechanicalsoup.StatefulBrowser(
    user_agent="Mozilla/5.0 (compatible; data-collector)"
)

browser.open("https://httpbingo.org/forms/post")
# browser.page es ahora un objeto BeautifulSoup que puedes consultar directamente

browser.open() devuelve la respuesta de requests; browser.page es el árbol BeautifulSoup analizado para la página que acabas de cargar.


Implementación básica: llenar y enviar un formulario

El bucle central son tres llamadas: seleccionar el formulario, asignar sus campos, enviar. select_form toma un selector CSS; la asignación de campos se realiza al estilo diccionario en el navegador; submit_selected() envía el formulario y sigue la redirección.

python Copy
import mechanicalsoup

browser = mechanicalsoup.StatefulBrowser(
    user_agent="Mozilla/5.0 (compatible; data-collector)"
)
browser.open("https://httpbingo.org/forms/post")

# Apunta al formulario por su acción, luego llena los campos por nombre
browser.select_form('form[action="/post"]')
browser["custname"] = "Ada Lovelace"
browser["custtel"] = "555-0100"
browser["custemail"] = "ada@example.com"
browser["size"] = "mediano"             # botón de opción
browser["topping"] = ["bacon", "queso"]  # casillas de verificación de múltiples valores
browser["comments"] = "Dejar en la puerta"

response = browser.submit_selected()
print(response.status_code)
data = response.json()
print(data["url"])
print(data["form"])

El endpoint de httpbin devuelve el cuerpo del formulario analizado, lo que confirma exactamente lo que MechanicalSoup envió:

json Copy
{
  "url": "https://httpbingo.org/post",
  "form": {
    "comments": "Dejar en la puerta",
    "custemail": "ada@example.com",
    "custname": "Ada Lovelace",
    "custtel": "555-0100",
    "delivery": "",
    "size": "mediano",
    "topping": ["bacon", "queso"]
  }
}
// Los valores reflejan la verdadera presentación; el campo "delivery" vacío es un campo no establecido en el formulario.

Los botones de opción toman una sola cadena, los grupos de casillas de verificación toman una lista, y cualquier campo que quede sin configurar se envía vacío: la misma codificación que produciría un navegador.


Patrones avanzados

Mantener cookies a lo largo de una sesión

Un StatefulBrowser reutiliza una requests.Session, por lo que cualquier cookie que el servidor establezca persiste a solicitudes posteriores automáticamente. Eso es lo que hace que los inicios de sesión y los flujos de varios pasos funcionen:

python Copy
import mechanicalsoup

browser = mechanicalsoup.StatefulBrowser()

# El servidor establece una cookie en esta solicitud
browser.open("https://httpbingo.org/cookies/set?session_id=abc123")
print(browser.session.cookies.get_dict())
# {'session_id': 'abc123'}

# Una solicitud posterior en el mismo navegador envía la cookie almacenada de vuelta
echo = browser.open("https://httpbingo.org/cookies")
print(echo.json())
# {'cookies': {'session_id': 'abc123'}}

Para un inicio de sesión real, primero envía el formulario de inicio de sesión, luego sigue usando el mismo objeto browser: la cookie de autenticación viaja en cada página subsiguiente.

Enviar un formulario de búsqueda y raspar los resultados

Un formulario de búsqueda GET sigue el mismo patrón: establece el campo de consulta, envía, analiza las filas de resultado de browser.page.

python Copy
import mechanicalsoup

browser = mechanicalsoup.StatefulBrowser(
    user_agent="Mozilla/5.0 (compatible; data-collector)"
)
browser.open("https://www.scrapethissite.com/pages/forms/")

browser.select_form('form[action="/pages/forms/"]')
browser["q"] = "boston"
browser.submit_selected()
print(browser.url)  # https://www.scrapethissite.com/pages/forms/?q=boston

rows = browser.page.select("table.table tr.team")
print(f"{len(rows)} filas")
for row in rows[:3]:
    name = row.select_one(".name").get_text(strip=True)
    year = row.select_one(".year").get_text(strip=True)
    wins = row.select_one(".wins").get_text(strip=True)
    print(name, year, "victorias:", wins)

Debido a que la página de resultados se renderiza en el servidor, las filas están en el HTML que MechanicalSoup ya tiene, no se necesita una segunda solicitud.
Consigue tu clave de API en el plan gratuito: app.scrapeless.com


MechanicalSoup le entrega a BeautifulSoup lo que el servidor devolvió por HTTP, nada más. Cuando una página construye su contenido con JavaScript del lado del cliente, ese HTML sin procesar es un cuerpo vacío, y los selectores no encuentran nada:

python Copy
import mechanicalsoup

browser = mechanicalsoup.StatefulBrowser()
browser.open("https://quotes.toscrape.com/js/")
quotes = browser.page.select(".quote .text")
print("Citas encontradas por MechanicalSoup:", len(quotes))
# Citas encontradas por MechanicalSoup: 0

Cero. La variante /js/ de esa página inyecta sus citas con JavaScript después de cargar, por lo que no hay nada en el HTML del servidor para que BeautifulSoup lo coincida. El mismo obstáculo aparece frente a las páginas que tienen un desafío contra bots o que solo sirven contenido a una IP residencial, ninguno de los cuales un cliente solo HTTP puede superar.

La solución mantiene todo lo que ya escribiste. Deja que Scrapeless Scraping Browser haga el renderizado: el SDK crea una sesión en la nube, Playwright se conecta a ella a través de CDP y ejecuta el JavaScript de la página, y tú pasas el HTML renderizado directamente a los mismos selectores de BeautifulSoup.

Instala el SDK y un cliente de Playwright, luego obtiene el binario del navegador que Playwright controla:

bash Copy
pip install scrapeless playwright beautifulsoup4
python -m playwright install chromium

Establece tu clave en el entorno, nunca la codifiques:

bash Copy
export SCRAPELESS_API_KEY="tu_token_api_aqui"

Ahora renderiza la página del lado de la nube y analiza el resultado localmente:

python Copy
import os
from scrapeless import Scrapeless
from scrapeless.types import ICreateBrowser
from playwright.sync_api import sync_playwright
from bs4 import BeautifulSoup

client = Scrapeless()  # lee SCRAPELESS_API_KEY del entorno

# Crea una sesión en la nube; fija la salida residencial de EE. UU. para páginas con restricciones geográficas
session = client.browser.create(ICreateBrowser(
    session_name="guía-mechanicalsoup",
    session_ttl=180,
    proxy_country="US",
))

with sync_playwright() as p:
    # browser_ws_endpoint es una URL estándar wss:// CDP
    browser = p.chromium.connect_over_cdp(session.browser_ws_endpoint)
    page = browser.contexts[0].pages[0]
    page.goto("https://quotes.toscrape.com/js/", wait_until="domcontentloaded")
    page.wait_for_selector(".quote .text")
    html = page.content()
    browser.close()

# El mismo análisis de BeautifulSoup que usaste con MechanicalSoup
soup = BeautifulSoup(html, "html.parser")
quotes = soup.select(".quote .text")
print("Citas encontradas por Scrapeless + BeautifulSoup:", len(quotes))
print(quotes[0].get_text())
# Citas encontradas por Scrapeless + BeautifulSoup: 10
# “El mundo tal como lo hemos creado es un proceso de nuestro pensamiento. …”

La página que devolvió 0 filas a MechanicalSoup devuelve 10 a través del navegador en la nube, porque el JavaScript realmente se ejecutó antes de que se leyera el HTML. El renderizado y la salida se mueven del lado de la nube; la capa de análisis — soup.select(...) — es idéntica. Para una versión nativa de la biblioteca sobre la misma escalación, la guía del navegador en la nube Scrapling dirige un extractor de selector adaptativo a través del mismo browser_ws_endpoint.


Solución de problemas

Síntoma Causa Solución
LinkNotFoundError en select_form El selector CSS no coincide con ningún formulario en la página Imprime browser.page.select("form") y apunta al action/atributos reales
Los selectores de resultados devuelven una lista vacía La página renderiza su contenido con JavaScript Renderízalo del lado de la nube con el Scraping Browser, luego analiza el HTML devuelto
La envío ignora un campo El campo es un radio/casilla de verificación que necesita una cadena o lista, no un valor simple Asigna una sola cadena a los radios, una lista a los grupos de casillas de verificación
Una página con sesión iniciada actúa como si estuviera desconectada Un StatefulBrowser nuevo (nuevo jar de cookies) por paso Reutiliza un objeto browser para que la cookie de sesión persista
La página devuelve un desafío en lugar de contenido Reto activo contra bots o verificación de región en un cliente solo HTTP Fija proxy_country y deja que la huella digital del navegador en la nube renderice la página real

Conclusión: mantiene el analizador, cambia el fetch

MechanicalSoup es la herramienta adecuada para el gran conjunto de sitios que aún son HTML simple y formularios: abre una página, select_form, asigna campos, submit_selected(), y lee las filas con BeautifulSoup. El jar de cookies hace que los inicios de sesión y los flujos de múltiples pasos funcionen sin código adicional. Su única limitación es JavaScript: lee HTML, no lo renderiza. Cuando un objetivo se construye en el navegador o está detrás de un muro anti-bots, la solución más limpia es cambiar solo la obtención: crea una sesión de Scrapeless, renderiza la página a través de CDP y alimenta el HTML resultante en los mismos selectores. Cuando la página necesita un navegador sin cabeza completo con su propia salida de proxy, la guía de proxy de Puppeteer cubre el mismo patrón del lado de la nube, y la documentación de Scraping Browser documenta toda la superficie de CDP. Fija la salida de EE. UU. para páginas con restricciones geográficas, reutiliza una sesión a lo largo de los pasos y trata los campos ausentes como anulables.


¿Listo para construir tu pipeline de datos potenciado por IA?

Únete a nuestra comunidad para reclamar un plan gratuito y conectarte con desarrolladores que construyen automatización de formularios y pipelines de renderizado: Discord · Telegram.

Regístrate en app.scrapeless.com para obtener un tiempo de ejecución gratuito de Scraping Browser y adapta los patrones anteriores a los formularios, inicios de sesión y páginas renderizadas que necesita tu flujo de trabajo. Consulta precios para escalas.


FAQ

Q: ¿MechanicalSoup ejecuta JavaScript?
No. MechanicalSoup envuelve requests y BeautifulSoup, por lo que solo ve el HTML que devuelve el servidor. Las páginas que construyen su contenido en el lado del cliente regresan vacías; renderiza esas a través de un navegador en la nube y analiza el HTML resultante con los mismos selectores de BeautifulSoup.

Q: ¿Cómo maneja MechanicalSoup los inicios de sesión y las sesiones?
Un solo StatefulBrowser reutiliza una requests.Session, por lo que cualquier cookie que establezca el servidor persiste en cada solicitud posterior automáticamente. Envía el formulario de inicio de sesión una vez, luego sigue usando el mismo objeto del navegador y la cookie de autenticación permanece.

Q: ¿Cómo selecciono un formulario específico en una página?
Pasa un selector CSS a select_form, por ejemplo browser.select_form('form[action="/post"]'). Si no hay un formulario que coincida, obtendrás un LinkNotFoundError: imprime browser.page.select("form") para ver los atributos reales y dirigirte a uno de ellos.

Q: ¿Es legal raspar un sitio con MechanicalSoup?
Raspar datos públicamente visibles es generalmente permisible, pero las reglas varían según la jurisdicción y los términos de servicio del sitio. Revisa los Términos de Servicio del objetivo, respeta las directrices de robots, evita datos personales o restringidos y consulta a un abogado para cualquier cosa ambigua.

Q: ¿Necesito un proxy con MechanicalSoup?
Para páginas abiertas, renderizadas por el servidor, a menudo no. Para páginas que restringen por región o que solo sirven contenido a IPs residenciales, dirige la obtención a través del Scraping Browser de Scrapeless y fija proxy_country para que la solicitud salga desde una IP en la que el sitio confíe.

Q: ¿Puedo mantener mi código de BeautifulSoup cuando me mude al navegador en la nube?
Sí. El navegador en la nube solo reemplaza el paso de obtención; devuelve HTML renderizado, que puedes analizar con las mismas llamadas soup.select(...) que usabas con MechanicalSoup. La capa de análisis no cambia.

En Scrapeless, solo accedemos a datos disponibles públicamente y cumplimos estrictamente con las leyes, regulaciones y políticas de privacidad del sitio web aplicables. El contenido de este blog es sólo para fines de demostración y no implica ninguna actividad ilegal o infractora. No ofrecemos garantías y renunciamos a toda responsabilidad por el uso de la información de este blog o enlaces de terceros. Antes de realizar cualquier actividad de scraping, consulte a su asesor legal y revise los términos de servicio del sitio web de destino u obtenga los permisos necesarios.

Artículos más populares

Catalogar