Playwright + Navegador de Scraping Sin Residuos: Capturar y Reproducir una Sesión HAR Completa
Scraping and Proxy Management Expert
TL;DR:
- Un archivo HAR es un archivo HTTP estructurado, no una captura de pantalla o un video. Su array
log.entriesalmacena un objeto por cada solicitud HTTP capturada, incluyendo metadatos de solicitud y respuesta y, cuando está disponible, el contenido grabado. - Playwright graba archivos HAR a nivel de contexto del navegador. Establezca
record_har_pathal crear el contexto y llame acontext.close()para volcar el archivo en el disco. - Scrapeless Scraping Browser proporciona la sesión remota del navegador. Playwright se conecta a él a través de CDP, carga la página, activa solicitudes dinámicas y guarda el tráfico resultante localmente.
- El análisis HAR no requiere un navegador. Una vez que el archivo existe, el módulo estándar
jsonde Python puede inspeccionar sus URL, métodos, estados, tipos MIME, encabezados y cuerpos de respuesta incrustados. - Una solicitud capturada puede ser reemitida sin Playwright. El ejemplo reconstruye una solicitud JSON pública con
urllibdespués de eliminar los pseudo-encabezados de HTTP/2 y renegociar la codificación de contenido. - La reproducción de HAR tiene límites. Cookies expiradas, tokens CSRF, credenciales de portador, tramas de WebSocket y datos cambiantes del servidor pueden evitar que una solicitud posterior reproduzca la respuesta original.
- Gratis para empezar. Las nuevas cuentas de Scrapeless incluyen tiempo de ejecución de Scraping Browser gratuito — regístrate en app.scrapeless.com.
Introducción: Captura Primero, Decide Qué Importa Después
Un archivo HAR es un archivo JSON de transacciones HTTP observadas durante una sesión de navegador. No es una captura de pantalla de una página renderizada, un snapshot del DOM, o un video de la sesión.
Cada solicitud capturada aparece como un objeto dentro de:
text
log.entries
Una entrada puede contener el método de solicitud, URL, encabezados, parámetros de consulta, datos enviados, estado de respuesta, encabezados de respuesta, información de tiempo y contenido de respuesta grabado. El contenido binario puede ser representado con una codificación como Base64, mientras que los cuerpos textuales pueden aparecer directamente en la entrada.
Esta guía conecta Playwright al Scrapeless Scraping Browser a través del Protocolo de Herramientas de Desarrollo de Chrome, graba una carga completa de la página y una secuencia de desplazamiento con record_har_path, y cierra el navegador.
La segunda mitad del flujo de trabajo es libre de navegador:
- Inspeccionar la estructura HAR con
json. - Encontrar una solicitud API capturada.
- Reconstruir sus encabezados reutilizables.
- Reemitirla con
urllib. - Comparar la nueva respuesta JSON con el cuerpo almacenado en el archivo.
Cada resultado mostrado proviene de la sesión de objetivo capturada.
Lo Que Puedes Hacer Con Un Archivo HAR
La captura HAR es útil cuando el endpoint importante no se conoce antes de cargar una página.
- Auditar una carga completa de la página. Revisar HTML, hojas de estilo, scripts, fuentes, imágenes y solicitudes API de una sesión.
- Descubrir endpoints JSON internos. Buscar en el archivo después de la captura en lugar de predecir qué solicitud será importante.
- Depurar el comportamiento fallido de la página. Inspeccionar URL de solicitud, estados de respuesta, encabezados, tipos MIME y cuerpos después de que el navegador se haya cerrado.
- Preservar evidencia de red. Almacenar un artefacto JSON portátil que puede ser analizado más tarde o transferido a otra máquina.
- Comparar el comportamiento de carga de páginas. Capturar sesiones separadas y comparar sus conjuntos de solicitudes, estados o contenido de respuesta.
- Extraer datos de respuesta capturados. Leer cuerpos JSON o textuales incrustados sin cargar la página nuevamente.
- Reconstruir solicitudes elegibles. Reemitir solicitudes HTTP públicas o todavía autenticadas con un cliente HTTP estándar.
- Construir pruebas de navegador deterministas. Usar la función
route_from_har()separada de Playwright para servir respuestas grabadas de vuelta a un contexto de navegador en vivo.
Un archivo HAR es más valioso cuando una captura amplia es más útil que adjuntar un oyente a un endpoint ya conocido.
La Captura HAR, Grabación de Video y Enrutamiento HAR Son Diferentes
Tres características en esta área utilizan un lenguaje similar pero resuelven problemas diferentes.
| Característica | Lo que registra o hace | ¿Se requiere navegador después? |
|---|---|---|
Playwright record_har_path |
Archiva datos de solicitudes y respuestas HTTP | No, para inspección fuera de línea |
| Grabación de sesión Scrapeless | Crea una reproducción visual de la sesión renderizada | No, para reproducción en el panel |
Playwright route_from_har() |
Sirve respuestas grabadas a solicitudes hechas por un contexto de navegador | Sí |
El ejemplo de urllib en esta guía |
Reemite una solicitud capturada contra el servidor en vivo | No |
Intercepción en Vivo
La intercepción en vivo observa solicitudes a medida que ocurren. Funciona bien cuando el endpoint de destino o el patrón de respuesta ya son conocidos.
Una vez que la sesión termina, cualquier cosa que no haya sido capturada por el oyente se pierde.
Captura HAR
La captura HAR registra el tráfico HTTP del contexto de forma amplia. El endpoint que importa puede ser seleccionado después de que el navegador se cierre.
Esto hace que la captura HAR sea una mejor opción para:
- Depuración posterior a la sesión
- Inventarios de red
- Descubrimiento de API
- Auditoría de todos los recursos cargados por una página
- Preservar los cuerpos de respuesta para inspección offline
Grabación de Sesiones Sin Residuos
El Navegador de Scraping Sin Residuos soporta una capacidad de grabación de sesiones nativa separada. Esto produce un registro visual reproducible de la sesión del navegador renderizado.
No reemplaza un archivo HAR. Un video muestra lo que apareció en la pantalla; un HAR expone transacciones HTTP estructuradas.
Playwright route_from_har()
El route_from_har() de Playwright envía respuestas HAR guardadas de vuelta a las solicitudes realizadas por un contexto de navegador en vivo. Se utiliza comúnmente para simular el comportamiento del backend en pruebas de navegador.
El ejemplo de reproducción en esta guía hace algo diferente: lee una solicitud del archivo y envía una nueva solicitud HTTP en vivo con urllib.
¿Por qué capturar HAR a través del Navegador de Scraping Sin Residuos?
El Navegador de Scraping Sin Residuos proporciona el entorno de navegador remoto que Playwright controla a través de CDP.
La sesión del navegador se ejecuta en una infraestructura en la nube y soporta la selección de proxy geográfico a través de los parámetros de conexión. Playwright todavía utiliza sus API normales de navegador, contexto, página y HAR.
Para este flujo de trabajo, la división de responsabilidades es simple:
| Componente | Responsabilidad |
|---|---|
| Navegador de Scraping Sin Residuos | Ejecuta la sesión remota de Chromium y proporciona el punto final de CDP |
| Playwright | Crea el contexto, controla la página y graba el HAR |
| Sistema de archivos local | Almacena session.har |
| Biblioteca estándar de Python | Inspecciona el archivo y vuelve a emitir la solicitud seleccionada |
La grabación HAR en sí misma es una característica de Playwright. Conectar Playwright a Scrapeless mueve la etapa de renderizado en vivo a un navegador remoto administrado mientras deja el archivo resultante en la máquina que ejecuta el script de Python.
La conexión utiliza el mismo Dominio de red del Protocolo de herramientas de desarrollo de Chrome que las herramientas del navegador utilizan para observar la actividad de red.
El inicio rápido del Navegador de Scraping cubre el modelo de conexión más amplio de Playwright y Puppeteer.
Requisitos Previos
Necesitas:
- Python 3.9 o más reciente
- Playwright 1.59.0 para la ejecución reproducida
- Una cuenta y clave API de Scrapeless
- Acceso de escritura al directorio donde se creará
session.har - Acceso a la red a la página objetivo pública
Playwright 1.59.0 declara Python 3.9 o más reciente. Fijar esa versión hace que la instalación coincida con los resultados capturados en esta guía.
No se requiere ninguna instalación local de Chrome para este flujo de trabajo. connect_over_cdp() se conecta a un navegador que ya se está ejecutando en la infraestructura de Scrapeless.
Los scripts de inspección y reemisión de solicitudes utilizan solo la biblioteca estándar de Python. No importan Playwright ni abren una conexión de navegador.
Paso 1 — Instalar Playwright
Instala la versión utilizada para la ejecución registrada:
bash
pip install "playwright==1.59.0"
Debido a que el script se conecta a un navegador remoto existente a través de CDP, no lanza un ejecutable de navegador instalado localmente.
Establece la clave API de Scrapeless en la terminal:
bash
export SCRAPELESS_API_KEY="tu_clave_api_scrapeless"
El código lee la clave del entorno en lugar de almacenarla en el control de versiones.
Paso 2 — Construir la URL de Scrapeless CDP
La URL de conexión del Navegador de Scraping lleva la clave API, la duración de la sesión y la ubicación del proxy como parámetros de consulta:
python
import os
from urllib.parse import urlencode
API_KEY = os.environ["SCRAPELESS_API_KEY"]
def scraping_browser_url(proxy_country="US", session_ttl=180):
params = urlencode({
"token": API_KEY,
"sessionTTL": session_ttl,
"proxyCountry": proxy_country,
})
return f"wss://browser.scrapeless.com/api/v2/browser?{params}"
La función genera una URL en esta forma:
text
wss://browser.scrapeless.com/api/v2/browser?token=...&sessionTTL=180&proxyCountry=US
Los tres valores configurados son:
token: la clave API de ScrapelesssessionTTL: la duración máxima de la sesiónproxyCountry: el país del proxy solicitado
Mantener la construcción de URL en una función también facilita aplicar los mismos ajustes de conexión en múltiples scripts de captura.
Paso 3 — Capturar la Sesión del Navegador
La configuración record_har_path de Playwright pertenece a browser.new_context(), no a connect_over_cdp().
La conexión del navegador proporciona acceso a Chromium. El contexto define qué se grabará.
python
import os
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright
API_KEY = os.environ["SCRAPELESS_API_KEY"]
HAR_PATH = "session.har"
def scraping_browser_url(proxy_country="US", session_ttl=180):
params = urlencode({
"token": API_KEY,
"sessionTTL": session_ttl,
"proxyCountry": proxy_country,
})
return f"wss://browser.scrapeless.com/api/v2/browser?{params}"
con sync_playwright() como p:
browser = p.chromium.connect_over_cdp(scraping_browser_url())
context = browser.new_context(
record_har_path=HAR_PATH,
record_har_content="embed",
)
page = context.new_page()
page.goto(
"https://quotes.toscrape.com/scroll",
wait_until="networkidle",
)
for _ in range(3):
page.evaluate(
"window.scrollTo(0, document.body.scrollHeight)"
)
page.wait_for_timeout(800)
print(
"elementos de cita visibles después de desplazarse:",
page.locator(".quote").count(),
)
context.close()
browser.close()
print(
"HAR escrito:",
HAR_PATH,
"-",
os.path.getsize(HAR_PATH),
"bytes",
)
La ejecución en vivo imprimió:
text
elementos de cita visibles después de desplazarse: 40
HAR escrito: session.har - 333269 bytes
El objetivo inicialmente renderizó diez citas. Cada desplazamiento cerca de la parte inferior desencadenó otra solicitud /api/quotes?page=N, llevando el total visible a 40 citas a través de cuatro páginas de API.
El script no necesitó predecir qué solicitud importaría más tarde. El HAR también capturó el documento, hojas de estilo, JavaScript, fuente y llamadas JSON.
Obtén tu clave API en el plan gratuito: app.scrapeless.com
Por qué se requiere context.close()
El HAR se finaliza cuando se cierra el contexto del navegador.
Playwright documenta record_har_path como una configuración del contexto del navegador y requiere browser_context.close() para que el HAR se guarde. Cerrar solo la conexión del navegador puede dejar artefactos del contexto sin un almacenamiento adecuado.
El orden de apagado correcto es:
python
context.close()
browser.close()
La llamada a context.close() es, por lo tanto, parte del procedimiento de captura, no una limpieza opcional.
record_har_content="embed" almacena el contenido de respuesta grabado dentro del HAR en lugar de en archivos compañeros separados. Esto hace que session.har sea autónomo para la posterior inspección de JSON y comparación de cuerpos.
El borrador del formato HAR histórico define el objeto log de nivel superior y su matriz entries requerida. Cada entrada representa una solicitud HTTP exportada.
Paso 4 — Inspeccionar el HAR sin un navegador
Después de que se cierra el contexto, session.har es un documento JSON local.
El siguiente script utiliza solo json, collections y pathlib:
python
import json
from collections import Counter
from pathlib import Path
har = json.loads(Path("session.har").read_text())
entries = har["log"]["entries"]
print("total de entradas:", len(entries))
by_type = Counter(
entry["response"]["content"]["mimeType"].split(";")[0]
for entry in entries
)
for mime_type, count in by_type.most_common():
print(f" {mime_type}: {count}")
print()
for entry in entries:
request = entry["request"]
response = entry["response"]
print(
f"{request['method']:4s} "
f"{response['status']:3d} "
f"{request['url']}"
)
El archivo capturado contenía:
text
total de entradas: 10
application/json: 4
text/css: 3
text/html: 1
application/javascript: 1
font/woff2: 1
GET 200 https://quotes.toscrape.com/scroll
GET 200 https://quotes.toscrape.com/static/bootstrap.min.css
GET 200 https://quotes.toscrape.com/static/main.css
GET 200 https://quotes.toscrape.com/static/jquery.js
GET 200 https://fonts.googleapis.com/css?family=Raleway:400,700
GET 200 https://fonts.gstatic.com/s/raleway/v37/1Ptug8zYS_SKggPNyC0ITw.woff2
GET 200 https://quotes.toscrape.com/api/quotes?page=1
GET 200 https://quotes.toscrape.com/api/quotes?page=2
GET 200 https://quotes.toscrape.com/api/quotes?page=3
GET 200 https://quotes.toscrape.com/api/quotes?page=4
Las diez entradas cubren cinco tipos MIME:
- Un documento HTML
- Tres respuestas CSS
- Una respuesta JavaScript
- Una fuente web
- Cuatro respuestas JSON
Un oyente en vivo filtrado a /api/quotes habría observado las cuatro solicitudes JSON pero ignorado los otros seis recursos. El HAR preservó los diez para su posterior inspección.
Entendiendo la estructura de entradas del HAR
Cada elemento en har["log"]["entries"] contiene objetos de solicitud y respuesta anidados.
Una entrada simplificada tiene esta forma:
json
{
"request": {
"method": "GET",
"url": "https://example.com/api/data",
"headers": []
},
"response": {
"status": 200,
"headers": [],
"content": {
"mimeType": "application/json",
"text": "{}"
}
}
}
Los campos de solicitud útiles incluyen:
methodurlheadersqueryStringpostData
Los campos de respuesta útiles incluyen:
statusstatusTextheaderscontentredirectURL
El contenido HAR no está garantizado que se almacene como texto legiblemente directo en cada entrada. Dependiendo del recurso y del grabador,content.textpuede estar ausente, ser texto decodificado o una representación codificada cuyo campoencodingidentifica el formato.
Paso 5 — Manejar los Pseudo-Encabezados de HTTP/2
Los encabezados de solicitud para la llamada API capturada page=1 incluyeron nombres como:
text
:authority
:method
:path
:scheme
Estos son campos de pseudo-encabezado HTTP/2.
Transportan información de control que aparecería en una línea de solicitud HTTP/1.1 o objetivo:
:methodidentifica el método de solicitud.:schemeidentifica el esquema de URI.:authorityidentifica la autoridad objetivo.:pathidentifica la ruta y la consulta.
Los pseudo-encabezados no son campos de encabezado HTTP ordinarios. Un cliente orientado a HTTP/1.1 como urllib no puede aceptar un nombre de encabezado con prefijo de dos puntos.
Un script de reproducción debe traducir su significado en la URL y el método, y luego omitirlos del mapeo de encabezados ordinarios.
Paso 6 — Reemitir Una Solicitud Capturada Con urllib
La solicitud seleccionada /api/quotes?page=1 es ahora un diccionario dentro de un archivo JSON local.
El script a continuación:
- Encuentra la entrada capturada.
- Lee su método, URL y encabezados.
- Elimina los pseudo-encabezados HTTP/2.
- Elimina
accept-encoding. - Crea una nueva
urllib.request.Request. - Analiza los cuerpos de respuesta en vivo y capturados.
- Compara los dos objetos de Python.
python
import json
import urllib.error
import urllib.request
from pathlib import Path
har = json.loads(Path("session.har").read_text())
entries = har["log"]["entries"]
target = next(
entry
for entry in entries
if entry["request"]["url"].endswith("page=1")
)
captured_request = target["request"]
# Los pseudo-encabezados HTTP/2 describen el encuadre del protocolo y no pueden ser
# pasados como encabezados ordinarios de estilo HTTP/1.1.
#
# accept-encoding también se omite para que urllib pueda negociar una
# codificación que el script pueda decodificar directamente.
skip_headers = {"accept-encoding"}
headers = {
header["name"]: header["value"]
for header in captured_request["headers"]
if not header["name"].startswith(":")
and header["name"].lower() not in skip_headers
}
print("cuenta de encabezados reproducidos:", len(headers))
request = urllib.request.Request(
captured_request["url"],
headers=headers,
method=captured_request["method"],
)
with urllib.request.urlopen(request, timeout=10) as response:
if response.status != 200:
raise urllib.error.HTTPError(
captured_request["url"],
response.status,
"estado inesperado",
response.headers,
None,
)
live_data = json.loads(response.read())
captured_content = target["response"]["content"]
captured_data = json.loads(captured_content["text"])
print("estado:", response.status, "-- sin proceso de navegador en ejecución")
print(
"primer autor de la cita:",
live_data["quotes"][0]["author"]["name"],
)
print(
"coincide con el cuerpo de respuesta que el HAR ya capturó:",
live_data == captured_data,
)
La reproducción sin navegador imprimiò:
text
cuenta de encabezados reproducidos: 12
estado: 200 -- sin proceso de navegador en ejecución
primer autor de la cita: Albert Einstein
coincide con el cuerpo de respuesta que el HAR ya capturó: True
El mapeo filtrado contenía 12 encabezados ordinarios. Los pseudo-encabezados HTTP/2 y accept-encoding fueron excluidos.
accept-encoding es un campo de negociación de contenido HTTP. El cliente que reproduce puede anunciar las codificaciones de contenido que admite en lugar de copiar ciegamente la negociación Brotli del navegador.
La respuesta objetivo coincidió con el cuerpo JSON almacenado en el HAR para esta ejecución. Esa comparación se realizó en los objetos de Python analizados en lugar de en su espacio en blanco o formato de clave serializado.
Esta es una reconstrucción semántica de la solicitud, no una reproducción byte por byte del intercambio de red original. La nueva solicitud puede usar una versión diferente de HTTP, orden de encabezados, negociación de compresión, conexión y sesión TLS.
Lo Que Obtienes de Vuelta
El flujo de trabajo produce tres artefactos o resultados reutilizables:
| Etapa | Salida | ¿Se requiere navegador? |
|---|---|---|
| Captura | session.har |
Sí |
| Inspección | Inventario de solicitudes y resumen de tipo MIME | No |
| Reemisión | Comparación de respuesta en vivo analizada y cuerpo capturado | No |
La sesión capturada produjo:
text
tamaño HAR: 333269 bytes
entradas HTTP: 10
entradas JSON: 4
Citas visibles después de desplazarse: 40
estado de la solicitud reemitida: 200
coincidencia JSON capturada/viva: True
Estos números describen esta sesión objetivo específica. Una página diferente, versión de navegador, temporización de desplazamiento, ubicación de proxy o respuesta de página pueden producir un conjunto de solicitudes y tamaño de archivo diferentes.
Confirma la Secuencia Completa en Un Solo Script
La captura, inspección y programas de reproducción separados son más fáciles de entender, pero las mismas etapas se pueden combinar:
python
import json
import os
import urllib.error
import urllib.request
from collections import Counter
from pathlib import Path
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright
API_KEY = os.environ["SCRAPELESS_API_KEY"]
HAR_PATH = "session.har"
def scraping_browser_url(proxy_country="US", session_ttl=180):
params = urlencode({
"token": API_KEY,
"sessionTTL": session_ttl,
"proxyCountry": proxy_country,
})
return f"wss://browser.scrapeless.com/api/v2/browser?{params}"
# Etapa 1: captura. Se requiere un navegador.
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(
scraping_browser_url()
)
context = browser.new_context(
record_har_path=HAR_PATH,
record_har_content="embed",
)
page = context.new_page()
page.goto(
"https://quotes.toscrape.com/scroll",
wait_until="networkidle",
)
for _ in range(3):
page.evaluate(
"window.scrollTo(0, document.body.scrollHeight)"
)
page.wait_for_timeout(800)
context.close()
browser.close()
print("=== captura ===")
print(
"HAR escrito:",
HAR_PATH,
"-",
os.path.getsize(HAR_PATH),
"bytes",
)
# Etapa 2: inspección. El navegador está cerrado.
har = json.loads(Path(HAR_PATH).read_text())
entries = har["log"]["entries"]
print("\n=== inspección (sin navegador) ===")
print("total de entradas:", len(entries))
by_type = Counter(
entry["response"]["content"]["mimeType"].split(";")[0]
for entry in entries
)
for mime_type, count in by_type.most_common():
print(f" {mime_type}: {count}")
# Etapa 3: volver a emitir una solicitud. El navegador permanece cerrado.
target = next(
entry
for entry in entries
if entry["request"]["url"].endswith("page=1")
)
captured_request = target["request"]
skip_headers = {"accept-encoding"}
headers = {
header["name"]: header["value"]
for header in captured_request["headers"]
if not header["name"].startswith(":")
and header["name"].lower() not in skip_headers
}
request = urllib.request.Request(
captured_request["url"],
headers=headers,
method=captured_request["method"],
)
with urllib.request.urlopen(request, timeout=10) as response:
if response.status != 200:
raise urllib.error.HTTPError(
captured_request["url"],
response.status,
"estado inesperado",
response.headers,
None,
)
live_data = json.loads(response.read())
captured_data = json.loads(
target["response"]["content"]["text"]
)
print("\n=== volver a emitir (sin navegador) ===")
print("estado:", response.status)
print(
"autor de la primera cita:",
live_data["quotes"][0]["author"]["name"],
)
print(
"coincide con el cuerpo capturado:",
live_data == captured_data,
)
La ejecución combinada imprimió:
text
=== captura ===
HAR escrito: session.har - 333259 bytes
=== inspección (sin navegador) ===
total de entradas: 10
application/json: 4
text/css: 3
text/html: 1
application/javascript: 1
font/woff2: 1
=== volver a emitir (sin navegador) ===
estado: 200
autor de la primera cita: Albert Einstein
coincide con el cuerpo capturado: True
Solo la primera etapa importa y utiliza Playwright. Las etapas posteriores operan en el archivo y el punto final HTTP en vivo seleccionado.
Lo que un HAR captura
Un archivo HAR representa transacciones HTTP grabadas por el contexto del navegador.
Dependiendo del grabador y la configuración, una entrada puede contener:
- Método de solicitud y URL
- Parámetros de cadena de consulta
- Encabezados de solicitud
- Cookies de solicitud
- Datos publicados
- Estado de respuesta
- Encabezados de respuesta
- Cookies de respuesta
- Tipo MIME
- Contenido de respuesta
- Tamaños de transferencia
- Información de tiempo
- Detalles de redirección
- Información de caché
Con record_har_content="embed", Playwright almacena el contenido de respuesta disponible dentro del HAR. Sin contenido integrado, el inventario de solicitudes aún puede ser útil, pero el archivo puede no contener el cuerpo de respuesta necesario para el análisis o comparación sin conexión.
Lo que un HAR no garantiza
Un archivo HAR es un registro duradero de la actividad HTTP capturada, pero no es un registro completo de cada comportamiento del navegador.
Los marcos de WebSocket no se archivan
HAR modela transacciones de solicitud y respuesta. No preserva la secuencia de mensajes transportados dentro de una conexión WebSocket establecida.
Una página que combina puntos finales HTTP normales con un flujo en vivo de WebSocket necesita mecanismos de captura separados:
- HAR para tráfico de solicitudes y respuestas HTTP
- Escuchadores de marcos de WebSocket para mensajes de socket
La conexión inicial puede involucrar una actualización HTTP, pero el flujo de marcos en curso está fuera del modelo normal de solicitud-respuesta de HAR.
Un HAR no es una instantánea del DOM
El archivo no preserva el árbol del documento final de la misma manera que lo haría una instantánea del DOM.
Un cuerpo de respuesta puede contener el HTML o JSON original, pero las mutaciones de JavaScript posteriores, el estado de los elementos, el diseño renderizado y la apariencia visible para el usuario son preocupaciones separadas.
Un HAR No Es Un Video
El archivo de registro no contiene una línea de tiempo visual de lo que apareció en la página.
Utiliza la grabación de sesión de Scrapeless cuando el objetivo es revisar el comportamiento visible del navegador. Utiliza la captura de HAR cuando el objetivo es inspeccionar el tráfico HTTP estructurado.
Puede Faltar Contenido o Estar Codificado
HAR admite campos de contenido opcionales. Un grabador puede omitir cuerpos, y los recursos binarios pueden estar codificados.
Antes de analizar response.content.text, verifica que:
- El campo
textexiste. - Se espera el tipo de contenido.
- Se maneja el campo
encodingsi está presente. - El cuerpo no ha sido omitido por la configuración de grabación.
Cuándo Funciona la Reemisión Sin Navegador
Una solicitud capturada puede reemitirse con éxito cuando el servidor en vivo aún acepta la solicitud reconstruida.
El punto final público /api/quotes funciona porque no depende de una sesión autenticada que esté por expirar.
La reemisión se complica más cuando la solicitud original utiliza:
- Cookies de sesión
- Tokens CSRF
- Credenciales de portador de corta duración
- URLs firmadas
- Firmas de solicitud por sesión
- Estado almacenado solo dentro del navegador
- Datos generados por un paso de navegación anterior
- Un cuerpo de solicitud cuyo contenido cambia por sesión
El HAR puede preservar los valores de credenciales originales, pero no puede extender su validez. Una vez que esos valores expiran, se puede requerir una nueva sesión de navegador para crear un nuevo estado.
Reproducir Datos de HAR de Forma Segura
Un archivo HAR puede contener datos de sesión sensibles.
Los encabezados de solicitud y respuesta pueden exponer:
- Cookies
- Encabezados de autorización
- Claves de API
- Identificadores de sesión
- URLs internas
- Datos personales devueltos por un punto final
Trata los archivos HAR como artefactos sensibles:
- No los comprometas en un repositorio público.
- Elimina credenciales antes de compartirlas.
- Restringe el acceso a sesiones de producción archivadas.
- Evita registrar encabezados completos innecesariamente.
- Almacena solo las capturas necesarias para la tarea de depuración o auditoría.
- Elimina archivos según los requisitos de retención del proyecto.
El archivo de registro en este tutorial proviene de una página de demostración pública y no autenticada. Las mismas suposiciones no deben aplicarse automáticamente a las aplicaciones autenticadas.
Problemas Comunes
El Archivo HAR No Aparece
La causa más común es cerrar el navegador sin cerrar explícitamente el contexto.
Usa:
python
context.close()
browser.close()
También confirma que el proceso puede escribir en el directorio que contiene HAR_PATH.
El HAR No Contiene Cuerpo de Respuesta
Confirma que el contexto utiliza:
python
record_har_content="embed"
Luego inspecciona si entry["response"]["content"]["text"] existe. Algunos recursos pueden omitirse o representarse con una codificación.
urllib Rechaza Un Nombre de Encabezado
Elimina cualquier encabezado cuyo nombre comience con :. Estos son encabezados pseudo-HTTP/2, no campos de encabezado ordinarios.
La URL y el método de solicitud ya llevan su significado relevante.
La Respuesta Reemitida Está Comprimida Inesperadamente
No copies el valor accept-encoding de un navegador sin pensar a menos que el cliente de reproducción soporte cada codificación de contenido anunciada.
Deja que el cliente HTTP negocie una codificación que pueda decodificar.
La Nueva Respuesta No Coincide con el HAR
Un desajuste no significa necesariamente que el código de reconstrucción sea incorrecto.
El servidor puede devolver contenido cambiante, marcas de tiempo, campos aleatorios, resultados específicos de geolocalización o datos ligados a credenciales que ya no son válidas.
Compara los campos que se espera que permanezcan estables en lugar de asumir que cada punto final siempre devuelve bytes idénticos.
Conclusión
El record_har_path de Playwright convierte un contexto de navegador en un archivo de registro HTTP duradero.
El flujo de trabajo tiene tres fases claras:
- Conectar Playwright a Scrapeless Scraping Browser y capturar la sesión de la página.
- Cerrar el navegador e inspeccionar
log.entriescomo un JSON ordinario. - Reconstruir una solicitud elegible con
urlliby comparar su respuesta en vivo con el cuerpo capturado.
El navegador solo se requiere para producir el archivo de registro. Una vez que context.close() vacía el HAR, el archivo puede ser analizado en una máquina sin instalación de Playwright, proceso de navegador o conexión CDP.
Esa separación hace que la captura de HAR sea útil para la depuración posterior a la sesión, descubrimiento interno de API, auditoría de red y reconstrucción de solicitudes. También mantiene visibles las limitaciones: HAR no preserva tramas de WebSocket, estado visual renderizado, ni la validez futura de las credenciales capturadas.
Revisar la página del producto Scraping Browser para conocer las capacidades de la sesión del navegador detrás del flujo de trabajo de captura, y consultar los planes de precios de Scrapeless al pasar de una sesión de demostración a una carga de trabajo de captura más grande.
El explicador del Protocolo de Chrome DevTools cubre la superficie del protocolo debajo de la conexión del navegador.
¿Listo para archivar una sesión real de navegador?
Únete a la comunidad de Scrapeless para comparar patrones de captura de Playwright y flujos de trabajo de depuración de navegadores con otros desarrolladores: Discord · Telegram.
Regístrate en app.scrapeless.com para obtener la ejecución gratuita de Scraping Browser y luego adapta los pasos de captura, inspección y reconstrucción de solicitudes a una página pública relevante para tu proyecto.
FAQ
P: ¿Qué es un archivo HAR?
Un archivo HAR es un archivo JSON de archivos de transacciones HTTP capturados durante una sesión del navegador. Su matriz log.entries contiene un objeto por cada solicitud grabada, con información anidada de solicitud, respuesta, temporización y contenido.
Un archivo HAR no es una captura de pantalla, un video de página, ni una instantánea completa del DOM.
P: ¿En qué se diferencia la captura HAR de la interceptación de solicitudes en vivo?
La captura HAR registra el tráfico HTTP del contexto del navegador de manera amplia, mientras que la interceptación en vivo observa las solicitudes coincidentes a medida que ocurren.
La interceptación en vivo es útil cuando el punto final ya es conocido. La captura HAR es útil cuando la solicitud importante puede descubrirse solo después de que la sesión ha terminado.
P: ¿Necesitas un navegador para leer un archivo HAR?
No. Un archivo HAR completado es un documento JSON ordinario que puede leerse con el módulo json de Python.
El navegador es necesario durante la captura, pero no durante la inspección fuera de línea.
P: ¿Incluye la captura HAR tráfico de WebSocket?
La captura HAR no archiva los mensajes intercambiados dentro de una conexión de WebSocket establecida.
Usa un listener de frames de WebSocket cuando la página dependa de un feed de socket en vivo. HAR aún puede cubrir el tráfico HTTP ordinario utilizado por la misma página.
P: ¿La grabación HAR de Playwright es lo mismo que la grabación de sesión de Scrapeless?
No. La grabación HAR de Playwright crea un archivo de red estructurado, mientras que la grabación de sesión de Scrapeless crea una reproducción visual de la sesión del navegador renderizada.
Usa HAR para el análisis de solicitudes y respuestas. Usa la grabación de sesión cuando el comportamiento visible de la página sea el objeto de la investigación.
P: ¿Es el ejemplo de urllib lo mismo que route_from_har() de Playwright?
No. route_from_har() sirve respuestas grabadas a solicitudes realizadas dentro de un contexto de navegador Playwright en vivo.
El ejemplo de urllib lee una solicitud del HAR y envía una nueva solicitud al servidor en vivo sin iniciar un navegador.
P: ¿Por qué un HAR contiene encabezados como :authority y :method?
Esos nombres son campos de pseudo-encabezado HTTP/2 utilizados para transportar datos de control de solicitudes dentro del protocolo HTTP/2.
No son campos de encabezado ordinarios, por lo que un cliente de estilo HTTP/1.1 debe representar su significado a través del método de solicitud y la URL en lugar de copiar los nombres con prefijo de dos puntos.
P: ¿Se puede volver a emitir cada solicitud capturada con éxito?
No. Una solicitud solo puede volver a emitirse mientras el servidor en vivo acepte el método, URL, cuerpo, encabezados y credenciales reconstruidos.
Las solicitudes que dependen de cookies expiradas, tokens CSRF, URLs firmadas o credenciales de portador de corta duración pueden requerir una nueva sesión de navegador.
P: ¿Necesitas un proxy separado para este flujo de trabajo?
No se requiere configuración de proxy separado cuando la conexión del Scraping Browser de Scrapeless ya especifica el país del proxy deseado.
El ejemplo establece proxyCountry=US en la URL de conexión de CDP, por lo que la sesión del navegador utiliza esa salida configurada.
P: ¿Es seguro compartir un archivo HAR?
Un archivo HAR debe considerarse sensible hasta que su contenido haya sido revisado y desinfectado.
Puede contener cookies, encabezados de autorización, claves API, endpoints internos, datos de formularios enviados o contenido de respuesta privado. Elimina valores sensibles antes de compartir o comprometer el archivo.
P: ¿La grabación HAR solo funciona con Scrapeless Scraping Browser?
No. record_har_path es una opción de contexto de navegador de Playwright y se puede utilizar con navegadores locales o remotos compatibles.
Scrapeless Scraping Browser proporciona el entorno remoto de Chromium gestionado y la configuración de proxy utilizados durante la etapa de captura.
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.



