Web Scraping con NODRIVER en 2025

Domine el scraping web con NODRIVER. Esta guía cubre la configuración, las características clave y los métodos para agilizar sus flujos de trabajo de extracción de datos.
11 min de lectura
web scraping with NODRIVER blog image

Durante años, Undetected Chromedriver ha sido un elemento básico en la navegación segura y la evasión anti-bot. El desarrollador detrás de Undetected Chromedriver ha creado desde entonces NODRIVER. Con NODRIVER, ya no dependes de Selenium o Webdriver. Un simple pip instalar y todo debería estar listo para ir.

En esta guía aprenderás:

  • ¿Qué es NODRIVER?
  • ¿En qué se diferencia de otros navegadores sin cabeza?
  • ¿Cómo utilizar NODRIVER?
  • ¿Cuáles son las limitaciones de NODRIVER?
  • ¿Cómo utilizar NODRIVER con un proxy?
  • Sólidas alternativas a NODRIVER

¿Qué es NODRIVER y por qué debería importarle?

¿Qué es exactamente NODRIVER?

NODRIVER es el sucesor totalmente asíncrono de Undetected Chromedriver. El uso de “mejores prácticas” como el valor predeterminado para todos los kwargs, esta cosa ha sido diseñado para trabajar a la derecha de la caja con sólo una pequeña cantidad de código.

NODRIVER cuenta con las siguientes características:

  • Rendimiento
  • Sin dependencias externas (ni siquiera Chromedriver)
  • Anulación Antibot
  • Cookies de sesión persistentes
  • Nueva instancia del navegador con cada uso

¿Qué hace diferente a NODRIVER?

NODRIVER utiliza una arquitectura radicalmente diferente a la de Undetected Chromedriver e incluso a la de otros navegadores headless. Tradicionalmente, estos otros navegadores han dependido de Selenium, o Chrome DevTools Protocol (CDP).

NODRIVER utiliza su propia implementación personalizada del protocolo DevTools. En la documentación, en realidad se denomina “chrome (-ish) automation library”. Con NODRIVER, no dependes de Selenium, ni dependes directamente de CDP. NODRIVER utiliza una implementación personalizada de CDP. Para utilizar NODRIVER, todo lo que necesita es pip y un navegador basado en Chrome.

Scraping con NODRIVER

1. 1. Primeros pasos

Antes de empezar, necesitas asegurarte de que tienes Python y un navegador instalados. Si estás leyendo este artículo, asumo que ya los tienes. Puedes instalar NODRIVER directamente con pip.

pip install nodriver

2. Estructura básica

Nuestra estructura básica es realmente similar a la que obtendrías con Playwright o Puppeteer. Si estás interesado en usar Playwright en Python, puedes ver una guía completa sobre el scraping de listados de Amazon aquí. NODRIVER es muy similar a Playwright, pero aún está en fase de desarrollo.

Esta es nuestra estructura básica.

import nodriver

async def main():
    #start the browser
    browser = await nodriver.start()

    base_url = "https://quotes.toscrape.com"

    #navigate to a page
    page = await browser.get(base_url)

    ###logic goes here###

    #close the browser
    await page.close()

if __name__ == '__main__':

    #in their docs, they advise directly against asyncio.run()
    nodriver.loop().run_until_complete(main())

3. Obtener una página

Como probablemente hayas notado en nuestro esqueleto básico anterior, browser.get() devuelve un objeto página. Puedes incluso abrir múltiples páginas simultáneamente. Si estás dispuesto a ser creativo, puedes hacer operaciones altamente concurrentes.

El siguiente fragmento es sólo teórico.

#navigate to a page
page_1 = await browser.get(base_url)
page_2 = await browser.get(a_different_url)

####do stuff with the different pages#####

4. Contenido dinámico

Para manejar contenido dinámico, tienes dos opciones. Puedes usar el método .sleep() para esperar una cantidad arbitraria de tiempo, o puedes usar .wait_for() para esperar un selector específico en la página.

#wait an arbitrary amount of time
await tab.sleep(1)

#wait for a specific element
await tab.wait_for("div[data-testid='some-value']")

NOTA: En el fragmento anterior, he utilizado tab en lugar de page como nombre de variable. Son intercambiables. Ambos son objetos pestaña. Puede aprender más sobre las pestañas en NODRIVER aquí.

5. Encontrar elementos

