Cómo extraer localStorage con Playwright y Scrapeless
Expert in Web Scraping Technologies
Un navegador puede mantener un estado de página útil fuera del DOM. Esta guía utiliza Playwright para inspeccionar localStorage en una demostración pública de MDN, cambiar tres preferencias reales a través de la interfaz de usuario, capturar los eventos de almacenamiento resultantes en una segunda pestaña y demostrar que los valores sobreviven a una recarga antes de mover la misma lógica al Scrapeless Scraping Browser.
Lo que el Almacenamiento Web Agrega a un Flujo de Trabajo de Extracción
La API de Almacenamiento Web otorga a un origen dos almacenes con claves de cadena:
localStoragees compartido por documentos del mismo origen y sobrevive a las recargas de página ordinarias y reinicios del navegador cuando el perfil es persistente.sessionStorageestá limitado a un contexto de navegación de nivel superior y dura solo durante esa sesión de página.
Ninguno de los almacenes es un tarro de cookies. Los valores de Almacenamiento Web no se adjuntan automáticamente a las solicitudes HTTP, y cada clave/valor es una cadena. La guía de la API de Almacenamiento Web de MDN define esos límites de alcance y persistencia.
Para la extracción, el almacenamiento puede contener preferencias de la interfaz de usuario, identificadores en caché, estado de características o datos públicos que la aplicación ya ha cargado. Trátalo como un estado del navegador para validar, no como una razón para recopilar tokens de autenticación o datos privados de usuario.
Por Qué Usar Playwright Con Scrapeless
Playwright puede evaluar JavaScript en el origen de la página, abrir dos páginas en el mismo BrowserContext y observar el propio evento de almacenamiento del navegador. El Scrapeless Scraping Browser proporciona una sesión de Chromium alojada mientras mantiene esas API de Playwright.
La conexión del navegador utiliza connect_over_cdp. Una vez que existe una página, la inspección del almacenamiento es la misma ya sea que Chromium esté local o alojado.
Requisitos Previos
- Python 3.10 o posterior.
playwright1.59.0 o una versión compatible actual.- Chrome/Chromium local para el ejemplo ejecutable completo.
- Una cuenta de Scrapeless con fondos y
SCRAPELESS_API_KEYpara la conexión a la nube. Nuevas sesiones del navegador en la cuenta de verificación devolvieron el código 14500, por lo que el bloque de conexión es una brecha explícita en los requisitos previos.
Instalar
bash
python -m pip install "playwright==1.59.0"
Conectar al Scrapeless Scraping Browser
Nota: Este bloque requiere un saldo de Scraping Browser con fondos. La cuenta de verificación final devolvió
saldo insuficiente, por favor recargue primero. Ejecuta con tu propio código financiado; el flujo de trabajo de almacenamiento completo a continuación se ejecutó en Chrome local contra la misma página pública.
python
import os
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright
params = urlencode({
"token": os.environ["SCRAPELESS_API_KEY"],
"sessionTTL": 120,
"proxyCountry": "US",
})
cdp_url = f"wss://browser.scrapeless.com/api/v2/browser?{params}"
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(cdp_url)
context = browser.contexts[0]
page = context.pages[0]
# Ejecuta los pasos de almacenamiento a continuación con el contexto y la página.
browser.close()
Utiliza la documentación del desarrollador de Scrapeless para obtener los parámetros de conexión actuales.
Inspeccionar Cada Clave de localStorage
La demostración pública de MDN almacena un color de fondo, una fuente y una elección de imagen:
python
TARGET_URL = "https://mdn.github.io/dom-examples/web-storage/"
page.goto(TARGET_URL, wait_until="domcontentloaded")
stored = page.evaluate(
"Object.fromEntries(Object.entries(localStorage))"
)
print("almacenamiento inicial:", stored)
print("almacenamiento de sesión:", page.evaluate("sessionStorage.length"))
text
almacenamiento inicial: {'font': 'sans-serif', 'image': 'images/firefoxos.png', 'bgcolor': 'FF0000'}
almacenamiento de sesión: 0
Leer todas las entradas evita atar el extractor a una sola clave. Mantén el origen en la salida porque el mismo nombre de clave puede significar algo diferente en otro sitio.
Capturar Cambios en una Segunda Pestaña
El event de storage se activa en otros documentos del mismo origen que comparten el almacén modificado. No se activa en la pestaña que realizó el cambio.
python
observer_page = context.new_page()
observer_page.goto(TARGET_URL, wait_until="domcontentloaded")
observer_page.evaluate("""
window.capturedStorageEvents = [];
addEventListener('storage', event => {
capturedStorageEvents.push({
key: event.key,
oldValue: event.oldValue,
newValue: event.newValue,
});
});
""")
Ambas páginas deben compartir un contexto de navegador y un origen. Un segundo contexto tiene almacenamiento separado y no recibirá estos eventos.
Cambiar Controles Reales de la Interfaz de Usuario
Cambia los controles de la demostración en lugar de escribir las claves directamente:
python
page.evaluate("""
bgcolor.value = '00FF00';
bgcolor.dispatchEvent(new Event('change', {bubbles: true}));
""")
page.select_option("#font", "serif")
page.select_option("#image", "images/crocodile.png")
page.wait_for_timeout(500)
print("almacenamiento actualizado:", page.evaluate(
"Object.fromEntries(Object.entries(localStorage))"
))
print("eventos:", observer_page.evaluate("capturedStorageEvents"))
text
almacenamiento actualizado: {'font': 'serif', 'image': 'images/crocodile.png', 'bgcolor': '00FF00'}
eventos: [{'key': 'bgcolor', 'oldValue': 'FF0000', 'newValue': '00FF00'}, {'key': 'font', 'oldValue': 'sans-serif', 'newValue': 'serif'}, {'key': 'image', 'oldValue': 'images/firefoxos.png', 'newValue': 'images/crocodile.png'}]
Ese resultado prueba tres cosas a la vez: la interfaz de usuario escribió en el almacenamiento, la segunda pestaña recibió exactamente tres cambios y cada evento conservó su valor anterior.
¿Listo para inspeccionar el estado en una sesión alojada? Crea una cuenta gratuita en Scrapeless y reemplaza solo la creación del navegador.
Demuestra que los valores sobreviven a la recarga
python
page.reload(wait_until="domcontentloaded")
reloaded = page.evaluate(
"Object.fromEntries(Object.entries(localStorage))"
)
controls = {
"bgcolor": page.locator("#bgcolor").input_value(),
"font": page.locator("#font").input_value(),
"image": page.locator("#image").input_value(),
}
print("almacenamiento recargado:", reloaded)
print("valores de control:", controls)
text
almacenamiento recargado: {'font': 'serif', 'image': 'images/crocodile.png', 'bgcolor': '00FF00'}
valores de control: {'bgcolor': '00FF00', 'font': 'serif', 'image': 'images/crocodile.png'}
Alinear los controles visibles con el estado almacenado es más fuerte que verificar solo el almacenamiento. Prueba que la aplicación consumió los valores guardados después de la navegación.
Script completo ejecutable
python
from playwright.sync_api import sync_playwright
TARGET_URL = "https://mdn.github.io/dom-examples/web-storage/"
with sync_playwright() as p:
browser = p.chromium.launch(
executable_path="/usr/bin/google-chrome",
headless=True,
)
context = browser.new_context()
page = context.new_page()
observer_page = context.new_page()
observer_page.goto(TARGET_URL, wait_until="domcontentloaded")
observer_page.evaluate("""
window.capturedStorageEvents = [];
addEventListener('storage', event => {
capturedStorageEvents.push({
key: event.key,
oldValue: event.oldValue,
newValue: event.newValue,
});
});
""")
page.goto(TARGET_URL, wait_until="domcontentloaded")
initial = page.evaluate(
"Object.fromEntries(Object.entries(localStorage))"
)
page.evaluate("""
bgcolor.value = '00FF00';
bgcolor.dispatchEvent(new Event('change', {bubbles: true}));
""")
page.select_option("#font", "serif")
page.select_option("#image", "images/crocodile.png")
page.wait_for_timeout(500)
updated = page.evaluate(
"Object.fromEntries(Object.entries(localStorage))"
)
events = observer_page.evaluate("capturedStorageEvents")
page.reload(wait_until="domcontentloaded")
reloaded = page.evaluate(
"Object.fromEntries(Object.entries(localStorage))"
)
controls = {
"bgcolor": page.locator("#bgcolor").input_value(),
"font": page.locator("#font").input_value(),
"image": page.locator("#image").input_value(),
}
assert len(events) == 3
assert updated == reloaded == controls
assert page.evaluate("sessionStorage.length") == 0
print("título:", page.title())
print("almacenamiento inicial:", initial)
print("almacenamiento actualizado:", updated)
print("claves de eventos:", [event["key"] for event in events])
print("conteo de eventos:", len(events))
print("almacenamiento recargado:", reloaded)
print("valores de control:", controls)
print("entradas de almacenamiento de sesión:", page.evaluate("sessionStorage.length"))
browser.close()
La ejecución devuelve tres claves iniciales, tres claves actualizadas, tres eventos entre pestañas, controles recargados coincidentes y cero entradas de sessionStorage.
localStorage, sessionStorage y Cookies
localStorage
Compartido por documentos de la misma origen, solo se pueden almacenar cadenas y persiste hasta que se borre. Úsalo cuando la aplicación deliberadamente mantenga el estado entre visitas.
sessionStorage
Separado para cada sesión de página de nivel superior. Duplicar o abrir una pestaña puede crear un ciclo de vida distinto incluso en la misma origen. Inspecciónalo desde la misma página cuya estado es importante.
Cookies
Enviadas con solicitudes HTTP coincidentes de acuerdo con las reglas de cookies. Usa las API de cookies del contexto de Playwright en lugar de confundirlas con Web Storage.
Límites de extracción seguros
El almacenamiento puede contener credenciales, identificadores de usuario o estado privado. Restringe los ejemplos a páginas de demostración públicas, recopila solo los campos necesarios para la tarea indicada y nunca publiques tokens o material de sesión. El acceso de origen a través de un navegador no otorga permiso para reutilizar cada valor que puedas leer.
Conclusión
La extracción de almacenamiento web es útil cuando el navegador tiene un estado que el DOM visible por sí solo no puede explicar. Lee el mapa completo, mantén el origen con el registro, observa los cambios entre pestañas cuando necesites el origen y verifica que la aplicación consuma los valores almacenados después de la navegación. Mover el flujo de trabajo a Scrapeless cambia la conexión del navegador, no la lógica de almacenamiento.
Comienza con Scrapeless, revisa los precios de Scrapeless, y lee lo que expone CDP antes de mover sesiones con estado a la nube.
FAQ
P: ¿Puede Playwright leer localStorage?
Sí. Evalúa Object.fromEntries(Object.entries(localStorage)) dentro de una página en el origen objetivo.
P: ¿Por qué no usar context.storage_state() para todo?
El estado del almacenamiento es útil para exportar el estado de autenticación admitido, pero la evaluación directa de la página te permite inspeccionar el mapa de claves en vivo y correlacionarlo con los cambios de UI y eventos de almacenamiento.
P: ¿Sobrevive localStorage a una recarga?
Sí, a menos que la aplicación o el navegador lo borren. Los tres valores cambiados de la demostración de MDN sobrevivieron a la recarga probada y repoblaron los controles.
P: ¿La pestaña que cambia localStorage recibe un evento de almacenamiento?
No. El evento se entrega a otros documentos de mismo origen que comparten la tienda, por eso el ejemplo escucha en una segunda página.
P: ¿sessionStorage se comparte entre pestañas?
No. Está limitado a un contexto de navegación de nivel superior y sus contextos secundarios de mismo origen, así que inspeciónalo desde la sesión de página específica.
P: ¿Los valores de Web Storage siempre son JSON?
No. Cada valor se almacena como una cadena. Analiza JSON solo cuando se confirme el formato de la aplicación y maneja JSON no válido de manera explícita.
P: ¿Es seguro raspar el almacenamiento del navegador?
Solo dentro de los permisos del objetivo y tus obligaciones de manejo de datos. Evita credenciales y estado privado del usuario, mantén la colección limitada y revisa los términos del sitio y la política de robots donde sea aplicable.
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.



