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:

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:

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))

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.

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

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.

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.

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.

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

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](/_next/image?url=https%3A%2F%2Fimages.prismic.io%2Fwebscrapingapi%2Fe6d9c82d-40b5-435b-a583-e355c31c3a54_image8.png%3Fauto%3Dformat%2Ccompress&w=3840&q=75)
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](/_next/image?url=https%3A%2F%2Fimages.prismic.io%2Fwebscrapingapi%2Fd3160920-a556-43a7-a069-461561f0b188_image9.png%3Fauto%3Dformat%252Ccompress%26rect%3D0%252C0%252C1100%252C119%26w%3D1100%26h%3D119&w=3840&q=75)
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](/_next/image?url=https%3A%2F%2Fimages.prismic.io%2Fwebscrapingapi%2F71f8d44f-66a5-49c0-8b9d-aff2d8e50b64_image2.png%3Fauto%3Dformat%2Ccompress&w=3840&q=75)
Selecciona todos los nodos «span» que sean hijos de un nodo «p».

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

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

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.




