Pull to refresh

Новый Selenium Python: стелс-режим, профиль, скрытая автоматизация

Level of difficultyMedium
Reading time7 min
Views6.1K

Привет всем! У меня отличные новости: работа с Selenium стала еще проще. Больше никаких танцев с вебдрайверами — теперь всё работает "из коробки"!

В честь этих изменений я хочу поделиться своим опытом работы с этой замечательной библиотекой.

Краткий ликбез

Selenium — это библиотека Python, предназначенная для тестирования браузеров, что в данном контексте можно сравнить с автоматизацией любого действия в браузере, которое вы можете выполнить вручную.

Selenium используется для:

  • Парсинга (хотя это не лучший выбор, но об этом позже)

  • Автокликов

  • Автозаполнения форм

  • Любого действия, которое можно выполнить вручную.

Основные плюсы:

  • Удобство: Легко получать доступ к любому элементу страницы через CSS, ID, классы, теги и XPath.

  • Низкий порог входа: Достаточно 2-3 часов даже для абсолютного новичка, чтобы начать писать скрипты с использованием Selenium.

Минусы:

  • Медленный для задач парсинга

  • Не всегда стабильный

  • Тяжелый для системы (особенно при параллельном использовании нескольких драйверов)

Что мы сегодня сделаем

  1. Установим Selenium и ряд полезных библиотек, которые позволят нам работать в стелс-режиме и без плашки «Браузером управляет автоматизированное ПО».

  2. Научимся использовать профиль браузера, позволяющий сохранять личную историю каждого экземпляра браузера (авторизации, историю запросов, историю ввода и т.д.).

  3. Настроим рандомный User-Agent для каждого подключения, что позволит нам быть еще более незаметными в сети.

  4. Научимся использовать опции при инициации драйвера, чтобы повысить его скрытность и функциональность.

Установка необходимых библиотек

pip install selenium selenium-stealth fake-useragent

Или используйте requirements.txt (пример на скрине ниже).

pip install -r .\req.txt в моем случае. Для написания кода использую Pycharm
pip install -r .\req.txt в моем случае. Для написания кода использую Pycharm

Импортируем необходимые модули:

import os
from fake_useragent import UserAgent
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium_stealth import stealth
import time

Создаем функцию для генерации рандомного User-Agent:

def get_random_chrome_user_agent():
    user_agent = UserAgent(browsers='chrome', os='windows', platforms='pc')
    return user_agent.random

Эта функция возвращает случайный User-Agent для браузера Chrome под Windows.

Инициация драйвера

Не забудьте создать папку users в корне вашего проекта!

Теперь начинается самая важная часть. Инициацию драйвера (браузера под селениум) я привык делать в виде функции. Давайте я сейчас дам пример такой функции «как есть», а далее подробно поясню за что отвечает каждая строка кода.

def create_driver(user_id=1):
    options = Options()
    options.add_argument("start-maximized")
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
    options.add_experimental_option('useAutomationExtension', False)

    script_dir = os.path.dirname(os.path.abspath(__file__))
    base_directory = os.path.join(script_dir, 'users')
    user_directory = os.path.join(base_directory, f'user_{user_id}')

    options.add_argument(f'user-data-dir={user_directory}')
    options.add_argument('--disable-gpu')
    options.add_argument('--disable-dev-shm-usage')
    options.add_argument("--disable-notifications")
    options.add_argument("--disable-popup-blocking")
    options.add_argument('--no-sandbox')
    # options.add_argument('--headless')

    driver = webdriver.Chrome(options=options)
    ua = get_random_chrome_user_agent()
    stealth(driver=driver,
            user_agent=ua,
            languages=["ru-RU", "ru"],
            vendor="Google Inc.",
            platform="Win32",
            webgl_vendor="Intel Inc.",
            renderer="Intel Iris OpenGL Engine",
            fix_hairline=True,
            run_on_insecure_origins=True
            )

    driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
        'source': '''
            delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array;
            delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise;
            delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol;
      '''
    })
    return driver

А теперь к разбору полетов. Как вы уже поняли функция вернет некий экземпляр драйвера. Он, в дальнейшем, будет выполнять роль нашего браузера:

- переход по ссылкам

- сбор данных

- клики и прочие действия, которые можно только представить.

Функция принимает один параметр — ID пользователя, который используется для создания уникального профиля браузера. На примере браузера которым вы пользуетесь сейчас поясню.

Вы зашли в браузер, авторизовались на одном сайте, потом на другом и так далее. Затем закрыли браузер, выключили компьютер. Вернувшись на следующий день, открыли браузер и обнаружили, что все авторизации, кэш и история сохранились. Аналогичный процесс мы реализуем с помощью Selenium (подробнее на коде ниже).

options = Options()

Здесь создается экземпляр класса Options, который используется для настройки поведения Chrome WebDriver.

options.add_argument("start-maximized")

Добавляется аргумент для запуска браузера в режиме максимального окна.

options.add_experimental_option("excludeSwitches", ["enable-automation"])

Добавляется экспериментальная опция, исключающая переключатель "enable-automation", чтобы предотвратить автоматическое обнаружение, что браузер управляется WebDriver.

options.add_experimental_option('useAutomationExtension', False)

Добавляется экспериментальная опция, отключающая расширение автоматизации в браузере, что также помогает скрыть использование WebDriver.

script_dir = os.path.dirname(os.path.abspath(__file__))

Эта строка получает абсолютный путь к текущему скрипту и извлекает директорию, в которой он находится. file содержит путь к текущему файлу.

