Volver al blog
Guías
Mihnea-Octavian ManolacheLast updated on Mar 31, 202612 min read

La guía definitiva sobre web scraping y automatización para Playwright en 2023

La guía definitiva sobre web scraping y automatización para Playwright en 2023

El web scraping y la automatización van de la mano en el mundo digital actual. Desde sitios web de comparación de precios hasta empresas basadas en datos, la capacidad de extraer y procesar datos de la web se ha convertido en una parte fundamental de muchos proyectos en línea.

Te presentamos Playwright: una herramienta que te permite automatizar tareas de web scraping y pruebas con facilidad. Playwright te permite controlar un navegador sin interfaz gráfica, lo que te da la capacidad de extraer datos e interactuar con sitios web de forma rápida y eficiente.

En este artículo, exploraremos las capacidades de Playwright para la automatización y el scraping. Te mostraré cómo instalar y configurar Playwright, proporcionaré ejemplos de código para tareas comunes y analizaré técnicas avanzadas como el manejo de formularios de inicio de sesión, la captura de capturas de pantalla y mucho más.

¿Qué es Playwright?

Playwright es una biblioteca Node.js multiplataforma de código abierto desarrollada por Microsoft que permite automatizar tareas en un navegador web. Está diseñada para ser fiable y fácil de usar, y es compatible con características web modernas como CSS3 y JavaScript.

Playwright se puede utilizar para tareas como probar aplicaciones web, automatizar tareas basadas en la web y extraer datos de la web. Se basa en la popular biblioteca de pruebas web Puppeteer y tiene como objetivo proporcionar una API más fácil de usar y de mantener.

Playwright es compatible con múltiples navegadores, incluidos Chromium, Firefox y WebKit. Esto significa que puedes utilizarlo para automatizar tareas y extraer datos en diferentes navegadores. Playwright te permite cambiar fácilmente de un navegador a otro y aprovechar sus características únicas.

Primeros pasos

Para instalar y configurar Playwright en un equipo local, necesitarás tener instalados Node.js y npm (el gestor de paquetes para Node.js). Si aún no los tienes, puedes descargarlos e instalarlos desde el sitio web oficial de Node.js.

Una vez que tengas Node.js y npm instalados, puedes instalar Playwright siguiendo estos pasos:

  • Abre un terminal o una ventana de comandos
  • Crea una carpeta llamada `playwright` donde se alojará el código de nuestro proyecto
  • Ve a la carpeta recién creada
  • Ejecuta el comando `npm init` para inicializar el proyecto (y crear el archivo package.json)
  • Instala la dependencia necesaria con el comando `npm install playwright`

Scraping básico con Playwright

Crea un archivo llamado `index.js` y pega el siguiente código:

const { chromium } = require('playwright');

(async () => {

    // Launch a Chromium browser

    const browser = await chromium.launch();

    // Create a new page in the browser

    const page = await browser.newPage();

    // Navigate to a website

    await page.goto('https://coinmarketcap.com');

    // Get the page content

    const content = await page.content();

    // Display the content

    console.log(content);

    // Close the browser

    await browser.close();

})();

Este código iniciará un navegador Chromium sin interfaz gráfica, creará una nueva página, navegará a la página de inicio de CoinMarketCap, obtendrá el contenido de la página, registrará el contenido y, a continuación, cerrará el navegador.

Puedes utilizar un código similar para iniciar los otros navegadores compatibles (Firefox y WebKit) requiriendo el módulo adecuado y sustituyendo «chromium» por «firefox» o «webkit».

Búsqueda de elementos para la extracción de datos

Ahora que tenemos una base para nuestro scraper, extraigamos algunos datos del sitio web de destino. En este ejemplo, recuperaremos el nombre y el precio de las primeras 10 divisas que aparecen en la página.

Para ver el árbol DOM de la página de inicio de CoinMarketCap, abre el sitio web en un navegador, haz clic con el botón derecho del ratón sobre el nombre de una divisa y selecciona «Inspeccionar». Esto abrirá las Herramientas de desarrollador y mostrará el árbol DOM.

Seleccionar los selectores adecuados es un arte en sí mismo. En este caso, el elemento de tabla que queremos seleccionar es el contexto. Esta tabla tiene una clase llamada «cmc-table» que nos resultará útil para nuestros fines.

