
Successeur d'Undetected-Chromedriver. Fournissant un framework ultra-rapide pour l'automatisation web, le web scraping, les bots et toute autre idée créative qui est normalement entravée par des systèmes anti-bot agaçants comme Captcha / CloudFlare / Imperva / hCaptcha
La communication directe offre une résistance encore meilleure contre les pare-feu d'applications web (WAF), tout en offrant un énorme gain de performances. Ce module est, contrairement à undetected-chromedriver, entièrement asynchrone.
Ce qui rend ce package différent des autres packages connus, c'est l'optimisation pour rester indétecté face à la plupart des solutions anti-bot.
Un autre point d'attention est la convivialité et le prototypage rapide, attendez-vous donc à ce que beaucoup de choses fonctionnent -tel quel-, la plupart des paramètres de méthode ayant des valeurs par défaut de bonnes pratiques.
Avec 1 ou 2 lignes, c'est opérationnel, fournissant une configuration de bonnes pratiques par défaut. Il nettoie les fichiers créés (profil) par la suite.
connu pour fonctionner avec
Bien que la convivialité et la commodité soient importantes. Il est également facile de tout personnaliser entièrement en utilisant l'ensemble des domaines, méthodes et événements CDP disponibles.
Aucune dépendance au binaire chromedriver ou à Selenium
Opérationnel en 1 ligne de code*
utilise un profil frais à chaque exécution, nettoie à la sortie
sauvegarde et charge les cookies dans un fichier pour éviter de répéter les étapes de connexion fastidieuses
tab.find("sometext")
tab.find_all("sometext")
tab.select("a[class*=something]")
tab.select_all("a[href] > div > img")
recherche d'élément intelligente et performante, par sélecteur ou texte, y compris le contenu des iframes.
cela peut également être utilisé comme condition d'attente pour l'apparition d'un élément, car il réessaiera pendant la durée de jusqu'à ce qu'il soit trouvé. donc un await tab.select('body') pourrait être utilisé comme indicateur pour savoir si une page est chargée.
la méthode find recherche par texte, mais ne renverra pas naïvement le premier élément correspondant, mais fera correspondre les candidats par la longueur de texte la plus proche (le plus court gagne), cela fait que les recherches comme tab.find('accept all') renvoient le vrai bouton de cookie au lieu d'un script dans les en-têtes.
peut se connecter à une session de débogage chrome en cours d'exécution
__repr__ descriptif pour les éléments, qui représente l'élément en html
fonction utilitaire pour convertir une instance undetected_chromedriver.Chrome en cours d'exécution en une instance nodriver.Browser et continuer à partir de là
rempli d'helpers et de méthodes utilitaires pour les opérations les plus utilisées et importantes
Certaines parties ont été réécrites pour utiliser des connexions plates dans le protocole.
Pourquoi ?
- les iframes sont inclus dans la plupart des opérations.
- l'onglet a une nouvelle méthode : await tab.get_frames()
qui retournera les Iframes qui sont inspectables.
- find() inclura les iframes, vous pouvez donc même rechercher "verify you are human" et
cliquer sur la case de vérification dans les défis js.
Comme cela a nécessité pas mal de réécriture, veuillez tester minutieusement, surtout si vous exécutez de gros projets.
tab.xpath(selector, timeout=2.5)trouver des nœuds en utilisant le sélecteur xpath ! voir tab xpath dans la documentation de l'api
tab.cf_verify()trouve la case à cocher et clique dessus avec succès cela ne fonctionne que lorsque PAS en mode expert. actuellement intégré en anglais uniquement nécessite que le package opencv-python soit installé
tab.bypass_insecure_connection_warning()méthode de commodité, pour l'avertissement de page non sécurisée. par exemple lorsque un certificat est invalide.
tab.open_external_debugger()vous permet d'inspecter l'onglet sans casser votre connexion
tab.get_local_storage()obtenir le contenu du localstorage
tab.set_local_storage(dict)définir le contenu du localstorage
tab.add_handler(someEvent, callback)le callback peut accepter un seul argument (event), ou 2 arguments (event, tab).
start(expert=True)fait quelques hacks pour les utilisateurs plus expérimentés. Il désactive la sécurité web et les origin-trials, et garantit que les shadow-roots sont toujours ouverts. Cela vous rend plus détectable cependant !
vous avez besoin de chrome (ou d'un navigateur basé sur chromium) installé de préférence à l'emplacement par défaut sur la machine où vous utilisez ce package.
lors de l'exécution sur une machine headless, comme AWS ou tout autre environnement où aucun affichage n'est présent, il est préférable d'utiliser un outil Xvfb, pour émuler un écran. alternativement, ce package peut être utilisé en mode headless.
pip install nodriver
pip install -U nodriver
L'objectif de ce projet (tout comme undetected-chromedriver, il y a longtemps) est de le garder court et simple, afin que vous puissiez rapidement ouvrir un éditeur ou une session interactive, taper ou coller quelques lignes et c'est parti.
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())
Je vais laisser de côté le code standard asynchrone ici
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')
Je vais laisser de côté le code standard asynchrone ici
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())
automatisation de la création de compte 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())