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.
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()
.
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.
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:
- Proxies residenciales: Conexiones de dispositivos reales para eludir los geobloqueos.
- Desbloqueador Web: Proxies gestionados con solucionador CAPTCHA incorporado.
- Navegador de raspado: Automatización remota del navegador con proxy y soporte CAPTCHA. La solución perfecta para proyectos de scraping de varios pasos.
- Raspador personalizado: Ejecute trabajos de raspado personalizados sin necesidad de código y con extracción de datos asistida por expertos.
Solicite una prueba gratuita y empiece hoy mismo.
No se requiere tarjeta de crédito