Para encontrar el selector del nombre de la moneda, tendremos que desplazarnos hacia abajo en el árbol DOM. El elemento que buscamos se encuentra dentro del elemento `.cmc-table tbody tr td:nth-child(3) a .name-area p`.

Como regla general, es importante ser lo más preciso posible al seleccionar elementos, ya que esto minimizará el número de errores que habrá que gestionar.

Utilizando la misma técnica, podemos encontrar el selector para el precio, que es `.cmc-table tbody tr td:nth-child(3) a span`. En resumen, esta es nuestra lista de selectores:

  • Nombre: `.cmc-table tbody tr td:nth-child(3) a .name-area p`
  • Precio: `.cmc-table tbody tr td:nth-child(4) a span`

Extracción de datos

Utilizando los selectores que hemos identificado anteriormente, extraigamos los datos de la página web y almacenémoslos en una lista. La función de utilidad $$eval devuelve una matriz de elementos que coinciden con un selector, evaluados en el contexto del DOM de la página.

Reemplacemos la línea console.log(content); por esto:

// Extract the currencies data

const currencies = await page.$$eval('.cmc-table tbody tr:nth-child(-n+10)', trs => {

    const data = []

    trs.forEach(tr => {

        data.push({

            name: tr.querySelector('td:nth-child(3) a .name-area p').innerHTML,

            price: tr.querySelector('td:nth-child(4) a span').innerHTML,

        })

    })

    return data

})

// Display the results

console.log(currencies)

Este código utiliza la función $$eval para seleccionar los primeros 10 elementos tr dentro de .cmc-table. A continuación, recorre estos elementos, selecciona las celdas de datos de la tabla utilizando los selectores que hemos identificado anteriormente y extrae su contenido de texto. Los datos se devuelven como una matriz de objetos.

Puedes leer más sobre la función $$eval en la documentación oficial.

El código completo tiene este aspecto:

const { chromium } = require('playwright');

(async () => {

    // Launch a Chromium browser

    const browser = await chromium.launch();

    // Create a new page in the browser

    const page = await browser.newPage();

    // Navigate to a website

    await page.goto('https://coinmarketcap.com');

    // Extract the currencies data

    const currencies = await page.$$eval('.cmc-table tbody tr:nth-child(-n+10)', trs => {

   	 const data = []

   	 trs.forEach(tr => {

   		 data.push({

   			 name: tr.querySelector('td:nth-child(3) a .name-area p').innerHTML,

   			 price: tr.querySelector('td:nth-child(4) a span').innerHTML,

   		 })

   	 })

   	 return data

    })

    // Display the results

    console.log(currencies)

    // Close the browser

    await browser.close();

})();

Manejo de contenido dinámico

Solo hemos extraído las primeras 10 divisas porque es la cantidad que CoinMarketCap carga en la carga inicial de la página. Para extraer más, necesitamos realizar una acción humana, que es desplazarnos por la página. Afortunadamente, Playwright es ideal para esta tarea.

Empecemos por refactorizar la función $$eval que utilizamos anteriormente e implementar la paginación. Llamaremos a esta nueva función extractData:

const extractData = async (page, currentPage, perPage = 10) => {

}

Ampliamos el selector :nth-child seleccionando elementos por pasos (elementos del 0 al 10, del 11 al 21, del 22 al 32, etc.). Definimos el selector inicial (los primeros 10 elementos):

let selector = `:nth-child(-n+${currentPage * perPage})`;

Por último, pero no menos importante, añadimos soporte para las páginas siguientes. El código queda así:

if(currentPage > 1) {

    selector = `:nth-child(n+${(currentPage - 1) + perPage}):nth-child(-n+${(currentPage * perPage) + 1})`;

}

La función final tendrá este aspecto:

const extractData = async (page, currentPage, perPage = 10) => {

    let selector = `:nth-child(-n+${currentPage * perPage})`;

    if(currentPage > 1) {

   	 selector = `:nth-child(n+${(currentPage - 1) + perPage}):nth-child(-n+${(currentPage * perPage) + 1})`;

    }

    return await page.$$eval(`.cmc-table tbody tr${selector}`, trs => {

   	 const data = [];

   	 trs.forEach(tr => {

   		 data.push({

   			 name: tr.querySelector('td:nth-child(3) a .name-area p').innerHTML,

   			 price: tr.querySelector('td:nth-child(4) a span').innerHTML,

   		 });

   	 });

   	 return data;

    });

};

Ahora es el momento de volver a nuestro código de scraper, implementar el desplazamiento y ampliar la extracción de datos. Hacemos todo el trabajo después de esta línea:

await page.goto('https://coinmarketcap.com');

Redefinimos la variable de divisas:

// Extract the currencies data

let currencies = await extractData(page, 1, 10);

Usando la función evaluate, desplazamos la página a 1,5 veces el tamaño de la ventana de visualización. Esto hará que se carguen los siguientes elementos de la tabla:

// Scroll the page to a little more than the viewport height

await page.evaluate(() => {

    window.scrollTo(0, window.innerHeight * 1.5);

});

El segundo de espera le dará a la interfaz de usuario algo de tiempo para rellenar la tabla con los datos recuperados de la API:

// Wait for the new elements to load

await page.waitForTimeout(1000);

Por último, extraigamos los datos de la segunda página y registremos los resultados:

// Extract the next 10 elements

currencies = [...currencies, ...await extractData(page, 2, 10)]

// Display the results

console.log(currencies)

El código completo del rastreador debería tener este aspecto:

const { chromium } = require('playwright');

const extractData = async (page, currentPage, perPage = 10) => {

    let selector = `:nth-child(-n+${currentPage * perPage})`;

    if(currentPage > 1) {

   	 selector = `:nth-child(n+${(currentPage - 1) + perPage}):nth-child(-n+${(currentPage * perPage) + 1})`;

    }

    return await page.$$eval(`.cmc-table tbody tr${selector}`, trs => {

   	 const data = [];

   	 trs.forEach(tr => {

   		 data.push({

   			 name: tr.querySelector('td:nth-child(3) a .name-area p').innerHTML,

   			 price: tr.querySelector('td:nth-child(4) a span').innerHTML,

   		 });

   	 })

   	 return data;

    })

};

(async () => {

    // Launch a Chromium browser

    const browser = await chromium.launch();

    // Create a new page in the browser

    const page = await browser.newPage();

    // Navigate to a website

    await page.goto('https://coinmarketcap.com');

    // Extract the currencies data

    let currencies = await extractData(page, 1, 10)

    // Scroll the page to a little more than the viewport height

    await page.evaluate(() => {

   	 window.scrollTo(0, window.innerHeight * 1.5);

    });

    // Wait for the new elements to load

    await page.waitForTimeout(1000);

    // Extract the next 10 elements

    currencies = [...currencies, ...await extractData(page, 2, 10)];

    // Display the results

    console.log(currencies);

    // Close the browser

    await browser.close();

})();

En resumen, el scraper abrirá la página de inicio de CoinMarketCap, extraerá los datos de las primeras 10 monedas, desplazará la página, extraerá los datos de las siguientes 10 monedas y mostrará los resultados.

Deberías obtener resultados similares a estos:

[

  { name: 'Bitcoin', price: '$16,742.58' },

  { name: 'Ethereum', price: '$1,244.45' },

  { name: 'Tether', price: '$0.9997' },

  { name: 'USD Coin', price: '$1.00' },

  { name: 'BNB', price: '$255.78' },

  { name: 'XRP', price: '$0.335' },

  { name: 'Binance USD', price: '$1.00' },

  { name: 'Dogecoin', price: '$0.07066' },

  { name: 'Cardano', price: '$0.2692' },

  { name: 'Polygon', price: '$0.7762' },

  { name: 'Dai', price: '$0.9994' },

  { name: 'Litecoin', price: '$73.80' },

  { name: 'Polkadot', price: '$4.59' },

  { name: 'Solana', price: '$12.95' },

  { name: 'TRON', price: '$0.0505' },

  { name: 'Shiba Inu', price: '$0.000008234' },

  { name: 'Uniswap', price: '$5.29' },

  { name: 'Avalanche', price: '$11.43' },

  { name: 'UNUS SED LEO', price: '$3.47' },

  { name: 'Wrapped Bitcoin', price: '$16,725.03' },

  { name: 'Cosmos', price: '$9.97' }

]

