• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья SeleniumBase или история о том, как ученик превзошёл учителя

shqnx

RAID-массив
Пользователь
Регистрация
02.02.2024
Сообщения
58
Реакции
132
Автор: shqnx
Специально для
XSS

Всех рад поприветствовать в данной статье, которая будет посвящена обзору и практическому применению SeleniumBase. Без лишних слов сразу к делу.

Учим матчасть
Что вообще такое SeleniumBase и почему вы, вероятнее всего, о нем не слышали?
Начнем с того, что SeleniumBase - это универсальный Python-фреймворк для автоматизации браузеров, включающий в себя веб-краулинг, скраппинг, тестирование и отчетность.

Мое знакомство с SeleniumBase произошло относительно недавно. Я писал регчекер на ванильном Selenium и столкнулся с рядом проблем, а именно то, что сайт легко детектил использование Selenium и ограничивал возможность войти / попытаться войти в аккаунт. Тогда я начал ресерчить и спустя N-ное количество времени и просмотренных ресурсов совершенно случайно наткнулся на данный фреймворк. Немного разобравшись с документацией я обнаружил замечательный режим, а именно UC-Mode (Undetected-Chromedriver Mode), о котором мы поговорим чуть-чуть позже. Использование этого режима помогло мне все же закончить работу над регчекером, ведь сайт действительно перестал детектить использование каких-либо средств для автоматизации браузера и каждая новая инстанция выглядела для него как абсолютно нормальный человеческий браузер.

Я заметил, что в русскоязычном пространстве мало кто вообще знает о существовании этого инструмента. Либо, по крайней мере, никто не хочет рассказывать о его использовании, не выдавая своих "шеф-поварских" рецептов. Если вы относитесь к данному типу людей, то публично извиняюсь перед вами за раскрытие ваших секретиков, не держите на меня зла =)

Чем SeleniumBase отличается от сырого Selenium?
1. SeleniumBase использует API Selenium/WebDriver и включает в себя прогонщики тестов, такие как pytest, pynose и behave, чтобы обеспечить организованную структуру, обнаружение тестов, их выполнение, состояние тестов (например, пройден, не пройден или пропущен) и опции командной строки для изменения параметров по умолчанию (например, выбор браузера). В сыром Selenium вам придется настроить собственный парсер опций для конфигурирования тестов из командной строки.

2. Менеджер драйверов SeleniumBase дает вам больше контроля над автоматической загрузкой драйверов. По умолчанию SeleniumBase загружает версию драйвера, соответствующую основной версии браузера, если она не задана.

3. SeleniumBase автоматически различает CSS-селекторы и XPath, что означает, что вам не нужно указывать тип селектора в ваших командах (но опционально вы можете).

3. Методы SeleniumBase часто выполняют несколько действий в одном вызове метода. Например, self.type(selector, text) выполняет следующие действия:
1) Ожидает, пока элемент станет видимым.
2) Ожидает, пока элемент станет интерактивным.
3) Очищает текстовое поле.
4) Вводит новый текст.
5) Нажимает Enter/Submit, если текст заканчивается на "\n".
В необработанном Selenium эти действия требуют вызова нескольких методов.

4. SeleniumBase использует значения таймаута по умолчанию, если они не заданы:

self.click("button")
В сыром Selenium методы мгновенно (по умолчанию) завершались, если элементу требовалось больше времени для загрузки:
self.driver.find_element(by="css selector", value="button").click()

5. SeleniumBase позволяет изменять явные значения таймаута методов:
self.click("button", timeout=10)
В сыром Selenium для этого требуется больше кода:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable("css selector", "button")).click()

6. SeleniumBase выводит чистые сообщения об ошибках, когда тест не работает. В необработанном Selenium сообщения об ошибках могут быть очень запутанными.

7. SeleniumBase дает возможность генерировать дэшборды и отчеты по тестам. Он также сохраняет скриншоты неудачных тестов в папке ./latest_logs/. Голый Selenium не имеет этих опций из коробки.

8. SeleniumBase включает в себя настольные приложения с графическим интерфейсом для запуска тестов, такие как SeleniumBase Commander для pytest и SeleniumBase Behave GUI для behave.

9. SeleniumBase имеет свой собственный Recorder / Test Generator для создания тестов из ручных действий браузера.

10. SeleniumBase поставляется с программным обеспечением для управления тестовыми случаями ("CasePlans") для организации тестов и описания шагов.

11. SeleniumBase включает инструменты для создания приложений для работы с данными ("ChartMaker"), которые могут генерировать JavaScript из Python.