base_directory = os.path.join(script_dir, 'users')

Создается путь к базовой директории users, которая находится в той же директории, что и текущий скрипт. (если не находится - исправьте). В этой дирректории мы будем хранить папки с пользователями. Далее достаточно будет повторно указать айдишник пользователя и вы сможете «вернуться в профиль».

user_directory = os.path.join(base_directory, f'user_{user_id}')

Создается путь к директории конкретного пользователя, используя значение user_id. Например, если user_id равно 1, будет создан путь users/user_1.

options.add_argument(f'user-data-dir={user_directory}')

Добавляется аргумент для Chrome, указывающий на директорию с данными пользователя. Это позволяет использовать разные профили Chrome для разных пользователей.

options.add_argument('—disable-gpu')

Отключается использование GPU в браузере. Это иногда необходимо для правильной работы в средах без графического интерфейса. Аргумент не обязательный, но можете с ним поиграться.

options.add_argument('--disable-dev-shm-usage')

Отключается использование разделяемой памяти /dev/shm. Это может быть полезно для предотвращения проблем с памятью в контейнеризованных средах.

options.add_argument("—disable-notifications")

Отключаются уведомления в браузере.

options.add_argument("—disable-popup-blocking")

Отключается блокировка всплывающих окон.

options.add_argument('—no-sandbox')

Отключается песочница (sandbox) для повышения стабильности в некоторых средах, но это уменьшает безопасность. Иногда без этого аргумента не запускается вебдрайвер на средах без GUI, но тоже указывать не обязательно.

options.add_argument('—headless')

Запускает браузер в безголовом режиме (без графического интерфейса, фоном), что полезно для автоматизации и тестирования. С этим аргументом бывают интересные штуки. Иногда драйвер начинает работать быстрее, многда медленнее, а иногда и вовсе сайт это вычисляет и закрывает доступ брузеру. Так что с этим будьте аккуратны. На примере аргумент закомментирован.

driver = webdriver.Chrome(options=options)

Создается экземпляр WebDriver для Chrome с заданными параметрами options.

ua = get_random_chrome_user_agent()

Получает случайный user-agent для Chrome. Это может быть функцией, которую мы написали выше или ваш собственный user-agent.

stealth(driver=driver,
            user_agent=ua,
            languages=["ru-RU", "ru"],
            vendor="Google Inc.",
            platform="Win32",
            webgl_vendor="Intel Inc.",
            renderer="Intel Iris OpenGL Engine",
            fix_hairline=True,
            run_on_insecure_origins=True
            )

Вызывает функцию stealth для маскировки использования WebDriver. Здесь устанавливаются различные параметры, такие как user_agent, languages, vendor, platform, webgl_vendor, renderer, и другие, чтобы сделать браузер менее распознаваемым как управляемый WebDriver.

driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
        'source': '''
            delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array;
            delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise;
            delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol;
      '''
    })

Выполняет команду CDP (Chrome DevTools Protocol) для удаления определенных свойств из объекта window, которые могут использоваться для обнаружения WebDriver. К примеру с Озон вы не сможете работать без удаления этих свойств с объекта window.

return driver

Возвращает созданный и настроенный объект WebDriver.

Ну что, давайте теперь к простенькому примеру? Сейчас мы с вами зайдем на какой то сайт, выполним авторизацию и закроем браузер. После этого зайдем на этот сайт повторно через вебдрайвер и посмотрим остались ли мы авторизованными.

def main_login(user_id=1):
    driver = create_driver(user_id)
    driver.get('Ccылка на любой сайт)
    time.sleep(350)

Думаю тут все ясно:

  • инициируем браузер

  • переходим по ссылке

  • ставим паузу в 350 секунд чтоб я успел сделать авторизацию (конечно это можно делать автоматически с привязкой к форме, кнопкам, но это не тема данной статьи).

И так. Я взял первый попавшийся сайт. Видем, что предупреждений что это автоматизированное ПО нет. Как и нет входа на сайт. Давайте исправим
И так. Я взял первый попавшийся сайт. Видем, что предупреждений что это автоматизированное ПО нет. Как и нет входа на сайт. Давайте исправим

Делаю авторизацию руками

Видим, что мы смогли свободно войти на сайт без каких-либо замечаний.
Видим, что мы смогли свободно войти на сайт без каких-либо замечаний.

А теперь давайте посмотрим что у нас получилось после входа в папке пользователя с user_id — 1.

Много файлов и папок
Много файлов и папок

Как вы видите там большое количество разных папок и файлов. Похожая картинка будет в корневых папках вашего браузера. Так рабоает профиль браузера. Тяжеловат он конечно, но открывает много возможностей.

Ну что, остается зайти в созданный профиль. Сейчас мы выполним ту же функцию, так как мы передавали айдишник 1 на запуске (перед авторизацией) и он же нам нужен для входа.

Все ок
Все ок

Прекрасно. Мы по прежнему в аккаунте и браузер по прежнему не говорит, что «Браузером управляет автоматическое ПО».

На этом все. Кому интересны фишки, связанные с селениумом — пишите. Есть много чего вам рассказать, так как опыт работы с автоматизацией браузера максимально обширный.

Кому было полезно — комментируйте и ставьте лайки. Ваша поддержка для меня очень важна.

До скорого!

Only registered users can participate in poll. Log in, please.
Узнали новое?
81.4% Да35
18.6% Нет8
43 users voted. 1 user abstained.
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+8
Comments13

Articles