
Successore di Undetected-Chromedriver. Fornisce un framework estremamente veloce per automazione web, web scraping, bot e qualsiasi altra idea creativa che normalmente viene ostacolata da fastidiosi sistemi anti-bot come Captcha / CloudFlare / Imperva / hCaptcha
La comunicazione diretta offre una resistenza ancora maggiore contro i firewall per applicazioni web (WAF), mentre le prestazioni ricevono un enorme incremento. Questo modulo, a differenza di undetected-chromedriver, è completamente asincrono.
Ciò che rende questo pacchetto diverso dagli altri pacchetti noti è l'ottimizzazione per rimanere non rilevato dalla maggior parte delle soluzioni anti-bot.
Un altro punto focale è l'usabilità e il prototyping rapido, quindi aspettati che molte cose funzionino -così come sono-,
con la maggior parte dei parametri dei metodi che hanno valori predefiniti di best practice.
Con 1 o 2 righe, è operativo, fornendo una configurazione best practice
per impostazione predefinita. Pulisce i file creati (profilo) in seguito.
Funziona con
Sebbene l'usabilità e la comodità siano importanti, è anche facile personalizzare completamente tutto utilizzando l'intera gamma di domini, metodi ed eventi CDP disponibili.
Nessuna dipendenza da chromedriver binario o Selenium
Operativo in 1 riga di codice*
Utilizza un profilo nuovo a ogni esecuzione, pulisce all'uscita
Salva e carica i cookie su file per non ripetere fastidiosi passaggi di login
tab.find("sometext")
tab.find_all("sometext")
tab.select("a[class*=something]")
tab.select_all("a[href] > div > img")
Ricerca intelligente ed efficiente degli elementi, per selettore o testo, inclusi i contenuti degli iframe.
Può anche essere utilizzata come condizione di attesa per la comparsa di un elemento, poiché riproverà
per la durata di finché non viene trovato. Quindi un await tab.select('body') potrebbe essere usato
come indicatore del caricamento della pagina.
Il metodo find cerca per testo, ma non restituirà ingenuamente il primo
elemento corrispondente, ma confronterà i candidati in base alla lunghezza del testo più vicina (vince il più corto),
questo fa sì che ricerche come tab.find('accept all') restituiscano il pulsante effettivo dei cookie invece di
uno script nelle intestazioni
Può connettersi a una sessione di debug di Chrome in esecuzione
__repr__ descrittivo per gli elementi, che rappresentano l'elemento come HTML
Funzione di utilità per convertire un'istanza Chrome di undetected_chromedriver in esecuzione in un'istanza Browser di nodriver e continuare da lì
Ricco di helper e metodi di utilità per le operazioni più utilizzate e importanti
Parti sono state riscritte per utilizzare connessioni flat nel protocollo.
Perché?
- gli iframe sono inclusi nella maggior parte delle operazioni.
- tab ha un nuovo metodo: await tab.get_frames()
che restituirà Iframe ispezionabili.
- find() includerà gli iframe, quindi puoi persino cercare "verify you are human" e
fare clic sulla casella di verifica nelle sfide JS.
Poiché ciò ha richiesto parecchie riscritture, si prega di testare accuratamente, specialmente se si eseguono progetti grandi.
tab.xpath(selector, timeout=2.5)trova i nodi utilizzando il selettore xpath! vedi tab xpath nella documentazione API
tab.cf_verify()trova la casella di controllo e la clicca con successo funziona solo quando NON si è in modalità esperto. attualmente integrato solo in inglese richiede l'installazione del pacchetto opencv-python
tab.bypass_insecure_connection_warning()metodo di comodo, per l'avviso di pagina non sicura. ad esempio quando un certificato non è valido.
tab.open_external_debugger()ti permette di ispezionare la scheda senza interrompere la connessione
tab.get_local_storage()ottieni il contenuto di localStorage
tab.set_local_storage(dict)imposta il contenuto di localStorage
tab.add_handler(someEvent, callback)il callback può accettare un singolo argomento (evento) o 2 argomenti (evento, tab).
start(expert=True)fa qualche trucco per utenti più esperti. Disabilita la sicurezza web e gli origin-trials, e garantisce che le shadow-root siano sempre aperte. Questo però ti rende più rilevabile!
devi avere chrome (o qualche browser basato su chromium) installato preferibilmente nella posizione predefinita sulla macchina dove usi questo pacchetto.
quando si esegue su una macchina headless, come AWS o qualsiasi altro ambiente dove non è presente un display, è meglio utilizzare uno strumento Xvfb per emulare uno schermo. in alternativa, questo pacchetto può essere utilizzato in modalità headless.
pip install nodriver
pip install -U nodriver
L'obiettivo di questo progetto (proprio come undetected-chromedriver, molto tempo fa) è mantenerlo breve e semplice, così puoi aprire rapidamente un editor o una sessione interattiva, digitare o incollare poche righe e via.
import nodriver as uc
async def main():
browser = await uc.start()
page = await browser.get('https://www.nowsecure.nl')
... ulteriore codice ...
if __name__ == '__main__':
# poiché asyncio.run non ha mai funzionato (per me)
uc.loop().run_until_complete(main())
Tralascerò qui il boilerplate asincrono
from nodriver import *
browser = await start(
headless=False,
user_data_dir="/path/to/existing/profile", # specificandolo, non verrà ripulito automaticamente al termine
browser_executable_path="/path/to/some/other/browser",
browser_args=['--some-browser-arg=true', '--some-other-option'],
lang="en-US" # questo potrebbe impostare il codice lingua ISO nel navigator, non consigliato cambiarlo
)
tab = await browser.get('https://somewebsite.com')
Tralascerò qui il boilerplate asincrono
from nodriver import *
config = Config()
config.headless = False
config.user_data_dir="/path/to/existing/profile", # specificandolo, non verrà ripulito automaticamente al termine
config.browser_executable_path="/path/to/some/other/browser",
config.browser_args=['--some-browser-arg=true', '--some-other-option'],
config.lang="en-US" # questo potrebbe impostare il codice lingua ISO nel navigator, non consigliato cambiarlo
)
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 # attendi che gli eventi vengano elaborati
await p.reload()
if p != page3:
await p.close()
if __name__ == '__main__':
# poiché asyncio.run non ha mai funzionato (per me)
uc.loop().run_until_complete(main())
automazione della creazione di un account Twitter/X
Un esempio più concreto, che si trova nella cartella ./example/,
mostra uno script per creare un account twitter
```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")
# attendi che appaia il testo invece di un numero statico di secondi da attendere
# questo non sempre funziona come previsto, a causa della velocità.
print('trovando il pulsante "create account"')
create_account = await tab.find("create account", best_match=True)
print('"create account" => clicca')
await create_account.click()
print("trovando il campo di input email")
email = await tab.select("input[type=email]")
# a volte, il campo email non viene mostrato, perché viene chiesto invece il telefono
# quando ciò accade, trova il testo piccolo che dice "use email instead"
if not email:
use_mail_instead = await tab.find("use email instead")
# e cliccaci
await use_mail_instead.click()
# ora trova di nuovo il campo email
email = await tab.select("input[type=email]")
randstr = lambda k: "".join(random.choices(string.ascii_letters, k=k))
# invia i tasti al campo email
print('riempiendo il campo input "email"')
await email.send_keys("".join([randstr(8), "@", randstr(8), ".com"]))
# trova il campo input nome
print("trovando il campo input nome")
name = await tab.select("input[type=text]")
# ancora, invia testo casuale
print('riempiendo il campo input "nome"')
await name.send_keys(randstr(8))
# poiché ci sono 3 campi select sulla scheda, possiamo usare l'unpacking
# per assegnare ciascun campo
print('trovando i campi "mese", "giorno" e "anno" in 1 colpo')
sel_month, sel_day, sel_year = await tab.select_all("select")
# await sel_month.focus()
print('riempiendo il campo input "mese"')
await sel_month.send_keys(months[random.randint(0, 11)].title())
# await sel_day.focus()
# non voglio preoccuparmi della lunghezza dei mesi e degli anni bisestili
print('riempiendo il campo input "giorno"')
await sel_day.send_keys(str(random.randint(0, 28)))
# await sel_year.focus()
# non voglio preoccuparmi delle restrizioni di età
print('riempiendo il campo input "anno"')
await sel_year.send_keys(str(random.randint(1980, 2005)))
await tab
# gestiamo anche il fastidio dei cookie
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("dormendo 2 secondi")
await tab.sleep(2) # vedi visivamente in quale parte ci troviamo
print('trovando il pulsante "next"')
next_btn = await tab.find(text="next", best_match=True)
print('cliccando il pulsante "next"')
await next_btn.mouse_click()
# attendi un pulsante qualsiasi, prima di continuare
await tab.select("[role=button]")
print('trovando il pulsante "sign up"')
sign_up_btn = await tab.find("Sign up", best_match=True)
# abbiamo bisogno del secondo
print('cliccando il pulsante "sign up"')
await sign_up_btn.click()
print('il resto della "implementazione" è fuori dallo scopo')
# ulteriore implementazione fuori dallo scopo
await tab.sleep(10)
driver.stop()
# codice di verifica via email
if __name__ == "__main__":
# poiché asyncio.run non ha mai funzionato (per me)
# uso
uc.loop().run_until_complete(main())