Я думаю всем наглядно видно, что SeleniumBase во многом превосходит обыкновенный Selenium и не удивлюсь, если после данной статьи многие (если не все) из тех, кто раньше использовал голый Selenium, пересядут на SeleniumBase =)

Ну а теперь перейдем к сладенькому, а именно к краткому экскурсу по UC-Mode и к практической части использования SeleniumBase в живой природе.

Пробежимся более детально по самому UC-Mode и тому, что он из себя представляет:

SeleniumBase UC Mode (Undetected-Chromedriver Mode) позволяет ботам принимать человеческий облик, что позволяет им избегать обнаружения со стороны антибот-сервисов, которые пытаются их блокировать, или запускать капчу на различных сайтах.

Режим UC Mode основан на undetected-chromedriver, но содержит множество обновлений, исправлений и улучшений для поддержки более широкого спектра функций и побочных ситуаций:
1) Автоматически изменяет юзер агент для предотвращения обнаружения.
2) Поддержка многопоточных параллельных тестов с помощью pytest-xdist.
3) Настраивает некоторые параметры конфигурации в зависимости от окружения.
4) Включает определение и управление версиями драйверов.
5) Имеет опции для настройки прокси и proxy-with-auth.
6) Имеет команды для настройки таймингов по сравнению со значениями по умолчанию.
7) Включает несколько способов структурирования тестовых скриптов.

Что делает UC Mode для того, чтобы боты выглядели как люди?
1) Модифицирует chromedriver для переименования переменных Chrome DevTools Console.
2) Запускает браузеры Chrome перед тем, как к ним подключается chromedriver.
3) Отключает chromedriver от Chrome во время скрытных действий.

Если вы запускаете Chrome с помощью chromedriver, то в настройках будут присутствовать параметры, которые сделают ваш браузер похожим на бота. Вместо этого UC Mode подключает chromedriver к Chrome после запуска браузера, что делает Chrome похожим на обычный веб-браузер, управляемый человеком.

Пока chromedriver подключен к Chrome, службы веб-сайта могут его обнаружить. К счастью, в сыром Selenium уже есть driver.service.stop() для остановки службы chromedriver, driver.service.start() для запуска службы chromedriver и driver.start_session(capabilities) для оживления активной сессии браузера с заданными capabilities. Методы SeleniumBase UC Mode автоматически используют эти необработанные методы Selenium по мере необходимости.

Также обратите внимание, что chromedriver не обнаруживается на вкладке браузера, если он никогда не заходит на эту вкладку. Вот команда JS, которая позволяет открыть URL в новой вкладке (из текущей вкладки):

window.open("URL");

Приведенный выше метод JS используется в методах SeleniumBase UC Mode для скрытого открытия URL-адресов. Поскольку некоторые веб-сайты пытаются определить, является ли ваш браузер ботом при начальной загрузке страницы, это позволяет обойти обнаружение в таких ситуациях. Через несколько секунд (настраиваемых) UC Mode сообщает chromedriver о подключении к этой вкладке, чтобы теперь можно было выполнять автоматические команды. В этот момент chromedriver может быть обнаружен, если веб-сайты ищут его (но обычно веб-сайты ищут его только во время определенных событий, таких как загрузка страницы, отправка формы и нажатие кнопки).

Избежать обнаружения во время клика легко, если запланировать клики на будущее время, когда служба chromedriver будет остановлена. Вот команда JS, позволяющая запланировать события (например, щелчки) на будущее:

window.setTimeout(function() { SCRIPT }, MS);

Приведенный выше JS-метод используется в методе SeleniumBase UC Mode: driver.uc_click(selector), чтобы нажатие было незаметным. UC Mode планирует ваш клик, отключает chromedriver от Chrome, немного ждет (настраивается) и снова подключается.

Практическая часть
А теперь, основываясь на вышеприведенной информации, мы напишем несколько скриптов с использованием Selenium UC Mode:
В качестве подопытного я выбрал сайт vimeo.com
Почтовик взял с сайта disposablemail.com

1) Простой авторегер
Для того, чтобы сделать такой авторегер фактически для любого сайта, нам необходимо посмотреть id необходимых для нас элементов и в целом понимать логику панели входа.
Заходим на страницу регистрации конечного сайта, ищем поле ввода login / email, жмякаем ПКМ и смотрим код:
1711953938103.png

Нас интересует исключительно id инпута, а именно email_login:
1711954085817.png

