Playwright: Web Scraping & Testing
Domine la automatización del navegador para pruebas y raspado web
Playwright es un poderoso marco moderno de automatización del navegador que revoluciona el raspado web y las pruebas de extremo a extremo.
Desarrollado por Microsoft, proporciona una API unificada para automatizar los navegadores Chromium, Firefox y WebKit con una fiabilidad y velocidad sin precedentes.

¿Qué es Playwright?
Playwright es un marco de automatización del navegador de código abierto que permite a los desarrolladores escribir pruebas de extremo a extremo confiables y construir soluciones avanzadas de raspado web. A diferencia de las herramientas de automatización tradicionales, Playwright fue construido desde cero para manejar aplicaciones web modernas con contenido dinámico, aplicaciones de una sola página (SPA) y marcos complejos de JavaScript.
El marco aborda el problema central que afectaba a las herramientas de automatización anteriores: la fragilidad. Playwright introduce mecanismos de espera automática que esperan automáticamente a que los elementos sean accionables antes de realizar operaciones, eliminando la necesidad de tiempos de espera arbitrarios y declaraciones de sueño que hacían que las pruebas fueran poco confiables.
Características clave
Compatibilidad multi-navegador: Playwright soporta todos los motores de navegador principales: Chromium (incluyendo Chrome y Edge), Firefox y WebKit (Safari). Esto significa que puedes escribir tu script de automatización una vez y ejecutarlo en diferentes navegadores sin modificaciones, asegurando que tus aplicaciones web funcionen de manera consistente en todas partes.
Espera automática: Una de las características más poderosas de Playwright es su mecanismo de espera automática integrado. Antes de realizar cualquier acción, Playwright espera automáticamente a que los elementos sean visibles, habilitados, estables y no obstruidos. Esto elimina las condiciones de carrera y hace que las pruebas sean mucho más confiables en comparación con herramientas como Selenium donde a menudo se requieren esperas explícitas.
Intercepción de red: Playwright permite interceptar, modificar y simular solicitudes y respuestas de red. Esto es invaluable para probar casos límite, simular redes lentas, bloquear recursos innecesarios durante el raspado o simular respuestas de API sin necesidad de un backend.
Emulación móvil: Prueba aplicaciones web móviles emulando varios dispositivos móviles con tamaños de viewport específicos, agentes de usuario y eventos táctiles. Playwright incluye descriptores de dispositivos para teléfonos y tabletas populares.
Selectores poderosos: Más allá de los selectores CSS y XPath, Playwright soporta selectores de texto, selectores basados en roles para pruebas de accesibilidad y incluso selectores experimentales para marcos basados en componentes como React y Vue.
Instalación y configuración
Configurar Playwright es sencillo en diferentes lenguajes de programación.
Instalación en Python
Para proyectos de Python, Playwright se puede instalar mediante pip e incluye tanto APIs síncronas como asíncronas. Si estás buscando un gestor de paquetes, proyectos y entornos de Python más rápido y moderno, consulta nuestra guía sobre uv - Gestor de paquetes, proyectos y entornos de Python:
# Instalar paquete Playwright
pip install playwright
# Instalar navegadores (Chromium, Firefox, WebKit)
playwright install
# Solo para un navegador específico
playwright install chromium
Para una referencia completa de la sintaxis de Python y comandos comúnmente utilizados al trabajar con Playwright, consulta nuestro Hoja de trucos de Python.
Instalación en JavaScript/TypeScript
Para proyectos de Node.js, instale Playwright mediante npm o yarn:
# Usando npm
npm init playwright@latest
# Usando yarn
yarn create playwright
# Instalación manual
npm install -D @playwright/test
npx playwright install
El comando npm init playwright proporciona una configuración interactiva que configura tu proyecto con pruebas de ejemplo, archivos de configuración y flujos de trabajo de GitHub Actions.
Configuración básica
Cree un archivo playwright.config.ts (TypeScript) o playwright.config.js (JavaScript):
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
timeout: 30000,
retries: 2,
workers: 4,
use: {
headless: true,
viewport: { width: 1280, height: 720 },
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});
Raspado web con Playwright
Playwright destaca en el raspado web, especialmente para sitios web modernos con contenido dinámico que las bibliotecas tradicionales de raspado tienen dificultades para manejar.
Ejemplo básico de raspado
Aquí hay un ejemplo completo en Python que demuestra conceptos básicos de raspado:
from playwright.sync_api import sync_playwright
import json
def scrape_website():
with sync_playwright() as p:
# Iniciar navegador
browser = p.chromium.launch(headless=True)
# Crear contexto para aislamiento
context = browser.new_context(
viewport={'width': 1920, 'height': 1080},
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
)
# Abrir nueva página
page = context.new_page()
# Navegar a URL
page.goto('https://example.com/products')
# Esperar a que el contenido se cargue
page.wait_for_selector('.product-item')
# Extraer datos
products = page.query_selector_all('.product-item')
data = []
for product in products:
title = product.query_selector('h2').inner_text()
price = product.query_selector('.price').inner_text()
url = product.query_selector('a').get_attribute('href')
data.append({
'title': title,
'price': price,
'url': url
})
# Limpiar
browser.close()
return data
# Ejecutar raspador
results = scrape_website()
print(json.dumps(results, indent=2))
Manejo de contenido dinámico
Los sitios web modernos suelen cargar contenido dinámicamente a través de JavaScript. Playwright maneja esto de forma sencilla:
async def scrape_dynamic_content():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto('https://example.com/infinite-scroll')
# Desplazarse para cargar más contenido
for _ in range(5):
await page.evaluate('window.scrollTo(0, document.body.scrollHeight)')
await page.wait_for_timeout(2000)
# Esperar a que la red esté inactiva
await page.wait_for_load_state('networkidle')
# Extraer todos los elementos cargados
items = await page.query_selector_all('.item')
await browser.close()
Convertir contenido raspado a Markdown
Después de extraer contenido HTML con Playwright, a menudo necesitas convertirlo a un formato más usable. Para guías completas sobre la conversión de HTML a Markdown, consulta nuestros artículos sobre Convertir HTML a Markdown con Python: Una Guía Completa que compara 6 bibliotecas diferentes de Python, y Convertir contenido HTML a Markdown usando LLM y Ollama para la conversión potenciada por IA. Si estás trabajando con documentos de Word en lugar de HTML, consulta nuestra guía sobre Convertir documentos de Word a Markdown.
Autenticación y gestión de sesión
Cuando el raspado requiere autenticación, Playwright facilita guardar y reutilizar el estado del navegador:
def login_and_save_session():
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
# Iniciar sesión
page.goto('https://example.com/login')
page.fill('input[name="username"]', 'your_username')
page.fill('input[name="password"]', 'your_password')
page.click('button[type="submit"]')
# Esperar a la navegación después del inicio de sesión
page.wait_for_url('**/dashboard')
# Guardar el estado autenticado
context.storage_state(path='auth_state.json')
browser.close()
def scrape_with_saved_session():
with sync_playwright() as p:
browser = p.chromium.launch()
# Reutilizar el estado de autenticación guardado
context = browser.new_context(storage_state='auth_state.json')
page = context.new_page()
# Ya autenticado!
page.goto('https://example.com/protected-data')
# ... raspar contenido protegido
browser.close()
Este enfoque es especialmente útil al trabajar con APIs o al construir servidores MCP para integraciones de IA. Para una guía completa sobre la implementación de raspado web en integraciones de herramientas de IA, consulta nuestro artículo sobre Construir servidores MCP en Python: WebSearch & Scrape.
Pruebas de extremo a extremo
El caso de uso principal de Playwright es escribir pruebas robustas de extremo a extremo para aplicaciones web.
Escribir su primera prueba
Aquí hay un ejemplo completo de prueba en TypeScript:
import { test, expect } from '@playwright/test';
test('el usuario puede agregar un artículo al carrito', async ({ page }) => {
// Navegar a la página principal
await page.goto('https://example-shop.com');
// Buscar producto
await page.fill('[data-testid="search-input"]', 'laptop');
await page.press('[data-testid="search-input"]', 'Enter');
// Esperar a que aparezcan los resultados de búsqueda
await expect(page.locator('.product-card')).toBeVisible();
// Hacer clic en el primer producto
await page.locator('.product-card').first().click();
// Verificar que la página del producto se cargue
await expect(page).toHaveURL(/\/product\/.+/);
// Agregar al carrito
await page.click('[data-testid="add-to-cart"]');
// Verificar que el carrito se actualice
const cartCount = page.locator('[data-testid="cart-count"]');
await expect(cartCount).toHaveText('1');
});
Modelo de página
Para conjuntos de pruebas más grandes, utilice el patrón Modelo de Página para mejorar la mantenibilidad:
// pages/LoginPage.ts
export class LoginPage {
constructor(private page: Page) {}
async navigate() {
await this.page.goto('/login');
}
async login(username: string, password: string) {
await this.page.fill('[name="username"]', username);
await this.page.fill('[name="password"]', password);
await this.page.click('button[type="submit"]');
}
async getErrorMessage() {
return await this.page.locator('.error-message').textContent();
}
}
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
test('inicio de sesión con credenciales inválidas muestra error', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.navigate();
await loginPage.login('invalid@email.com', 'wrongpass');
const error = await loginPage.getErrorMessage();
expect(error).toContain('Credenciales inválidas');
});
Funciones avanzadas
Codegen - Generación automática de pruebas
La herramienta Codegen de Playwright genera pruebas registrando tus interacciones con una página web:
# Abrir Codegen
playwright codegen example.com
# Con navegador específico
playwright codegen --browser firefox example.com
# Con estado de autenticación guardado
playwright codegen --load-storage=auth.json example.com
Mientras interactúas con la página, Codegen genera código en tiempo real. Esto es increíblemente útil para prototipar pruebas rápidamente o aprender la sintaxis de selector de Playwright.
Visor de trazas para depuración
Cuando las pruebas fallan, entender por qué puede ser un desafío. El Visor de trazas de Playwright proporciona una vista en forma de cronograma de la ejecución de tu prueba:
// Habilitar trazas en la configuración
use: {
trace: 'on-first-retry',
}
Después de que una prueba falle y se reintente, ve la traza:
playwright show-trace trace.zip
El Visor de trazas muestra capturas de pantalla en cada acción, actividad de red, registros de consola y capturas de DOM, haciendo que la depuración sea sencilla.
Intercepción y simulación de red
Interceptar y modificar el tráfico de red para probar casos límite:
def test_with_mocked_api():
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
# Simular respuesta de API
def handle_route(route):
if 'api/products' in route.request.url:
route.fulfill(
status=200,
body=json.dumps({
'products': [
{'id': 1, 'name': 'Producto de prueba', 'price': 99.99}
]
})
)
else:
route.continue_()
page.route('**/*', handle_route)
page.goto('https://example.com')
# La página ahora usa datos simulados
browser.close()
Pruebas móviles
Prueba tus diseños responsivos en varios dispositivos:
from playwright.sync_api import sync_playwright
def test_mobile():
with sync_playwright() as p:
# Usar descriptor de dispositivo
iphone_13 = p.devices['iPhone 13']
browser = p.webkit.launch()
context = browser.new_context(**iphone_13)
page = context.new_page()
page.goto('https://example.com')
# Interactuar como usuario móvil
page.locator('#mobile-menu-button').click()
browser.close()
Buenas prácticas
Para el raspado web
- Usar modo sin cabeza en producción: El navegador sin cabeza es más rápido y utiliza menos recursos
- Implementar limitación de velocidad: Respetar los sitios web con retrasos entre las solicitudes
- Manejar errores con gracia: Problemas de red, tiempos de espera y cambios en selectores ocurren
- Rotar agentes de usuario: Evitar la detección variando las huellas del navegador
- Respetar robots.txt: Verificar y seguir las políticas de raspado del sitio web
- Usar aislamiento de contexto: Crear contextos de navegador separados para el raspado paralelo
Cuando conviertas contenido raspado a formato markdown, considera aprovechar herramientas basadas en LLM o bibliotecas de Python especializadas en la conversión HTML a markdown para obtener una salida más limpia.
Para las pruebas
- Usar atributos data-testid: Más estables que las clases CSS que cambian con frecuencia
- Evitar esperas duras: Usar los mecanismos de espera integrados de Playwright en lugar de
sleep() - Mantener las pruebas independientes: Cada prueba debe poder ejecutarse de forma aislada
- Usar fixtures: Compartir código de configuración entre pruebas de forma eficiente
- Ejecutar pruebas en paralelo: Aprovechar los hilos de trabajo de Playwright para mayor velocidad
- Grabar trazas al fallar: Habilitar la grabación de trazas para una depuración más sencilla
Optimización de rendimiento
# Deshabilitar recursos innecesarios
def fast_scraping():
with sync_playwright() as p:
browser = p.chromium.launch()
context = browser.new_context()
page = context.new_page()
# Bloquear imágenes y hojas de estilo para acelerar el raspado
async def block_resources(route):
if route.request.resource_type in ['image', 'stylesheet', 'font']:
await route.abort()
else:
await route.continue_()
page.route('**/*', block_resources)
page.goto('https://example.com')
browser.close()
Comparación de Playwright con alternativas
Playwright vs Selenium
Ventajas de Playwright:
- El esperado automático elimina pruebas frágiles
- Ejecución más rápida debido a la arquitectura moderna
- Mejor intercepción y simulación de red
- Herramientas de depuración superiores (Visor de trazas)
- API más simple con menos código de boilerplate
- Soporte multi-navegador con una sola instalación
Ventajas de Selenium:
- Ecosistema más maduro con una comunidad extensa
- Soporta más lenguajes de programación
- Mayor compatibilidad con navegadores, incluyendo versiones antiguas
Playwright vs Puppeteer
Ventajas de Playwright:
- Soporte verdadero multi-navegador (Firefox, WebKit, Chromium)
- Mejor diseño de API basado en lecciones de Puppeteer
- Herramientas de depuración más poderosas
- Soporte activo de Microsoft
Ventajas de Puppeteer:
- Tamaño ligeramente más pequeño
- Experiencia con el protocolo DevTools de Chrome
Para la mayoría de los nuevos proyectos, Playwright es la opción recomendada debido a su arquitectura moderna y su conjunto completo de características. Si estás trabajando con Go en lugar de Python o JavaScript y necesitas capacidades de raspado web, consulta nuestra guía sobre Alternativas a Beautiful Soup para Go para herramientas de raspado comparables en el ecosistema de Go.
Casos de uso comunes
Extracción de datos para aplicaciones de IA/LLM
Playwright es excelente para recopilar datos de entrenamiento o crear capacidades de búsqueda web para modelos de IA. Cuando se construyen servidores MCP (Model Context Protocol), Playwright puede manejar la parte de raspado web mientras los LLM procesan el contenido extraído.
Pruebas automatizadas en CI/CD
Integra las pruebas de Playwright en tu pipeline de integración continua:
# .github/workflows/playwright.yml
name: Pruebas de Playwright
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
test:
timeout-minutos: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Instalar dependencias
run: npm ci
- name: Instalar navegadores de Playwright
run: npx playwright install --with-deps
- name: Ejecutar pruebas de Playwright
run: npx playwright test
- uses: actions/upload-artifact@v3
if: always()
with:
name: reporte-playwright
path: reporte-playwright/
retention-days: 30
Monitoreo de sitios web
Monitorea tus sitios web de producción para verificar disponibilidad y funcionalidad:
import schedule
import time
def monitor_website():
with sync_playwright() as p:
try:
browser = p.chromium.launch()
page = browser.new_page()
page.goto('https://tu-sitio.com', timeout=30000)
# Verificar elementos críticos
assert page.is_visible('.header')
assert page.is_visible('#main-content')
print("✓ El sitio web está saludable")
except Exception as e:
print(f"✗ Detectado problema en el sitio web: {e}")
# Enviar alerta
finally:
browser.close()
# Ejecutar cada 5 minutos
schedule.every(5).minutes.do(monitor_website)
while True:
schedule.run_pending()
time.sleep(1)
Solución de problemas comunes
Problemas de instalación de navegadores
Si los navegadores fallan al descargarse:
# Establecer ubicación de descarga personalizada
PLAYWRIGHT_BROWSERS_PATH=/ruta/Personalizada playwright install
# Limpiar caché e reinstalar
playwright uninstall
playwright install
Errores de tiempo de espera
Aumenta los tiempos de espera para redes lentas o páginas complejas:
page.goto('https://sitio-lento.com', timeout=60000) # 60 segundos
page.wait_for_selector('.elemento', timeout=30000) # 30 segundos
Selector no encontrado
Usa el Inspector de Playwright para identificar selectores correctos:
PWDEBUG=1 pytest test_file.py
Esto abre el inspector donde puedes pasar el cursor sobre elementos para ver sus selectores.
Conclusión
Playwright representa la vanguardia de la tecnología de automatización del navegador, combinando características poderosas con una excelente experiencia del desarrollador. Ya sea que estés construyendo una tubería de raspado web, implementando una cobertura de pruebas completa o creando flujos de trabajo automatizados, Playwright proporciona las herramientas y confiabilidad que necesitas.
Sus mecanismos de espera automática eliminan pruebas frágiles, el soporte multi-navegador asegura que tus aplicaciones funcionen en todas partes y las poderosas herramientas de depuración hacen que la solución de problemas sea sencilla. A medida que las aplicaciones web continúan creciendo en complejidad, la arquitectura moderna de Playwright y su desarrollo activo lo hacen una excelente opción para cualquier necesidad de automatización del navegador.
Para desarrolladores de Python que trabajan en tuberías de datos o proyectos de raspado web, Playwright se integra de forma sencilla con gestores de paquetes modernos y funciona excelente junto con pandas, requests y otras herramientas de ciencia de datos. La capacidad de extraer datos estructurados de sitios web complejos modernos lo hace invaluable para aplicaciones de IA, proyectos de investigación y inteligencia empresarial. Cuando se combina con herramientas de conversión de HTML a Markdown y un procesamiento adecuado del contenido, Playwright se convierte en una solución completa para extraer, transformar y utilizar datos web a gran escala.
Enlaces útiles
- Hoja de trucos de Python
- uv - Gestor de paquetes, proyectos y entornos de Python
- Convertir contenido HTML a Markdown usando LLM y Ollama
- Convertir documentos de Word a Markdown: Una Guía Completa
- Convertir HTML a Markdown con Python: Una Guía Completa
- Construir servidores MCP en Python: WebSearch & Scrape
- Alternativas a Beautiful Soup para Go