
Преемник Undetected-Chromedriver. Предоставляет молниеносно быстрый фреймворк для веб-автоматизации, веб-скрапинга, ботов и любых других творческих идей, которым обычно препятствуют раздражающие антибот-системы, такие как Captcha / CloudFlare / Imperva / hCaptcha.
Прямое взаимодействие обеспечивает ещё лучшую устойчивость к межсетевым экранам веб-приложений (WAF), при этом производительность получает огромный прирост. Этот модуль, в отличие от undetected-chromedriver, полностью асинхронный.
Что отличает этот пакет от других известных пакетов, так это оптимизация, позволяющая оставаться незамеченным для большинства антибот-решений.
Ещё один акцент — удобство использования и быстрое прототипирование, поэтому рассчитывайте, что многое работает -as is-,
а большинство параметров методов имеют значения по умолчанию из best practice.
Одна-две строки — и всё запущено с оптимальной конфигурацией по умолчанию. Затем он очищает созданные файлы (профиль).
Известно, что работает с
Несмотря на важность удобства и практичности, также легко полностью настроить всё, используя весь массив доступных CDP доменов, методов и событий.
Нет зависимости от бинарника chromedriver или Selenium
Запуск одной строкой кода*
Использует свежий профиль при каждом запуске, очищает его при выходе
Сохраняет cookie в файл и загружает их, чтобы не повторять утомительные шаги входа
tab.find("sometext")
tab.find_all("sometext")
tab.select("a[class*=something]")
tab.select_all("a[href] > div > img")
умный и производительный поиск элементов по селектору или тексту, включая содержимое iframe.
это также можно использовать как условие ожидания появления элемента, так как поиск будет повторяться
в течение , пока элемент не будет найден. поэтому await tab.select('body') можно использовать
как индикатор загрузки страницы.
метод find ищет по тексту, но не будет наивно возвращать первый подходящий
элемент, а выберет среди кандидатов по наиболее близкой длине текста (побеждает самый короткий),
поэтому такие запросы, как tab.find('accept all'), возвращают реальную кнопку cookie вместо
скрипта в шапке страницы
может подключаться к запущенной отладочной сессии chrome
описательный __repr__ для элементов, который представляет элемент в виде html
утилита для преобразования запущенного экземпляра undetected_chromedriver.Chrome в экземпляр nodriver.Browser и продолжения работы с него
укомплектован вспомогательными и утилитарными методами для наиболее используемых и важных операций
Части кода переписаны для использования flat-соединений в протоколе.
Почему?
- iframes включены в большинство операций.
- у tab появился новый метод: await tab.get_frames()
который возвращает Iframes, доступные для инспекции.
- find() будет учитывать iframe, так что вы можете даже искать "verify you are human" и
нажимать чекбокс верификации в js-задачах.
Поскольку это потребовало довольно серьёзной переработки, пожалуйста, тщательно протестируйте, особенно если вы запускаете большие проекты.
tab.xpath(selector, timeout=2.5)находит узлы с помощью xpath-селектора! см. tab xpath в документации api
tab.cf_verify()находит чекбокс и успешно нажимает его работает только НЕ в экспертном режиме. в настоящее время встроен только английский язык требует установки пакета opencv-python
tab.bypass_insecure_connection_warning()удобный метод для обхода предупреждения о небезопасной странице. например, когда сертификат недействителен.
tab.open_external_debugger()позволяет инспектировать вкладку, не разрывая ваше соединение
tab.get_local_storage()получить содержимое localstorage
tab.set_local_storage(dict)установить содержимое localstorage
tab.add_handler(someEvent, callback)callback может принимать один аргумент (event) или 2 аргумента (event, tab).
start(expert=True)делает некоторые ухищрения для более опытных пользователей. Он отключает веб-безопасность и origin-trials, а также гарантирует, что shadow-roots всегда открыты. Однако это делает вас более заметными!
вам нужен установленный chrome (или любой браузер на основе chromium), желательно в стандартном расположении, на машине, где вы используете этот пакет.
При запуске на headless-машине, например AWS или в любой другой среде без дисплея, лучше всего использовать какой-либо инструмент Xvfb для эмуляции экрана. В качестве альтернативы этот пакет можно использовать в headless-режиме.
pip install nodriver
pip install -U nodriver
Цель этого проекта (как и undetected-chromedriver когда-то давно) — оставаться кратким и простым, чтобы вы могли быстро открыть редактор или интерактивную сессию, набрать или вставить несколько строк — и вперёд.
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())
Здесь я опущу асинхронный шаблонный код
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')
Здесь я опущу асинхронный шаблонный код
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())
автоматизация создания учётной записи 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())