В данном примере нажатие на Enter эквивалентно нажатию на кнопку "Continue with email", поэтому после ввода email я прописал \n, чтобы эмулировать нажатие на кнопку. На некоторых сайтах это не работает, особенно банки любят делать свои странички входа с невозможностью входа по нажатию Enter. В таком случае придется прописывать отдельно нажатие на кнопку (в следующих примерах это есть, читайте дальше).

Абсолютно аналогично поступаем с другими нужными нам полями.

Python:
from seleniumbase import SB

# Инициализация SeleniumBase
with SB(uc=True) as sb:
    # Задаем URL для регистрации на Vimeo
    url = "https://vimeo.com/join"
    # Открываем браузер и переходим по URL
    sb.driver.get(url)

    # Вводим email для регистрации
    sb.type("#email_login", "trenton.emrick@dockerbike.com\n")
    # Вводим имя пользователя
    sb.type("#name", "John Doe")
    # Вводим пароль для регистрации
    sb.type("#password_login", "XSS_password123\n")
    
    # Проверяем, успешно ли прошла регистрация, ожидая появления указанного текста на странице
    if sb.assert_text("You’re all signed up! Get even more from Vimeo.", timeout=15):
        print("Регистрация прошла успешно.")
    else:
        print("Регистрация не прошла успешно.")

Для открытия браузера и перехода по URL я использовал метод driver.get(), можно также использовать driver.default_get() - это будет быстрее, однако Selenium может быть обнаружен.

2) Простой регчекер

Здесь нам уже придется ожидать появления каких-либо ошибок после ввода некорректных / не валидных данных для входа.
Для этого на помощь приходит метод wait_for_element_visible().
Аналогично тыкаем на ошибку ПКМ и смотрим код:
1711954725328.png

Данная ошибка находится в span-контейнере:
1711954810683.png

Нам необходимо скопировать его класс. Если в классе встречаются пробелы, в нашем скрипте необходимо заменить их на точки. Перед классом идет название элемента. Вот то, что в конечном итоге должно выйти:

span.sc-jRQBWg.gFTdpF.sc-dJjYzT.doitBf

Сейчас мы рассмотрели ошибку, которая появляется при вводе корректных, но не валидных данных.
На сайте Vimeo также присутствует ошибка, которая говорит о том, что мы ввели некорректный email:
1711955006049.png

У данных ошибок один и тот же span с одинаковым классом, поэтому мы не обозначаем ее как-то по-особенному в коде. Однако в других примерах это не обязательно будет точно так же.

Пример с валидными данными после того, как мы запустили наш авторегер из пункта (1):
Python:
from seleniumbase import SB

with SB(uc=True) as sb:
    # URL для страницы входа на Vimeo
    url = "https://vimeo.com/log_in"

    # Открываем страницу входа
    sb.open(url)

    # Вводим email для входа
    sb.type("#email_login", "trenton.emrick@dockerbike.com")

    # Вводим пароль для входа
    sb.type("#password_login", "XSS_password123\n")

    try:
        # Ожидаем появления элемента, указывающего на не валидный аккаунт
        sb.wait_for_element_visible("span.sc-jRQBWg.gFTdpF.sc-dJjYzT.doitBf", timeout=5)

        # Выводим сообщение, что аккаунт не является валидным
        print("Аккаунт не является валидным.")

    except:
        # Если элемент не был найден (аккаунт валиден), выводим сообщение о валидности аккаунта
        print("Аккаунт является валидным.")

Пример с не валидными данными после того, как мы запустили наш авторегер из пункта (1):
Python:
from seleniumbase import SB

with SB(uc=True) as sb:
    # URL для страницы входа на Vimeo
    url = "https://vimeo.com/log_in"

    # Открываем страницу входа
    sb.open(url)

    # Вводим email для входа
    sb.type("#email_login", "trenton.emrick@dockerbike.com")

    # Вводим пароль для входа
    sb.type("#password_login", "XSS_password12345\n")

    try:
        # Ожидаем появления элемента, указывающего на не валидный аккаунт
        sb.wait_for_element_visible("span.sc-jRQBWg.gFTdpF.sc-dJjYzT.doitBf", timeout=5)

        # Выводим сообщение, что аккаунт не является валидным
        print("Аккаунт не является валидным.")

    except:
        # Если элемент не был найден (аккаунт валиден), выводим сообщение о валидности аккаунта
        print("Аккаунт является валидным.")

3) Не настолько простой авторегер
Сейчас я хочу сделать авторегер, который будет для каждого нового аккаунта автоматически брать новую почту с disposablemail.com, а также генерировать уникальный пароль и записывать все полученные аккаунты в файл vimeo.txt.