NODRIVER nos ofrece una variedad de métodos para encontrar elementos en la página. Parece que están en medio de la manipulación de algunos métodos heredados.

Existen cuatro métodos diferentes basados en texto para encontrar elementos. Dos de ellos desaparecerán probablemente en el futuro.

#find an element using its text
my_element = page.find("some text here")

#find a list of elements by their text
my_elements = page.find_all("some text here")

#find an element using its text
my_element = page.find_element_by_text("some text here")

#find a list of elements using their text
my_elements = page.find_element_by_text("some text here")

Al igual que los métodos anteriores, también existen cuatro métodos basados en selectores para encontrar elementos. Dos de ellos probablemente desaparecerán. Si los desarrolladores detrás de NODRIVER quieren alinearse claramente con CDP, los métodos query_selector probablemente sobrevivirán.

#find a single element using its css selector
my_element = page.select("div[class='your-classname']")

#find a list of elements using a css selector
my_elements = page.select_all("div[class='your-classname']") 

#find a single element using its css selector
my_element = page.query_selector("div[class='your-classname']")

#find a list of elements using a css selector
my_elements = page.query_selector_all("div[class='your-classname']") 

Como puedes ver arriba, no importa cómo quieras encontrar elementos en la página, probablemente hay múltiples maneras de hacerlo. Con el tiempo, los desarrolladores de NODRIVER podrían mejorar este aspecto. Dicho esto, por el momento, sus métodos de análisis son como una motosierra del ejército suizo.

6. Extracción de sus datos

NODRIVER ofrece un par de métodos para extraer datos. Puede utilizar el rasgo .attributes para extraer los atributos directamente – esto no es muy fácil de usar – devuelve una matriz, no un objeto JSON.

He aquí un truco que hice para extraer el href de un objeto enlace. Es feo, pero funciona. Espero que el método de atributos sea reemplazado pronto por algo un poco más funcional.

next_button = await page.select("li[class='next'] > a")

#this returns an array
attributes = next_button.attributes

#use array indexing to find the href object and its value
for i in range(len(attributes)):
    if attributes[i] == "href":
        next_url = attributes[i+1]

NOTA: La mayoría de los navegadores headless contienen un método get_attribute(). Sin embargo, este método aún no funciona en NODRIVER.

Así es como extraemos los datos de texto. Como puede notar, no usamos await aquí. Sospecho que esto cambiará en el futuro para alinearse con otros navegadores de estilo CDP. En su forma actual, text es solo un atributo, no un metodo – await lanzara un error cuando se use con atributos. Esto parece contrario a Puppeteer y Playwright, pero este es el estado actual de NODRIVER – todavia en desarrollo.

#find the quote element
quote_element = await quote.query_selector("span[class='text']")
#extract its text
quote_text = quote_element.text

7. Almacenamiento de datos

Almacenaremos nuestros datos en un pequeño archivo JSON. Al extraer citas, cada cita tiene una lista de etiquetas y listas no hacen muy bien en forma CSV.

import json

with open("quotes.json", "w", encoding="utf-8") as f:
    json.dump(scraped_data, f, ensure_ascii=False, indent=4)

8. Poner todo junto

Ahora, pongamos todos estos conceptos juntos en un script de trabajo. En el siguiente ejemplo, utilizamos los conceptos anteriores para extraer datos de Qutoes to Scrape, un sitio creado exclusivamente para tutoriales de scraping. Copia y pega el siguiente código para hacerte una idea de cómo funciona NODRIVER.

import nodriver
import json

async def main():

    #list to hold scraped data
    scraped_data = []


    browser = await nodriver.start()

    next_url = "/"

    base_url = "https://quotes.toscrape.com"

    #while we still have urls to scrape
    while next_url:

        #go to the page
        page = await browser.get(f"{base_url}{next_url}")

        #find quote divs using a selector
        quotes = await page.select_all("div[class='quote']")

        #iterate through the quotes
        for quote in quotes:

            #find the quote element and extract its text
            quote_element = await quote.query_selector("span[class='text']")
            quote_text = quote_element.text

            #find the author and extract the text
            author_element = await quote.query_selector("small[class='author']")
            author = author_element.text

            #find the tag elements
            tag_elements = await quote.query_selector_all("a[class='tag']")
            tags = []

            #iterate through the tags and extract their text
            for tag_element in tag_elements:
                text = tag_element.text
                tags.append(text)

            #add our extracted data to the list of scraped data
            scraped_data.append({
                "quote": quote_text,
                "author": author,
                "tags": tags
            })

        #check the page for a "next" button
        next_button = await page.select("li[class='next'] > a")

        #if it doesn't exist, close the browser and break the loop
        if next_button == None:
            await page.close()
            next_url = None

        #if it does, follow this block instead
        else:
            attributes = next_button.attributes

            #loop through the attributes to find your desired attribute, its value is the next index
            for i in range(len(attributes)):
                if attributes[i] == "href":
                    next_url = attributes[i+1]

    #write the data to a json file
    with open("quotes.json", "w", encoding="utf-8") as f:
        json.dump(scraped_data, f, ensure_ascii=False, indent=4)


