
Sucesor de Undetected-Chromedriver. Proporciona un framework ultrarrápido para automatización web, web scraping, bots y cualquier otra idea creativa que normalmente se ve obstaculizada por molestos sistemas anti-bots como Captcha / CloudFlare / Imperva / hCaptcha.
La comunicación directa proporciona una resistencia aún mejor contra los cortafuegos de aplicaciones web (WAF), mientras que el rendimiento recibe un enorme impulso. Este módulo es, a diferencia de undetected-chromedriver, completamente asíncrono.
Lo que hace diferente a este paquete de otros paquetes conocidos es la optimización para pasar desapercibido ante la mayoría de las soluciones anti-bot.
Otro punto clave es la usabilidad y la creación rápida de prototipos, así que espera que muchas cosas funcionen -tal cual-, con la mayoría de los parámetros de métodos con valores predeterminados de mejores prácticas.
Con 1 o 2 líneas, esto está en funcionamiento, proporcionando una configuración de mejores prácticas por defecto. Además, limpia los archivos creados (perfil) al finalizar.
Se sabe que funciona con
Aunque la usabilidad y la conveniencia son importantes, también es fácil personalizar completamente todo usando toda la gama de dominios, métodos y eventos de CDP disponibles.
Sin dependencia del binario chromedriver ni de Selenium
En funcionamiento en 1 línea de código*
Utiliza un perfil nuevo en cada ejecución y limpia al salir
Guarda y carga cookies en un archivo para no repetir tediosos pasos de inicio de sesión
tab.find("sometext")
tab.find_all("sometext")
tab.select("a[class*=something]")
tab.select_all("a[href] > div > img")
búsqueda de elementos inteligente y eficiente, por selector o texto, incluido el contenido de iframes.
esto también se puede usar como condición de espera para que aparezca un elemento, ya que reintentará
durante la duración de hasta que lo encuentre. así que un await tab.select('body') podría usarse
como indicador de si una página está cargada.
el método find busca por texto, pero no devolverá ingenuamente el primer
elemento coincidente, sino que comparará candidatos por la longitud de texto coincidente más cercana (gana la más corta),
esto hace que búsquedas como tab.find('accept all') devuelvan el botón real de cookies en lugar de
un script en las cabeceras
puede conectarse a una sesión de depuración de chrome en ejecución
__repr__ descriptivo para elementos, que representa el elemento como html
función de utilidad para convertir una instancia de undetected_chromedriver.Chrome en ejecución a una instancia de nodriver.Browser y continuar desde ahí
lleno de ayudantes y métodos de utilidad para las operaciones más usadas e importantes
Partes han sido reescritas para usar conexiones planas en el protocolo.
¿Por qué?
- los iframes están incluidos en la mayoría de las operaciones.
- tab tiene un nuevo método: await tab.get_frames()
que devolverá Iframes que son inspeccionables.
- find() incluirá iframes, por lo que incluso puedes buscar "verify you are human" y
hacer clic en la casilla de verificación en los desafíos js.
Dado que esto requirió bastante reescritura, por favor prueba a fondo, especialmente si ejecutas proyectos grandes.
tab.xpath(selector, timeout=2.5)¡encuentra nodos usando el selector xpath! consulta tab xpath en la documentación de la API
tab.cf_verify()encuentra la casilla de verificación y haz clic en ella con éxito esto solo funciona cuando NO estás en modo experto. actualmente solo incluye inglés integrado requiere que el paquete opencv-python esté instalado
tab.bypass_insecure_connection_warning()método de conveniencia, para la advertencia de página insegura. por ejemplo cuando un certificado no es válido.
tab.open_external_debugger()te permite inspeccionar la pestaña sin romper tu conexión
tab.get_local_storage()obtén el contenido de localstorage
tab.set_local_storage(dict)establece el contenido de localstorage
tab.add_handler(someEvent, callback)el callback puede aceptar un solo argumento (evento), o 2 argumentos (evento, tab).
start(expert=True)hace algunos trucos para usuarios más experimentados. Desactiva la seguridad web y los origin-trials, además de asegurar que las shadow-roots estén siempre abiertas. ¡Esto te hace más detectable!
necesitas tener chrome (o algún navegador basado en chromium) instalado preferiblemente en la ubicación predeterminada en la máquina donde uses este paquete.
cuando se ejecuta en una máquina sin pantalla, como AWS o cualquier otro entorno donde no haya pantalla, es mejor usar alguna herramienta Xvfb para emular una pantalla. alternativamente, este paquete se puede usar en modo headless.
pip install nodriver
pip install -U nodriver
El objetivo de este proyecto (al igual que undetected-chromedriver, en algún momento lejano) es mantenerlo corto y simple, para que puedas abrir rápidamente un editor o una sesión interactiva, escribir o pegar unas pocas líneas y listo.
import nodriver as uc
async def main():
browser = await uc.start()
page = await browser.get('https://www.nowsecure.nl')
... further code ...
if __name__ == '__main__':
# since asyncio.run never worked (for me)
uc.loop().run_until_complete(main())
Omitiré el código repetitivo async aquí
from nodriver import *
browser = await start(
headless=False,
user_data_dir="/path/to/existing/profile", # by specifying it, it won't be automatically cleaned up when finished
browser_executable_path="/path/to/some/other/browser",
browser_args=['--some-browser-arg=true', '--some-other-option'],
lang="en-US" # this could set iso-language-code in navigator, not recommended to change
)
tab = await browser.get('https://somewebsite.com')
Omitiré el código repetitivo async aquí
from nodriver import *
config = Config()
config.headless = False
config.user_data_dir="/path/to/existing/profile", # by specifying it, it won't be automatically cleaned up when finished
config.browser_executable_path="/path/to/some/other/browser",
config.browser_args=['--some-browser-arg=true', '--some-other-option'],
config.lang="en-US" # this could set iso-language-code in navigator, not recommended to change
)
import nodriver
async def main():
browser = await nodriver.start()
page = await browser.get('https://www.nowsecure.nl')
await page.save_screenshot()
await page.get_content()
await page.scroll_down(150)
elems = await page.select_all('*[src]')
for elem in elems:
await elem.flash()
page2 = await browser.get('https://twitter.com', new_tab=True)
page3 = await browser.get('https://github.com/ultrafunkamsterdam/nodriver', new_window=True)
for p in (page, page2, page3):
await p.bring_to_front()
await p.scroll_down(200)
await p # wait for events to be processed
await p.reload()
if p != page3:
await p.close()
if __name__ == '__main__':
# since asyncio.run never worked (for me)
uc.loop().run_until_complete(main())
automatizando la creación de cuentas de Twitter/X
A more concrete example, which can be found in the ./example/ folder,
shows a script to create a twitter account
```python
import random
import string
import logging
logging.basicConfig(level=30)
import nodriver as uc
months = [
"january",
"february",
"march",
"april",
"may",
"june",
"july",
"august",
"september",
"october",
"november",
"december",
]
async def main():
driver = await uc.start()
tab = await driver.get("https://twitter.com")
# wait for text to appear instead of a static number of seconds to wait
# this does not always work as expected, due to speed.
print('finding the "create account" button')
create_account = await tab.find("create account", best_match=True)
print('"create account" => click')
await create_account.click()
print("finding the email input field")
email = await tab.select("input[type=email]")
# sometimes, email field is not shown, because phone is being asked instead
# when this occurs, find the small text which says "use email instead"
if not email:
use_mail_instead = await tab.find("use email instead")
# and click it
await use_mail_instead.click()
# now find the email field again
email = await tab.select("input[type=email]")
randstr = lambda k: "".join(random.choices(string.ascii_letters, k=k))
# send keys to email field
print('filling in the "email" input field')
await email.send_keys("".join([randstr(8), "@", randstr(8), ".com"]))
# find the name input field
print("finding the name input field")
name = await tab.select("input[type=text]")
# again, send random text
print('filling in the "name" input field')
await name.send_keys(randstr(8))
# since there are 3 select fields on the tab, we can use unpacking
# to assign each field
print('finding the "month" , "day" and "year" fields in 1 go')
sel_month, sel_day, sel_year = await tab.select_all("select")
# await sel_month.focus()
print('filling in the "month" input field')
await sel_month.send_keys(months[random.randint(0, 11)].title())
# await sel_day.focus()
# i don't want to bother with month-lengths and leap years
print('filling in the "day" input field')
await sel_day.send_keys(str(random.randint(0, 28)))
# await sel_year.focus()
# i don't want to bother with age restrictions
print('filling in the "year" input field')
await sel_year.send_keys(str(random.randint(1980, 2005)))
await tab
# let's handle the cookie nag as well
cookie_bar_accept = await tab.find("accept all", best_match=True)
if cookie_bar_accept:
await cookie_bar_accept.click()
await tab.sleep(1)
next_btn = await tab.find(text="next", best_match=True)
# for btn in reversed(next_btns):
await next_btn.mouse_click()
print("sleeping 2 seconds")
await tab.sleep(2) # visually see what part we're actually in
print('finding "next" button')
next_btn = await tab.find(text="next", best_match=True)
print('clicking "next" button')
await next_btn.mouse_click()
# just wait for some button, before we continue
await tab.select("[role=button]")
print('finding "sign up" button')
sign_up_btn = await tab.find("Sign up", best_match=True)
# we need the second one
print('clicking "sign up" button')
await sign_up_btn.click()
print('the rest of the "implementation" is out of scope')
# further implementation outside of scope
await tab.sleep(10)
driver.stop()
# verification code per mail
if __name__ == "__main__":
# since asyncio.run never worked (for me)
# i use
uc.loop().run_until_complete(main())