
Aloísio Vítor
Image Processing Expert

Un agente de IA puede recibir un registro que parece válido de la página equivocada. Una pantalla de inicio de sesión puede contener un título, un documento incompleto puede analizarse correctamente y un modelo puede devolver JSON incluso cuando los hechos solicitados estén ausentes. Una arquitectura de scraping web para agentes de IA necesita decisiones separadas para acceder a la fuente e interpretar su contenido.
Este tutorial diseña esa frontera alrededor de una instantánea inmutable y un contrato de registro versionado. El flujo de trabajo aplica a la recopilación autorizada de avisos públicos, actualizaciones de documentación y otros datos web permitidos. CapSolver aparece como una capacidad de manejo de CAPTCHA admitida en la capa de acceso. El ejemplo ejecutable muestra luego cómo clasificar los resultados de adquisición, extraer un pequeño conjunto de registros y preservar evidencia cuando la validación falle.
La capa de acceso debe devolver una instantánea utilizable o un fallo explícito; la capa de extracción debe devolver registros candidatos vinculados a esa instantánea. Mantén ambos contratos estables incluso cuando cambie el entorno de navegador, el analizador o el modelo.
El flujo es: solicitud de recopilación aprobada → adaptador de acceso → instantánea guardada → adaptador de extracción → validación → almacén de registros aceptados → agente. En este diseño, la extracción puede ejecutarse nuevamente desde la evidencia almacenada sin volver a abrir un navegador.
Proporciona al adaptador de acceso una fuente aprobada, una identidad de tarea, un presupuesto de tiempo y un contexto de sesión permitido. Su trabajo incluye elegir la representación requerida, esperar contenido relevante, preservar la propiedad de la sesión y clasificar fallos. La configuración de red y el renderizado de JavaScript pertenecen a tu infraestructura HTTP o de navegador.
La salida debe registrar las ubicaciones de origen solicitada y final, el momento de observación, el tipo de representación, el resumen de contenido y la evidencia de preparación. Evita una bandera única de "éxito" que oculte qué página realmente se cargó. Una URL final y un estado HTTP ayudan, pero también se necesitan comprobaciones de la identidad del documento esperado y de las regiones de contenido requeridas.
Proporciona al extractor una referencia a una instantánea, una versión de esquema y definiciones de campos. No debe navegar silenciosamente, cambiar credenciales o seleccionar otra ruta de red. Devuelve campos faltantes o ambiguos explícitamente en lugar de pedir al adaptador de acceso que siga intentando hasta que aparezca algún valor.
El glosario de scraping web con IA describe el uso más amplio de la IA para recopilar e interpretar información web. Esta frontera también admite extracción determinista: atributos estables o datos estructurados documentados pueden ser suficientes. Usa un modelo cuando sea necesario la interpretación, manteniendo el mismo contrato de validación posterior.
Una instantánea utilizable debe contener la evidencia necesaria para los campos solicitados, en una representación que el extractor entienda. Selecciona HTML, DOM renderizado o una captura de pantalla según ese requisito.
El HTML sin procesar es adecuado cuando la respuesta ya contiene el contenido relevante. Si los campos necesarios aparecen solo después de la ejecución del lado del cliente, un adaptador de navegador debe capturar el DOM renderizado después de una verificación de listo específica para la tarea. Define listo como una condición observable, como el contenedor de registros esperado y el marcador de finalización, en lugar de un sueño fijo universal.
Registra qué representación se capturó. Un analizador probado en marcado renderizado no debe recibir una estructura HTML inicial sin un cambio explícito en el contrato. Si una región requerida está ausente, clasifica la instantánea como incompleta antes de intentar la extracción.
Una captura de pantalla proporciona píxeles de un viewport específico en un momento específico. Para la extracción basada en capturas de pantalla, retiene las dimensiones de la imagen, el contexto de captura y una referencia de región para cada campo extraído. Si un valor está fuera del área capturada, devuélvelo como faltante; la familiaridad de un modelo con diseños similares no es evidencia para ese valor.
No conviertas una estimación visual en un número exacto sin registrar la incertidumbre. Donde ambos, DOM y evidencia visual estén disponibles, usa los desacuerdos como casos de revisión. El ejemplo siguiente implementa solo un adaptador HTML; un adaptador de visión necesitaría sus propias comprobaciones de evidencia y conjunto de evaluación.
Una decisión de reintentar debe nombrar la capa fallida, el beneficio esperado de otro intento y el presupuesto restante. Mantén separados los reintentos de adquisición e interpretación para que un error de extracción no cree tráfico no controlado.
| Observación | Capa responsable | Acción recomendada |
|---|---|---|
| Tiempo de espera agotado o error temporal seleccionado | Acceso | Reintenta solo una lectura permitida dentro de su presupuesto de tiempo y intentos |
| HTTP 429 o refrigeración solicitada por el servicio | Acceso | Posponer a un programador compartido y preservar la señal de refrigeración |
| HTTP 401/403 o autorización poco clara | Acceso | Detener y revisar el camino de acceso permitido |
| Desafío de CAPTCHA reconocido | Acceso | Pausar para revisión de elegibilidad y tarea admitida |
| Respuesta vacía, documento equivocado o región requerida ausente | Acceso | Conservar evidencia diagnóstica e investigar listo |
| Campo faltante, fecha inválida, registro duplicado o discrepancia de esquema | Extracción/validación | Cuarentenar el candidato y repetir contra la instantánea |
| Formato válido pero significado no admitido | Validación | Rechazar o solicitar revisión; no tratar texto fluido como evidencia |
Los semánticas HTTP son importantes al implementar la primera fila. Las reglas de reintentar e idempotencia de RFC 9110 distinguen operaciones que pueden repetirse con seguridad de operaciones cuyos efectos pueden ser inciertos. No reutilices un bucle de reintentar lectura para envíos de formularios u otras acciones que cambien estado.
El encabezado Retry-After puede expresar un retraso o una fecha HTTP. Preserva el valor para programación. Un trabajador local no debe reemplazar una espera solicitada por el servidor con un retroceso más corto, y los trabajadores que compartan el mismo ámbito de recopilación permitido deben compartir el estado de refrigeración.
CapSolver debe manejar solo una tarea de CAPTCHA documentada después de que tu flujo de trabajo haya establecido permiso, compatibilidad de tarea y contexto de sesión requerido. Una respuesta 403, una página vacía y un widget de CAPTCHA son observaciones distintas; evita mapear todas ellas a una solicitud de resolución.
El contrato de createTask de CapSolver requiere el objeto de tarea adecuado. Para trabajo asíncrono, getTaskResult devuelve el estado y la salida de la tarea. El adaptador de acceso sigue siendo responsable de aplicar la integración documentada y verificar el destino posteriormente.
Una tarea completada no es una instantánea de página validada. Vuelve a comprobar la identidad del documento y las condiciones de listo antes de entregar contenido a la extracción. Establece un presupuesto separado para desafíos y detén cuando el desafío no esté admitido, la autorización sea poco clara o la página esperada permanezca inaccesible. El piloto de infraestructura de navegador para agentes de IA proporciona orientación relacionada sobre propiedad de runtime y evidencia de sesión.
Redime tu código de bonificación de CapSolver
¡Aumenta tu presupuesto de automatización instantáneamente!
Usa el código de bonificación CAP26 al recargar tu cuenta de CapSolver para obtener un 5% adicional en cada recarga — sin límites.
Redímelo ahora en tu Panel de CapSolver
El siguiente flujo de Python clasifica respuestas de acceso sintéticas, retiene HTML aceptado, extrae campos de anuncios y devuelve JSON estructurado. Guárdalo como pipeline_example.py y ejecútalo con Python 3.9 o posterior; utiliza solo la biblioteca estándar.
La función fetch es un adaptador de lectura solo. Aquí proporciona fijaciones en memoria y la demostración desactiva el sueño. No se contacta a ningún sitio web, servicio de navegador, modelo o API de CAPTCHA. Los campos challenge y ready representan observaciones suministradas por un adaptador de acceso; el ejemplo no implementa un detector universal de desafíos.
El analizador usa las devoluciones de llamada de HTMLParser de Python para un contrato de marcado deliberadamente pequeño: cada article contiene un h2, un ID de registro y una fecha de publicación. No es un analizador general de DOM ni validador para HTML mal formado arbitrario.
from dataclasses import dataclass
from datetime import date
from hashlib import sha256
from html.parser import HTMLParser
import json
import time
class PipelineError(Exception):
def __init__(self, stage, reason, retry_after=""):
self.stage, self.reason = stage, reason
self.retry_after = retry_after
super().__init__(f"{stage}:{reason}")
@dataclass(frozen=True)
class Reply:
status: int
body: str = ""
content_type: str = "text/html"
challenge: bool = False
ready: bool = True
retry_after: str = ""
def access(fetch, wait=time.sleep):
# fetch is a read-only adapter; all values below are application policy.
for attempt in range(2):
try:
reply = fetch()
except TimeoutError:
if attempt == 0:
wait(0.5)
continue
raise PipelineError("access", "timeout_exhausted")
if reply.status == 429:
# Pass Retry-After to a shared scheduler; do not retry here.
raise PipelineError("access", "defer_rate_limit", reply.retry_after)
if reply.status in (401, 403):
raise PipelineError("access", "authorization_review")
if reply.challenge:
raise PipelineError("access", "challenge_review")
if reply.status == 503 and reply.retry_after:
raise PipelineError("access", "defer_service", reply.retry_after)
if reply.status in (502, 503, 504) and attempt == 0:
wait(0.5)
continue
if reply.status != 200:
raise PipelineError("access", "http_status")
if reply.content_type.split(";")[0].strip().lower() != "text/html":
raise PipelineError("access", "representation_mismatch")
if not reply.ready or not reply.body.strip():
raise PipelineError("access", "incomplete_snapshot")
return reply.body
raise PipelineError("access", "attempts_exhausted")
class BulletinParser(HTMLParser):
# This small parser supports only the documented fixture markup.
def __init__(self):
super().__init__(convert_charrefs=True)
self.rows, self.current, self.in_title = [], None, False
def handle_starttag(self, tag, attrs):
attrs = dict(attrs)
if tag == "article":
if self.current is not None:
raise PipelineError("extraction", "nested_record")
self.current = {"id": attrs.get("data-id", ""),
"published": attrs.get("data-published", ""),
"title_parts": [], "title_count": 0}
elif tag == "h2" and self.current is not None:
self.current["title_count"] += 1
self.in_title = True
def handle_data(self, data):
if self.current is not None and self.in_title:
self.current["title_parts"].append(data)
def handle_endtag(self, tag):
if tag == "h2":
self.in_title = False
if tag == "article" and self.current is not None:
self.rows.append(self.current)
self.current, self.in_title = None, False
def extract(html):
parser = BulletinParser()
parser.feed(html)
parser.close()
if parser.current is not None or not parser.rows:
raise PipelineError("extraction", "record_structure")
records, seen = [], set()
for row in parser.rows:
title = " ".join("".join(row["title_parts"]).split())
if not row["id"].strip() or not title or row["title_count"] != 1:
raise PipelineError("extraction", "required_field")
try:
published = date.fromisoformat(row["published"]).isoformat()
except ValueError:
raise PipelineError("extraction", "invalid_date")
if row["id"] in seen:
raise PipelineError("extraction", "duplicate_id")
seen.add(row["id"])
records.append({"id": row["id"], "title": title,
"published": published})
return records
def run(fetch, archive, wait=time.sleep):
html = access(fetch, wait)
digest = sha256(html.encode("utf-8")).hexdigest()
archive[digest] = html # In-memory evidence retained even if parsing fails.
records = extract(html)
return {"schema_version": "bulletins.v1", "source_id": "fixture:bulletins",
"snapshot_sha256": digest,
"records": records}
if __name__ == "__main__":
html = ('<article data-id="notice-1" data-published="2026-09-10">'
'<h2>Maintenance window announced</h2></article>')
replies = iter([Reply(503), Reply(200, html)])
archive = {}
output = run(lambda: next(replies), archive, wait=lambda seconds: None)
print(json.dumps(output, indent=2))
La demostración recibe un 503 sintético seguido de una respuesta HTML elegible. Produce este resultado:
{
"schema_version": "bulletins.v1",
"source_id": "fixture:bulletins",
"snapshot_sha256": "6ed8df5a98ee53e2889feb5ef7ed4dd8d549dba82882580418d4ca9656b7d46b",
"records": [
{
"id": "notice-1",
"title": "Maintenance window announced",
"published": "2026-09-10"
}
]
}
Cada registro debe tener un ID, un encabezado no vacío y una fecha parseable. Los IDs duplicados rechazan el lote. El resumen de la instantánea conecta la salida con el HTML conservado, y los errores de extracción dejan ese HTML en un archivo propiedad del llamador para repetición.
El límite de reintentos de dos intentos y el retraso de medio segundo son políticas de aplicación de ejemplo, no recomendaciones del proveedor. El bucle retrasa inmediatamente un 429, preserva un enfriamiento de 503 y detiene en autorización o revisión de desafío. Un fallo en extract no puede llamar a fetch nuevamente.
Implementar admisión de fuentes, verificación de redirecciones, decodificación de contenido soportada, temporizadores por solicitud y un plazo general antes de conectar el ejemplo a un transporte real. Un fetch sincrónico que nunca devuelve no está limitado por un contador de intentos. Pasar el plazo restante al transporte e incluir los retrasos de reintentos en ese presupuesto.
Reemplazar el archivo en memoria con almacenamiento controlado, y agregar marcas de tiempo de observación, identidad de fuente real, versión del extractor y versión del esquema a su metadatos. Aplicar límites de tamaño antes de decodificar o analizar. Una instantánea fallida o incompleta puede ser aún evidencia diagnóstica útil, pero mantenerla separada del conjunto de instantáneas elegibles para extracción.
Los datos aceptados necesitan comprobaciones de significado y cobertura además de la estructura JSON. El ejemplo valida su pequeño contrato determinista; un servicio de extracción general necesita una política de aceptación más rica.
Comience con definiciones de campos. Una fecha de publicación, fecha de actualización y marca de tiempo de colección describen eventos diferentes. Especificar cuál necesita el agente y rechazar sustituciones. Para campos generados por modelos, adjuntar un intervalo de fuente o región visual y verificar que la evidencia respalden el significado del campo. Una palabra coincidente en alguna parte de la página es demasiado débil para campos como precio, disponibilidad o fecha.
Verificar completitud a nivel de colección. Un arreglo vacío podría significar "sin registros", un diseño cambiado, paginación incompleta o un fallo de extracción. Aceptar un resultado vacío solo cuando la fuente proporcione un estado vacío explícito y verificado. El ejemplo rechaza una lista vacía porque no tiene tal contrato.
Definir una ventana de frescura para la tarea. Reextraer una instantánea antigua puede corregir un problema de analizador, pero no hace que la observación subyacente sea actual. Incluir identidad de instantánea y versiones de extractor/esquema en la clave de repetición, y publicar registros aceptados a través de una operación de almacenamiento idempotente. Mantener disponibles candidatos rechazados para revisión diagnóstica limitada en lugar de mezclarlos en el conjunto de trabajo del agente.
Tratar el contenido de la página como entrada no confiable en todo momento. La guía de inyección de comandos de OWASP describe riesgos de instrucciones incrustadas en contenido externo. Mantener las herramientas de extracción separadas de credenciales y acciones consecuentes; el texto de fuente no debe adquirir autoridad para cambiar el alcance de la colección o enviar datos a otro lugar.
Las pruebas de límites deben verificar tanto el resultado devuelto como la ausencia de trabajo no deseado adicional. Un test de analizador exitoso no demuestra que la capa de acceso se detenga correctamente.
Para este ejemplo, probar un tiempo de espera seguido de éxito, errores temporales repetidos, una respuesta 200 marcada como desafío, un 429 con enfriamiento, una representación no soportada, encabezados faltantes, fechas inválidas y IDs duplicados. Contar llamadas del adaptador: el caso de desafío debe detenerse después de una llamada, y un fallo de análisis debe preservar la instantánea sin otra intento de acceso.
La suite de pruebas local adjunta aprobó 21 pruebas para el flujo de trabajo del ejemplo, incluyendo agotamiento de reintentos, preservación de enfriamiento, retención de instantáneas y repetición determinista. Estas son verificaciones de software sintéticas, no una tasa de éxito de fuente en vivo o un benchmark de extracción de modelo.
Antes de la implementación, agregar una pequeña fuente permitida en fase de prueba y probar la preparación para renderizado real, manejo de redirecciones, caducidad de sesión, cancelación de transporte y evidencia de salida. Medir instantáneas elegibles y registros aceptados por separado. Esa división le indica si mejorar la adquisición o la interpretación cuando cambie la tasa de aceptación final.
Una arquitectura de agente de scraping web con inteligencia artificial se vuelve más fácil de operar cuando cada etapa tiene una salida observable y un propietario claro. Mantener el contrato de acceso enfocado en instantáneas elegibles, el contrato de extracción enfocado en campos candidatos y la validación enfocada en evidencia, completitud y frescura.
Comenzar con el flujo de trabajo local, practicar los caminos negativos y conectar una fuente permitida solo después de que los límites del adaptador estén explícitos. Para flujos de trabajo que necesiten manejo documentado de CAPTCHA, evaluar CapSolver dentro de ese límite de acceso y verificar el destino antes de reanudar la extracción.
Q: ¿Cuál es la diferencia entre una capa de acceso web y una capa de extracción de datos?
La capa de acceso obtiene una instantánea de página elegible y clasifica los fallos de adquisición. La capa de extracción interpreta esa instantánea en campos candidatos. Una verificación de aceptación separada determina si los registros resultantes son adecuados para el agente.
Q: ¿Debe recibir un modelo de IA HTML, una instantánea del DOM o una captura de pantalla?
Usar la representación que contenga evidencia para los campos solicitados. HTML puede ser adecuado para contenido proporcionado por el servidor, el DOM renderizado puede capturar contenido del lado del cliente y las capturas de pantalla pueden apoyar interpretación visual con referencias de región y comprobaciones de incertidumbre.
Q: ¿Debería causar un campo faltante otra solicitud de página?
Un campo faltante debería primero desencadenar una revisión o reextracción de la instantánea conservada. Solicitar una nueva página solo cuando la evidencia muestre que la instantánea es incompleta o obsoleta y la política de acceso permita otro intento.
Q: ¿Dónde encaja CapSolver en esta arquitectura?
CapSolver encaja detrás de una interfaz de tarea de CAPTCHA soportada en la capa de acceso para flujos autorizados. Su aplicación posee la elegibilidad de tarea, el contexto de sesión, el presupuesto de reintentos y la validación del destino después de que finalice la tarea.
Q: ¿Realiza el ejemplo de Python scraping web con IA en vivo?
No. El ejemplo ejecuta un flujo de trabajo de fixture de HTML local y prueba sus contratos. Una implementación en vivo debe agregar un adaptador de acceso permitido; la extracción basada en modelo o visual también necesita su propia implementación y evaluación basada en evidencia.
Evaluar servicios de CAPTCHA empresariales con una prueba piloto enfocada que cubra la compatibilidad de las tareas, los resultados aceptados, la atribución de costos, la evidencia de seguridad y el soporte.

Utilice una lista de verificación del servidor MCP de producción para revisar los permisos de la herramienta, el aislamiento de inquilinos, las entradas, el manejo de fallos, los logs y la evidencia de lanzamiento antes del despliegue.