if __name__ == '__main__':

    nodriver.loop().run_until_complete(main())

Si ejecutas el script anterior, obtendrás un archivo JSON con objetos como los que ves a continuación.

[
    {
        "quote": "“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”",
        "author": "Albert Einstein",
        "tags": [
            "change",
            "deep-thoughts",
            "thinking",
            "world"
        ]
    },
    {
        "quote": "“It is our choices, Harry, that show what we truly are, far more than our abilities.”",
        "author": "J.K. Rowling",
        "tags": [
            "abilities",
            "choices"
        ]
    },

Limitaciones actuales de NODRIVER

Actualmente, NODRIVER tiene algunas limitaciones importantes que vale la pena señalar. Vamos a repasarlas.

Modo sin cabeza

NODRIVER lanza un error cada vez que lo ejecutamos en modo headless. No estamos seguros de si esto es intencional (como una derivación antibot) o un problema legítimo.

Se muestra un rastreo de error de Python en una ventana de terminal, indicando un error de profundidad de recursión máxima excedida en un script Nodriver, con rutas de archivo y números de línea referenciados. El error sugiere problemas con la preparación de una sesión sin cabeza y el envío de una solicitud única.

Página Interacciones

Aunque NODRIVER tiene numerosas interacciones de página listadas en su documentación, la mayoría de ellas o funcionan parcialmente – o no funcionan en absoluto. Como puedes ver, esto está documentado en la captura de pantalla de abajo tanto para click_mouse() como para mouse_click().

Fragmento de código que muestra los parámetros y el uso de las funciones async mouse_click y click_mouse, incluyendo detalles sobre la selección de botones, teclas modificadoras y un evento interno de espera.

Extracción de atributos

El mayor problema de NODRIVER es la extracción de atributos. Como se mencionó antes, esto produce un array y es extremadamente arcaico como se vio en nuestra solución href. Esta es la salida literal del atributo. Para la producción a nivel de raspado, esto debe ser abordado.

Un fragmento de código que muestra un atributo de hipervínculo con el valor '/page/2/' en formato de matriz.

Uso del proxy con NODRIVER

Actualmente, el soporte de proxy para NODRIVER es limitado en el mejor de los casos. Proporcionan un método create_context() para la conexión proxy.

El siguiente fragmento procede directamente de su página de problemas. Sin embargo, tras horas probando este y otros métodos, seguía sin poder conectarme.

tab = await  browser.create_context("https://www.google.nl", proxy_server='socks5://myuser:mypass@somehost')

# or add  new_window=True if you would like a new window

Si miras su documentación, tienen una sección sobre proxies[1]. Aunque hay una sección oficial sobre proxies, no hay documentación real. Suponemos que esto se arreglará en un futuro próximo.

Alternativas viables

Aunque actualmente no está listo para su uso en producción, espero grandes cosas de NODRIVER en el futuro. Si buscas algo más potente, echa un vistazo a los navegadores que aparecen a continuación.

  • Selenio: Fuerte desde 2004. Selenium depende de Chromedriver, pero está probado en batalla y listo para producción. Más información sobre Selenium web scraping.
  • Playwright: Playwright parece una versión pulida y lista para usar de lo que has visto en este tutorial con NODRIVER. Aprende a utilizar Playwright para el web scraping.

Conclusión

NODRIVER es una herramienta nueva y apasionante para la automatización de navegadores, pero su rápido desarrollo implica que algunas funciones aún están madurando. Para el raspado web fiable a gran escala, considere el uso de soluciones robustas como:

Solicite una prueba gratuita y empiece hoy mismo.

No se requiere tarjeta de crédito