Тут реализовано нажатие на кнопку посредствами SeleniumBase в качестве примера, суть фактически такая же, как и с инпутами, думаю не стоит это объяснять в очередной раз.

Приступим:
Python:
import time
import random
import string
from seleniumbase import SB

def generate_password():
    # Генерация пароля по требованиям Vimeo
    special_chars = string.punctuation
    all_chars = string.ascii_letters + string.digits + special_chars
    password = random.choice(string.ascii_letters)  # Выбор случайной буквы
    password += random.choice(string.digits)  # Выбор случайной цифры
    password += random.choice(special_chars)  # Выбор случайного спец. символа
    password += ''.join(random.choice(all_chars) for _ in range(5))  # Добавление 5 случайных символов
    return ''.join(random.sample(password, len(password)))  # Перемешивание символов и возврат пароля

def get_temp_email():
    # Получаем временный email
    with SB(uc=True) as sb:
        sb.open("https://www.disposablemail.com/")
        temp_email = sb.get_text("#email.animace")  # Парсим ящик
    return temp_email.strip()  # Удаление лишних пробелов

def save_to_file(email, password):
    # Сохранение email и пароля в файл
    with open("vimeo.txt", "a") as file:
        file.write(f"{email}:{password}\n")  # Запись email и пароля в файл

def register_vimeo_account(email, password):
    # Регистрация аккаунта на Vimeo
    with SB(uc=True) as sb:
        sb.open("https://vimeo.com/join")  # Открытие страницы регистрации Vimeo
        sb.type("#email_login", email)  # Ввод временного email
        sb.click("button.sc-hKwDye.VlVUN.sc-12pmyy6-0.hQugVo")  # Клик по кнопке Continue with email
        sb.type("#name", "John Doe")  # Ввод имени пользователя
        sb.type("#password_login", password)  # Ввод пароля
        sb.click("button.sc-hKwDye.ftUpkC.sc-8u8vw5-1.lcmDrY.styledCta")  # Клик по кнопке "Join Vimeo"

        # Проверка успешности регистрации
        if sb.assert_text("You’re all signed up! Get even more from Vimeo.", timeout=15):
            print("Регистрация прошла успешно.")
        else:
            print("Регистрация не прошла успешно.")

if __name__ == "__main__":
    temp_email = get_temp_email()  # Получение временного email
    password = generate_password()  # Генерация пароля

    save_to_file(temp_email, password)  # Сохранение email и пароля в файл

    register_vimeo_account(temp_email, password)  # Регистрация аккаунта на Vimeo

4) Не настолько простой регчекер
Тут в качестве более наглядного примера использования я сделал регчекер, который берет mail:pass из базы с именем vimeo.txt и разделяет результаты по файлам:
Python:
from seleniumbase import SB  # Импортируем класс SB из библиотеки seleniumbase

# Открываем файлы для записи валидных и невалидных аккаунтов
valid_file = open("valid.txt", "a")
invalid_file = open("invalid.txt", "a")

# Читаем строки из файла "vimeo.txt"
with open("vimeo.txt", "r") as file:
    lines = file.readlines()

# Цикл
while True:
    # Проходимся по каждой строке из файла "vimeo.txt"
    for line in lines:
        # Разделяем строку на email и пароль
        email, password = line.strip().split(":")

        # Создаем экземпляр SB (SeleniumBase) с параметром uc=True
        with SB(uc=True) as sb:
            # Открываем страницу входа Vimeo
            url = "https://vimeo.com/log_in"
            sb.open(url)

            # Вводим email и пароль в соответствующие поля
            sb.type("#email_login", email)
            sb.type("#password_login", password + "\n")

            try:
                # Ждем, пока появится элемент, указывающий на ошибку входа
                sb.wait_for_element_visible("span.sc-jRQBWg.gFTdpF.sc-dJjYzT.doitBf", timeout=5)
                # Если элемент появился, значит аккаунт не валиден
                print(f"Аккаунт {email} не является валидным.")
                # Записываем аккаунт в файл невалидных аккаунтов
                invalid_file.write(f"{email}:{password}\n")
            except:
                # Если элемент не появился, значит аккаунт валиден
                print(f"Аккаунт {email} является валидным.")
                # Записываем аккаунт в файл валидных аккаунтов
                valid_file.write(f"{email}:{password}\n")

# Закрываем файлы после окончания работы
valid_file.close()
invalid_file.close()
 
Последнее редактирование:
Брад, где ты раньше был, я уже успел пересесть на nodejs+playwright, походу обратно на питончик пора
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх