Volver al blog
Ciencia del Web Scraping
Ștefan Răcilă15 de diciembre de 20227 min de lectura

CSS Selectors Cheat Sheet - Cómo raspar la web consejos y trucos

CSS Selectors Cheat Sheet - Cómo raspar la web consejos y trucos

Introducción al DOM

Durante el proceso de análisis de un archivo HTML, el navegador crea en su memoria una representación de los datos que tiene forma de árbol. Esta representación se denomina DOM (Modelo de objetos del documento). Por cada etiqueta HTML, hay un nodo asociado a ella en el DOM. Un nodo tiene propiedades como el nombre, el contenido, los nodos secundarios, los estilos, los eventos, etc. Puedes encontrar más información sobre cómo funciona la representación del navegador en este artículo : «Cómo funciona la representación del navegador: entre bastidores».

Cuando decimos que queremos acceder a los datos de una página web, lo que realmente queremos es recorrer el DOM hasta llegar a un conjunto específico de nodos y extraer el contenido que hay en ellos. En este artículo te daré varios consejos sobre cómo acceder rápidamente a esos nodos utilizando selectores CSS.

¿Qué son los selectores CSS?

¿Por qué se llaman «selectores CSS» (hojas de estilo en cascada)? 

El CSS se utiliza para definir el aspecto de los nodos en una página. Con el CSS puedes escribir reglas sobre cómo debe verse un nodo y cómo debe interactuar con otros nodos. Una regla se compone de un selector y una lista de estilos que se van a sobrescribir.

Por lo tanto, estos selectores se asocian con el CSS porque ese es su uso más habitual, pero no es necesario utilizarlos solo con el CSS. Con el CSS, lo que se busca es seleccionar un nodo y modificar su propiedad de estilo. Si lo piensas bien, lo que queremos hacer es lo mismo: seleccionar un nodo y realizar alguna acción con él, como leer su contenido o activar un evento. 

¿Cómo funcionan los selectores CSS?

Te resultará de gran ayuda visualizar cómo se lleva a cabo la selección. Supongamos que quieres extraer todos los párrafos de una página web. Quieres obtener todos los nodos que tengan el nombre «p». Puedes hacerlo manualmente. Solo tienes que recorrer todos los nodos del DOM y seleccionar únicamente aquellos que cumplan la condición `node.tagName === 'P' ` (los nombres de las etiquetas se escriben en mayúsculas).

Aquí tienes un pequeño fragmento de código que puedes utilizar:

function scrapeByTagName(node, tagName) {
    if (node === null)
        return;
 
    node.childNodes.forEach(node => {
        //console.log(node.tagName)

        if (node.tagName?.toLowerCase() === tagName.toLowerCase()) {
            console.log(node)
            return
        }

        scrapeByTagName(node, tagName)
    });
}

He creado una página web de prueba que tiene este aspecto:

Ejemplo de tarjeta de página web que muestra encabezados y párrafos con identificadores y clases CSS como .text y .bold

Y aquí está el código HTML correspondiente:

<!DOCTYPE html>
<html lang="en">

<head>
    <link rel="stylesheet" href="styles.css">
    <script src="script.js"></script>
</head>

<body>
    <div id="wrapper">
        <h1 custom-attr="some data">Some Title</h1>
        <h2 custom-attr="some other data">Some Subtitle</h2>
        <div id="container">
            <p custom-attr>paragraph
                <span> subparagraph</span>
            </p>
            <p id="text">paragraph with id #text</p>
            <p class="bold">paragraph with class .bold</p>
            <p class="text">paragraph with class .text</p>
            <p class="text bold">paragraph with class .text.bold</p>
            <p class="text italic">paragraph with class .text.italic</p>
        </div>
    </div>
</body>

</html>

Después de ejecutar la función en la consola del navegador, obtuve esta respuesta:

Code snippet showing HTML <p> elements with id and class attributes under a function call scrapeByTagName(document, 'p')

Como puedes ver, la función ha registrado todas las etiquetas p.

Para ver la consola del navegador, debes abrir DevTools y dirigirte a la pestaña «Consola» o pulsar esEsc. Puedes abrir devTools haciendo clic con el botón derecho en un elemento y seleccionando Inspeccionarpect en el menú, o utilizando el atajo de teclado Control + Mayús + i.

¿Cómo se utilizan los selectores CSS?

Utilizaremos dos métodos: querySelector y querySelectorAll. Estos métodos aparecen en todos los objetos de tipo Element. Los nodos que intentamos extraer son de tipo HTMLElement, que hereda del tipo Element.

querySelector devolverá el primer nodo que coincida con el selector. querySelectorAll devolverá una lista con todos los nodos que coincidan con el selector. Para replicar el ejemplo mostrado anteriormente, solo tenemos que llamar a querySelectorAll e iterar por la lista devuelta.

document.querySelectorAll('p').forEach(node => console.log(node))
Fragmento de código de la consola de JavaScript que utiliza `document.querySelectorAll('p')` para registrar los elementos de párrafo con distintas clases e ID

Como puedes ver, he utilizado document.querySelectorAll, eso es porque document está definido en el contexto de la ventana como la raíz de la página web, es decir, el equivalente a la etiqueta html. Puedes utilizar los métodos de querySelector con todos los nodos, no solo con el nodo raíz.

Para extraer datos de una página web, necesitarás utilizar una biblioteca que permita abrir una ventana del navegador y acceder a una URL. Solo entonces se ejecutará tu código, en el contexto de esa ventana. Para obtener más información sobre cómo hacerlo, te recomiendo este artículo : «La guía definitiva para la extracción de datos web con JavaScript y Node.js».

En WebScrapingAPI utilizamos Puppeteer. Puppeteer es una biblioteca que nos permite controlar instancias de navegadores Chromium sin interfaz gráfica. Puedes utilizar nuestra API para extraer datos de un sitio web sin necesidad de crear un rastreador personalizado. De hecho, contamos con un parámetro llamado «extract_rules» que utiliza selectores CSS para extraer datos de una URL determinada.

Guía rápida de selectores CSS

El selector *

Este selector selecciona todos los elementos del árbol. No se utiliza mucho, pero conviene saberlo.

El selector .class

Puedes obtener un nodo con una clase específica utilizando .class. Se suele utilizar sobre todo cuando se tiene una lista de elementos. Dado que es probable que los elementos de una lista tengan el mismo aspecto, es posible que compartan la misma clase. Busquemos la clase .text.

Fragmento de código que utiliza `document.querySelectorAll('.text')` para recorrer los elementos, con etiquetas de párrafo de ejemplo

Quizás quieras seleccionar el nodo que tiene la clase .bold.

Ejemplo en la consola de JavaScript para seleccionar elementos con la clase .bold y registrar dos nodos de párrafo

Parece que hay otro elemento que tiene la clase .bold. Puedes ser más específico con el selector de clase utilizando varias clases concatenadas.

Ejemplo en la consola de JavaScript para seleccionar «.text.bold» y registrar un elemento de párrafo con las clases «text» y «bold»

Ten en cuenta que no hay espacios entre las clases.

document.querySelectorAll('.text .bold').forEach(node => console.log(node))

Esta consulta no devuelve ningún resultado del código HTML anterior, ya que busca un elemento con la clase .text que tenga un elemento secundario con la clase .bold (no necesariamente un elemento secundario directo). La consulta devolvería el elemento secundario si lo encontrara. 

El selector #id

¿Qué ocurre si un elemento no tiene una clase o si la clase se utiliza con demasiada frecuencia en el documento? Puedes utilizar el atributo «id» para lograr un mayor nivel de especificidad. El inconveniente de utilizar el selector «id» es que, en la mayoría de los casos, el «id» es único en la página HTML, por lo que no es posible obtener una lista de nodos con él.

Fragmento de código que utiliza `document.querySelector('#text')` y devuelve un elemento de párrafo con el identificador «text»

El selector de nombres de nodos

Cada nodo tiene un nombre. Es el nombre exacto de la etiqueta emparejada en el código HTML. Puedes obtener todos los nodos que tengan un nombre específico utilizando ese nombre en el selector.

JavaScript console output listing two <div> elements with ids wrapper and container

El selector [atributo] 

Es posible que te encuentres con situaciones en las que quieras seleccionar todos los nodos que tengan un atributo concreto.

Ejemplo en la consola de JavaScript para seleccionar elementos con un atributo «custom-attr», mostrando los nodos de encabezado y párrafo

También puedes especificar el valor del atributo.

Ejemplo en la consola de JavaScript que selecciona [custom-attr="some data"] y devuelve un único elemento h1

O incluso qué debe contener el valor del atributo. Puedes utilizar el símbolo de la tilde (~) delante del signo igual para indicar que el valor del atributo debe contener una lista de palabras.

Ejemplo en la consola de JavaScript para seleccionar [custom-attr~="data"], que coincide con los elementos h1 y h2 con atributos personalizados

El selector de atributos será el más utilizado si decides crear un rastreador web. Es muy potente y tiene muchos más casos de uso de los que he mostrado aquí. Puedes encontrar más información sobre cómo utilizar el selector de atributos aquí: Selectores de atributos W3.

Agrupación de varios selectores

Obtener todos los nodos p que tengan un identificador.

Ejemplo de la consola de JavaScript para seleccionar p[id], que devuelve un elemento de párrafo con el texto del identificador

Selecciona todos los nodos «span» que sean hijos de un nodo «p».

Ejemplo de la consola de JavaScript para seleccionar un elemento `p` y un elemento `span`, y devolver un elemento `span` dentro de un párrafo

Obtén todos los elementos `div` que sean hijos directos del elemento `body`.

Ejemplo de la consola de JavaScript para seleccionar un elemento `body > div` y devolver un elemento `div` contenedor

Obtén todos los nodos p que tengan la clase .text

Ejemplo de consola de JavaScript que selecciona p.text y devuelve elementos de párrafo con la clase «text» en las variantes normal, negrita y cursiva

Las posibilidades de combinar estos selectores son infinitas. Intenta copiar el código HTML anterior y añádele más nodos. A continuación, prueba diferentes combinaciones de selectores. Si quieres saber más sobre los selectores CSS en general, Mozilla ofrece un artículo fantástico que explica cómo funcionan los selectores CSS en el desarrollo web.

Resumen

Si quieres aprender algo nuevo, te aconsejo que primero averigües cómo funciona. Sí, es un paso opcional, pero te proporcionará información que otros no tienen. 

En el ámbito del desarrollo de software, esta información te ayudará a encontrar la respuesta adecuada a tu problema o error. Podrías tomar las riendas del asunto e incluso crear una solución personalizada.

Si de verdad quieres entender los selectores CSS, tienes que entender el DOM. No es más que un árbol (un grafo acíclico no dirigido) con nodos que tienen un nombre y algunos atributos. Eso es todo. Cuando escribes un selector, lo único que haces es escribir una cadena que se analiza y se utiliza para consultar el DOM.

Acerca del autor
Ștefan Răcilă, desarrollador full stack en WebScrapingAPI
Ștefan RăcilăDesarrollador Full Stack

Stefan Racila es ingeniero de DevOps y Full Stack en WebScrapingAPI, donde se encarga de desarrollar funciones para los productos y de mantener la infraestructura que garantiza la fiabilidad 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.