Técnicas avanzadas

Ahora que hemos cubierto los conceptos básicos del scraping web con Playwright, como crear un scraper, encontrar selectores, extraer datos e implementar el desplazamiento infinito, es hora de profundizar en algunas de las funciones más avanzadas que ofrece Playwright.

Entre ellas se incluyen la captura de pantallas, el rellenado de formularios, el uso de XPaths en lugar de selectores de clase y el uso de proxies para eludir bloqueos de IP.

Hacer una captura de pantalla

Una de las ventajas de tomar capturas de pantalla mientras se realiza el web scraping es que permite ver cómo se ve un sitio o una aplicación web en diferentes navegadores y resoluciones.

Esto puede resultar especialmente útil para los desarrolladores, que pueden utilizar las capturas de pantalla para depurar problemas de diseño y probar el aspecto de sus aplicaciones web en diferentes plataformas.

Para hacer una captura de pantalla de página completa, puedes utilizar el método `screenshot` del objeto `Page`. Aquí tienes un ejemplo:

const screenshot = await page.screenshot();

Este código toma una captura de pantalla de toda la página y la devuelve como un Buffer. La función `screenshot` acepta propiedades. Podemos definir la ruta donde queremos que se guarde la captura de pantalla y si esta debe contener solo la ventana de visualización o toda la página.

Este es el código completo:

const { chromium } = require('playwright');

(async () => {

    const browser = await chromium.launch();

    const page = await browser.newPage();

    await page.goto('https://coinmarketcap.com');

    // Take a full page screenshot and save the file

    await page.screenshot({

   	 path: "screenshot.png",

   	 fullPage: false

    });

    await browser.close();

})();

Puedes guardar este código en un archivo llamado `screenshot.js` y ejecutarlo con el comando `node screenshot.js`. Tras la ejecución, se creará un archivo `screenshot.png` en la carpeta de tu proyecto.

Podemos hacer una captura de pantalla de un área de la página utilizando la propiedad `clip`. Necesitamos definir cuatro propiedades:

  • x: el desplazamiento horizontal desde la esquina superior izquierda
  • y: el desplazamiento vertical desde la esquina superior izquierda
  • width: el ancho del área
  • height: la altura del área

La función de captura de pantalla con la propiedad clip configurada tendrá este aspecto:

// Take a screenshot of a part of the page

await page.screenshot({

    path: "screenshot.png",

    fullPage: false,

    clip: {

        x: 50,

        y: 50,

        width: 320,

        height: 160

    }

});

Rellenar formularios

Una de las ventajas de usar Playwright es que te permite acceder a páginas protegidas. Al emular acciones humanas como hacer clic en botones, desplazarse por la página y rellenar formularios, Playwright puede eludir los requisitos de inicio de sesión y acceder a contenido restringido.

Usemos Playwright para acceder a nuestra cuenta de Reddit (si no tienes una cuenta de Reddit, ¡crea una ahora mismo!).

Ve a la página de inicio de sesión y utiliza las técnicas que aprendimos en la sección «Búsqueda de elementos para la extracción de datos» para extraer las clases de los campos de nombre de usuario y contraseña.

Los selectores deberían tener este aspecto:

  • Campo de nombre de usuario: `#loginUsername`
  • Campo de contraseña: `#loginPassword`
  • Botón de envío: `button[type=”submit”]`

Usemos estos selectores en el código. Crea un archivo `login.js` y pega este código:

const { chromium } = require('playwright');

(async () => {

    const browser = await chromium.launch();

    const page = await browser.newPage();

    await page.goto('https://reddit.com/login');

    // Fill up the form

    await page.fill('#loginUsername', "YOUR_REDDIT_USERNAME");

    await page.fill('#loginPassword', "YOUR_REDDIT_PASSWORD");

    // Click the submit button

    await page.click('button[type="submit"]');

    // Wait for the new page to load

    await page.waitForNavigation()

    // Take a screenshot of the new page

    await page.screenshot({

   	 path: "reddit.png",

   	 fullPage: false

    });

    // Close the browser

    await browser.close();

})();

Para ejecutar el código y hacer una captura de pantalla de la página protegida, solo tienes que escribir node login.js en la terminal. Tras unos segundos, aparecerá una captura de pantalla llamada reddit.png en el directorio de tu proyecto.

Por desgracia, no puedo compartir la captura de pantalla resultante contigo, ya que la mayor parte de mi cuenta de Reddit no es apta para el trabajo.

Puedes leer más sobre la autenticación con Playwright en la documentación oficial.

Uso de XPath para la extracción de datos

XPath puede ser una opción más estable para el web scraping, ya que es menos probable que cambie que los nombres de clase. Sitios web como Reddit y Google suelen actualizar sus nombres de clase, lo que puede causar problemas a los scrapers que dependen de ellos.

Por el contrario, las expresiones XPath se basan en la estructura del documento HTML y es menos probable que cambien. Esto significa que puedes utilizar XPath para identificar elementos de una manera más fiable y estable, incluso en sitios web que actualizan con frecuencia sus nombres de clase.

Como resultado, el uso de XPath puede ayudarte a crear un rastreador web más robusto y resistente, menos propenso a fallar cuando se actualiza el sitio web.

En este artículo solo vamos a dar una visión general de lo que se puede hacer con XPath. Para una guía más completa, consulta este artículo.

Volvamos a Reddit, abramos un subreddit y abramos las Herramientas de desarrollador. Yo utilizaré el subreddit /r/webscraping, pero puedes elegir cualquier subreddit que desees.

Si examinas el árbol DOM, te darás cuenta de que las clases de los elementos parecen generarse aleatoriamente. Usar estas clases reduciría la fiabilidad del scraper y requeriría un mantenimiento continuo.

Haz clic con el botón derecho en la etiqueta `h3`, ve a Copiar y selecciona `Copiar XPath`. El resultado debería ser similar a este:

//*[@id="t3_104ocrd"]/div[3]/div[2]/div[1]/a/div/h3

Antes de usar esta regla, eliminemos la parte @id para que la ruta cubra todas las publicaciones y no solo la primera.

Es hora de ponerlo en marcha. Crea el archivo `xpath.js` y pega este código:

const { chromium } = require('playwright');

(async () => {

    const browser = await chromium.launch();

    const page = await browser.newPage();

    await page.goto('https://reddit.com/r/webscraping');

    const titles = await page.$$eval("//*/div[3]/div[2]/div[1]/a/div/h3", element => {

   	 const data = []

   	 element.forEach(el => {

   		 data.push(el.innerHTML)

   	 })

   	 return data

    })

    console.log(titles)

    // Close the browser

    await browser.close();

})();

Para ejecutar el código, utiliza el comando `node xpath.js`. Esto devolverá una lista de títulos del subreddit que hayas seleccionado. Por ejemplo, mi lista tiene este aspecto:

[

  'A Year of Writing about Web Scraping in Review',

  'Linkedin Comments Scraper - Script to scrape comments (including name, profile picture, designation, email(if present), and comment) from a LinkedIn post from the URL of the post.',

  'Best Proxy Lists?',

  'Sorry if this is the wrong sub, but is it possible to extract an email from an old youtube account?',

  'Looking for people with datasets for sale!',

  "Are reddit's classes names change periodically (those with random letters and numbers and what not)",

  'Scrape Videos from multiple websites',

  'Anyone want to write me a program that can automate generating a pdf of a magazine subscription?',

  'Scraping a Dynamic Webpage with rSelenium',

  'Is there a way to convert LinkedIn Sales Navigator URLs to a LinkedIn public URL?',

  'Gurufocus / Implemented new cloudflare protection?',

  'Scraper to collect APY data from Web3 frontends'

]

Puedes leer más sobre XPath en la documentación oficial de Playwright. La encontrarás aquí.

Playwright frente a los demás

Playwright, Puppeteer y Selenium WebDriver son herramientas que se pueden utilizar para el scraping web y la automatización.

Playwright, desarrollado por Microsoft, es una herramienta más reciente que pretende ser una solución «completa» para la automatización web. Es compatible con múltiples navegadores (Chromium, Firefox y WebKit) y múltiples lenguajes de programación (JavaScript, TypeScript, Python y C#).

Puppeteer es una herramienta desarrollada por Google para el scraping web y la automatización, basada en el protocolo Chrome DevTools. Se utiliza principalmente con JavaScript y cuenta con numerosas funciones, como la captura de capturas de pantalla, la generación de archivos PDF y la interacción con el DOM.

Selenium WebDriver es una herramienta para la automatización y las pruebas web que es compatible con múltiples lenguajes de programación y navegadores. Está orientada a las pruebas y puede requerir más configuración que otras herramientas.

Comparación del rendimiento

El rendimiento es un factor importante a tener en cuenta a la hora de elegir una herramienta de web scraping. En esta sección, compararemos el rendimiento de Playwright, Puppeteer y Selenium WebDriver para ver qué herramienta es la más rápida y eficiente.

Durante nuestras pruebas, observamos que Playwright y Puppeteer tenían tiempos de respuesta casi idénticos en lo que respecta a las tareas de web scraping y automatización. Sin embargo, Selenium WebDriver fue significativamente más lento al iniciarse en comparación con las otras dos herramientas.

Conclusión

El web scraping permite extraer y procesar datos de sitios web, lo que proporciona una gran cantidad de información y oportunidades tanto para empresas como para particulares. Algunas de las ventajas del web scraping son:

  • Ahorro de costes: el web scraping puede ser una forma rentable de recopilar datos, ya que permite evitar la necesidad de adquirir costosas bases de datos o API.
  • Eficiencia en el tiempo: el scraping de grandes cantidades de datos puede realizarse mucho más rápido que recopilarlos manualmente.
  • Datos actualizados: el web scraping puede ayudarte a mantener tus datos actualizados, ya que te permite extraer y actualizar regularmente tus fuentes de datos.

Playwright es una potente herramienta para el web scraping que ofrece una variedad de funciones que la convierten en la opción preferida de muchos usuarios. Algunas de las ventajas de utilizar Playwright son:

  • Compatibilidad con Chromium: Playwright se basa en Chromium, el proyecto de navegador de código abierto que impulsa Google Chrome, lo que te da acceso a las últimas funciones de la plataforma web y a una amplia compatibilidad con sitios web.
  • Compatibilidad con múltiples navegadores: Playwright te permite automatizar tareas en varios navegadores, incluidos Chrome, Firefox y Safari.
  • Facilidad de uso: Playwright cuenta con una API sencilla e intuitiva, lo que facilita el inicio en el web scraping y las tareas de automatización.
  • Versatilidad: Playwright se puede utilizar para una amplia gama de tareas, incluyendo el web scraping, las pruebas y la automatización.

En general, los beneficios del web scraping y las ventajas de utilizar Playwright lo convierten en una herramienta esencial para cualquiera que desee extraer y procesar datos de la web.

Si buscas una solución más sencilla para tus necesidades de web scraping, considera utilizar WebScrapingAPI. Nuestro servicio te permite extraer datos de cualquier sitio web sin tener que lidiar con las complejidades de configurar y mantener un web scraper.

Con WebScrapingAPI, solo tienes que enviar una solicitud HTTP a nuestra API con la URL del sitio web que deseas extraer, y te devolveremos los datos en el formato que prefieras (JSON, HTML, PNG).

Nuestra API se encarga de todo el trabajo pesado por ti, incluyendo eludir CAPTCHAs, gestionar bloqueos de IP y manejar contenido dinámico.

¿Por qué perder tiempo y recursos creando y manteniendo tu propio rastreador web cuando puedes usar WebScrapingAPI y obtener los datos que necesitas con solo unas pocas y sencillas solicitudes de API? Pruébanos y descubre cómo podemos ayudarte a optimizar tus necesidades de rastreo web.

Acerca del autor
Mihnea-Octavian Manolache, Desarrollador Full Stack @ WebScrapingAPI
Mihnea-Octavian ManolacheDesarrollador Full Stack

Mihnea-Octavian Manolache es ingeniero Full Stack y DevOps en WebScrapingAPI, donde se encarga de desarrollar funciones para los productos y de mantener la infraestructura que garantiza el buen funcionamiento de la plataforma.

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.