Home » Учебник по Selenium WebDriver: начало работы
Учебник по Selenium WebDriver: начало работы

Учебник по Selenium WebDriver: начало работы

Итак, ты наверняка слышал о Selenium WebDriver — это мощный инструмент для автоматизации веб-браузеров, который стал стандартом де-факто для тестирования веб-приложений. Но если ты администратор серверов или DevOps-инженер, то знаешь, что возможности Selenium простираются далеко за пределы простого тестирования. Мониторинг веб-сервисов, автоматизация рутинных задач в браузере, сбор данных — всё это можно делать с помощью WebDriver. В этой статье я покажу, как быстро развернуть Selenium на твоём сервере и начать использовать его для автоматизации. Мы пройдём от установки до реальных примеров использования, разберём подводные камни и рассмотрим альтернативы.

Как работает Selenium WebDriver

WebDriver — это API для управления браузерами программно. В отличие от старого Selenium RC, который работал через JavaScript инъекции, WebDriver напрямую взаимодействует с браузером через его нативные методы. Это означает более стабильную работу и лучшую производительность.

Архитектура выглядит следующим образом:

  • Selenium Client — твой Python/Java/C# код
  • WebDriver Protocol — HTTP REST API для связи
  • Driver — ChromeDriver, GeckoDriver, EdgeDriver
  • Browser — Chrome, Firefox, Edge и т.д.

Когда ты пишешь driver.get("https://example.com"), происходит следующее:

  1. Selenium клиент отправляет HTTP POST запрос к WebDriver
  2. WebDriver переводит команду в вызовы браузерного API
  3. Браузер выполняет действие и возвращает результат
  4. WebDriver возвращает ответ обратно в твой код

Установка и настройка на сервере

Для серверного использования понадобится headless-режим (без графического интерфейса). Если у тебя ещё нет подходящего сервера, можешь взять VPS или выделенный сервер.

Начнём с установки на Ubuntu/Debian:

# Обновляем систему
sudo apt update && sudo apt upgrade -y

# Устанавливаем Python и pip
sudo apt install python3 python3-pip -y

# Устанавливаем Google Chrome (headless)
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list
sudo apt update
sudo apt install google-chrome-stable -y

# Устанавливаем Selenium
pip3 install selenium webdriver-manager

# Проверяем установку Chrome
google-chrome --version

Для CentOS/RHEL процесс немного отличается:

# Добавляем репозиторий Chrome
sudo tee /etc/yum.repos.d/google-chrome.repo << EOF
[google-chrome]
name=google-chrome
baseurl=http://dl.google.com/linux/chrome/rpm/stable/x86_64
enabled=1
gpgcheck=1
gpgkey=https://dl.google.com/linux/linux_signing_key.pub
EOF

# Устанавливаем Chrome
sudo yum install google-chrome-stable -y

# Устанавливаем Python и зависимости
sudo yum install python3 python3-pip -y
pip3 install selenium webdriver-manager

Первый скрипт и базовые операции

Создаём тестовый скрипт для проверки работоспособности:

#!/usr/bin/env python3
# test_selenium.py

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
import time

def create_driver():
    """Создаём WebDriver с оптимальными настройками для сервера"""
    options = Options()
    
    # Headless режим (без GUI)
    options.add_argument('--headless')
    
    # Отключаем GPU (для серверов без видеокарты)
    options.add_argument('--no-gpu')
    
    # Отключаем песочницу (нужно для запуска от root)
    options.add_argument('--no-sandbox')
    
    # Отключаем /dev/shm (решает проблемы с памятью)
    options.add_argument('--disable-dev-shm-usage')
    
    # Устанавливаем размер окна
    options.add_argument('--window-size=1920,1080')
    
    # Отключаем уведомления
    options.add_argument('--disable-notifications')
    
    # Автоматически загружаем нужную версию ChromeDriver
    service = Service(ChromeDriverManager().install())
    
    driver = webdriver.Chrome(service=service, options=options)
    driver.set_page_load_timeout(30)
    
    return driver

def test_basic_functionality():
    """Тестируем базовый функционал"""
    driver = create_driver()
    
    try:
        # Переходим на страницу
        print("Загружаем https://httpbin.org/html")
        driver.get("https://httpbin.org/html")
        
        # Ждём загрузки элемента
        wait = WebDriverWait(driver, 10)
        h1_element = wait.until(EC.presence_of_element_located((By.TAG_NAME, "h1")))
        
        # Получаем заголовок страницы
        print(f"Заголовок страницы: {driver.title}")
        print(f"Текст H1: {h1_element.text}")
        
        # Делаем скриншот
        driver.save_screenshot('/tmp/test_screenshot.png')
        print("Скриншот сохранён в /tmp/test_screenshot.png")
        
        # Получаем HTML
        html = driver.page_source
        print(f"Размер HTML: {len(html)} символов")
        
        return True
        
    except Exception as e:
        print(f"Ошибка: {e}")
        return False
    finally:
        driver.quit()

if __name__ == "__main__":
    success = test_basic_functionality()
    print(f"Тест {'прошёл' if success else 'провалился'}")

Запускаем тест:

python3 test_selenium.py

Реальные кейсы использования

Теперь рассмотрим практические примеры, которые пригодятся в повседневной работе сисадмина:

Мониторинг веб-сервисов

#!/usr/bin/env python3
# monitor_service.py

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
import time
import smtplib
from email.mime.text import MIMEText
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class WebServiceMonitor:
    def __init__(self):
        self.driver = None
        self.setup_driver()
    
    def setup_driver(self):
        options = Options()
        options.add_argument('--headless')
        options.add_argument('--no-gpu')
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-dev-shm-usage')
        options.add_argument('--window-size=1920,1080')
        
        service = Service(ChromeDriverManager().install())
        self.driver = webdriver.Chrome(service=service, options=options)
        self.driver.set_page_load_timeout(30)
    
    def check_login_form(self, url, username_field, password_field):
        """Проверяем доступность формы логина"""
        try:
            self.driver.get(url)
            wait = WebDriverWait(self.driver, 10)
            
            # Проверяем наличие полей
            username_input = wait.until(EC.presence_of_element_located((By.NAME, username_field)))
            password_input = wait.until(EC.presence_of_element_located((By.NAME, password_field)))
            
            logger.info(f"✓ Форма логина на {url} доступна")
            return True
            
        except Exception as e:
            logger.error(f"✗ Ошибка при проверке {url}: {e}")
            return False
    
    def check_element_text(self, url, selector, expected_text):
        """Проверяем содержимое элемента"""
        try:
            self.driver.get(url)
            wait = WebDriverWait(self.driver, 10)
            
            element = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, selector)))
            actual_text = element.text
            
            if expected_text in actual_text:
                logger.info(f"✓ Текст '{expected_text}' найден на {url}")
                return True
            else:
                logger.error(f"✗ Ожидался '{expected_text}', получен '{actual_text}'")
                return False
                
        except Exception as e:
            logger.error(f"✗ Ошибка при проверке {url}: {e}")
            return False
    
    def performance_check(self, url):
        """Проверяем производительность загрузки"""
        try:
            start_time = time.time()
            self.driver.get(url)
            
            # Ждём полной загрузки
            WebDriverWait(self.driver, 30).until(
                lambda driver: driver.execute_script("return document.readyState") == "complete"
            )
            
            load_time = time.time() - start_time
            logger.info(f"Время загрузки {url}: {load_time:.2f} секунд")
            
            return load_time
            
        except Exception as e:
            logger.error(f"Ошибка при проверке производительности {url}: {e}")
            return None
    
    def cleanup(self):
        if self.driver:
            self.driver.quit()

# Пример использования
if __name__ == "__main__":
    monitor = WebServiceMonitor()
    
    try:
        # Проверяем админку
        admin_ok = monitor.check_login_form(
            "https://your-admin-panel.com/login",
            "username",
            "password"
        )
        
        # Проверяем главную страницу
        main_ok = monitor.check_element_text(
            "https://your-site.com",
            "h1",
            "Welcome"
        )
        
        # Проверяем производительность
        load_time = monitor.performance_check("https://your-site.com")
        
        if not admin_ok or not main_ok or (load_time and load_time > 5):
            logger.error("Обнаружены проблемы с сервисом!")
            # Здесь можно добавить отправку уведомлений
            
    finally:
        monitor.cleanup()

Автоматизация рутинных задач

#!/usr/bin/env python3
# auto_tasks.py

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait, Select
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
import time
import json
import os

class ServerAutoTasks:
    def __init__(self):
        self.driver = None
        self.setup_driver()
    
    def setup_driver(self):
        options = Options()
        options.add_argument('--headless')
        options.add_argument('--no-gpu')
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-dev-shm-usage')
        
        # Настройки для загрузки файлов
        prefs = {
            "download.default_directory": "/tmp/downloads",
            "download.prompt_for_download": False,
            "download.directory_upgrade": True,
            "safebrowsing.enabled": True
        }
        options.add_experimental_option("prefs", prefs)
        
        service = Service(ChromeDriverManager().install())
        self.driver = webdriver.Chrome(service=service, options=options)
        self.driver.set_page_load_timeout(30)
    
    def download_ssl_certificate(self, domain):
        """Скачиваем SSL сертификат для домена"""
        try:
            # Используем онлайн-сервис для получения сертификата
            self.driver.get("https://www.ssllabs.com/ssltest/")
            
            # Вводим домен
            hostname_input = self.driver.find_element(By.NAME, "d")
            hostname_input.clear()
            hostname_input.send_keys(domain)
            
            # Запускаем тест
            submit_button = self.driver.find_element(By.CSS_SELECTOR, "input[type='submit']")
            submit_button.click()
            
            # Ждём результатов (это может занять время)
            wait = WebDriverWait(self.driver, 300)  # 5 минут
            
            # Проверяем статус
            try:
                grade_element = wait.until(
                    EC.presence_of_element_located((By.CSS_SELECTOR, ".grade"))
                )
                grade = grade_element.text
                print(f"SSL рейтинг для {domain}: {grade}")
                
                # Сохраняем скриншот результата
                self.driver.save_screenshot(f"/tmp/ssl_test_{domain}.png")
                
                return grade
                
            except:
                print(f"Не удалось получить рейтинг SSL для {domain}")
                return None
                
        except Exception as e:
            print(f"Ошибка при проверке SSL для {domain}: {e}")
            return None
    
    def backup_website_content(self, url, output_dir):
        """Создаём резервную копию контента сайта"""
        try:
            self.driver.get(url)
            
            # Получаем все ссылки
            links = self.driver.find_elements(By.TAG_NAME, "a")
            hrefs = [link.get_attribute("href") for link in links if link.get_attribute("href")]
            
            # Получаем все изображения
            images = self.driver.find_elements(By.TAG_NAME, "img")
            img_srcs = [img.get_attribute("src") for img in images if img.get_attribute("src")]
            
            # Сохраняем HTML
            html_content = self.driver.page_source
            
            # Создаём директорию для бэкапа
            os.makedirs(output_dir, exist_ok=True)
            
            # Сохраняем основной HTML
            with open(f"{output_dir}/index.html", "w", encoding="utf-8") as f:
                f.write(html_content)
            
            # Сохраняем метаданные
            metadata = {
                "url": url,
                "title": self.driver.title,
                "timestamp": time.time(),
                "links": hrefs,
                "images": img_srcs
            }
            
            with open(f"{output_dir}/metadata.json", "w", encoding="utf-8") as f:
                json.dump(metadata, f, indent=2, ensure_ascii=False)
            
            print(f"Бэкап {url} сохранён в {output_dir}")
            return True
            
        except Exception as e:
            print(f"Ошибка при создании бэкапа {url}: {e}")
            return False
    
    def cleanup(self):
        if self.driver:
            self.driver.quit()

# Пример использования
if __name__ == "__main__":
    tasks = ServerAutoTasks()
    
    try:
        # Проверяем SSL сертификат
        ssl_grade = tasks.download_ssl_certificate("google.com")
        
        # Создаём бэкап сайта
        tasks.backup_website_content("https://httpbin.org/html", "/tmp/backup")
        
    finally:
        tasks.cleanup()

Сравнение с альтернативными решениями

Selenium не единственный инструмент для автоматизации браузеров. Рассмотрим основные альтернативы:

Инструмент Плюсы Минусы Лучший случай использования
Selenium WebDriver • Поддержка всех браузеров
• Огромное сообщество
• Множество языков
• Стабильность
• Медленная работа
• Большое потребление ресурсов
• Сложная настройка headless
Комплексное тестирование, долгосрочные проекты
Playwright • Быстрая работа
• Современный API
• Встроенная поддержка headless
• Автоматическое ожидание
• Относительно новый
• Меньше плагинов
• Ограниченная поддержка старых браузеров
Современные веб-приложения, быстрые тесты
Puppeteer • Очень быстрый
• Отличная интеграция с Chrome
• Богатый API
• Хорошая документация
• Только Chrome/Chromium
• Только JavaScript
• Нет поддержки Firefox/Safari
Chrome-специфичные задачи, скрапинг
Requests + BeautifulSoup • Очень быстро
• Минимальное потребление ресурсов
• Простота использования
• Нет поддержки JavaScript
• Нет взаимодействия с UI
• Проблемы с SPA
Простой скрапинг статических сайтов

Оптимизация для серверного использования

При использовании Selenium на продакшн-серверах важно учесть несколько моментов:

Настройка ресурсов

# Скрипт для мониторинга ресурсов
#!/bin/bash
# monitor_selenium.sh

echo "=== Мониторинг Selenium процессов ==="
echo "Chrome процессы:"
ps aux | grep chrome | grep -v grep

echo -e "\nИспользование памяти:"
free -h

echo -e "\nИспользование CPU:"
top -bn1 | grep "Cpu(s)"

echo -e "\nДисковое пространство:"
df -h | grep -E "(Filesystem|/dev/)"

echo -e "\nСетевые соединения:"
netstat -tulpn | grep -E "(chrome|selenium)" | wc -l

Настройка лимитов

# /etc/security/limits.conf
selenium soft nofile 65536
selenium hard nofile 65536
selenium soft nproc 32768
selenium hard nproc 32768

# systemd service пример
# /etc/systemd/system/selenium-monitor.service
[Unit]
Description=Selenium Monitoring Service
After=network.target

[Service]
Type=simple
User=selenium
Group=selenium
WorkingDirectory=/opt/selenium
ExecStart=/usr/bin/python3 /opt/selenium/monitor.py
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal

# Ограничения ресурсов
MemoryLimit=1G
CPUQuota=50%

[Install]
WantedBy=multi-user.target

Docker-контейнер для изоляции

# Dockerfile
FROM ubuntu:20.04

# Устанавливаем зависимости
RUN apt-get update && apt-get install -y \
    python3 \
    python3-pip \
    wget \
    curl \
    unzip \
    && rm -rf /var/lib/apt/lists/*

# Устанавливаем Chrome
RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - \
    && echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \
    && apt-get update \
    && apt-get install -y google-chrome-stable \
    && rm -rf /var/lib/apt/lists/*

# Устанавливаем Python зависимости
RUN pip3 install selenium webdriver-manager

# Создаём пользователя
RUN useradd -m -s /bin/bash selenium

# Копируем скрипты
COPY scripts/ /home/selenium/
RUN chown -R selenium:selenium /home/selenium/

USER selenium
WORKDIR /home/selenium

CMD ["python3", "monitor.py"]

Запуск контейнера:

# Сборка
docker build -t selenium-monitor .

# Запуск
docker run -d \
  --name selenium-monitor \
  --memory=1g \
  --cpus=0.5 \
  --restart=unless-stopped \
  -v /tmp/selenium-logs:/home/selenium/logs \
  selenium-monitor

Полезные трюки и хаки

Обход anti-bot защиты

def create_stealth_driver():
    """Создаём WebDriver с настройками для обхода базовой защиты"""
    options = Options()
    
    # Базовые настройки
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-dev-shm-usage')
    
    # Антидетект настройки
    options.add_argument('--disable-blink-features=AutomationControlled')
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
    options.add_experimental_option('useAutomationExtension', False)
    options.add_argument('--disable-extensions')
    
    # Имитируем реального пользователя
    options.add_argument('--user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36')
    
    driver = webdriver.Chrome(options=options)
    
    # Удаляем webdriver property
    driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
    
    return driver

Параллельное выполнение задач

import concurrent.futures
import threading
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

class SeleniumPool:
    def __init__(self, max_workers=4):
        self.max_workers = max_workers
        self.local_driver = threading.local()
    
    def get_driver(self):
        if not hasattr(self.local_driver, 'driver'):
            options = Options()
            options.add_argument('--headless')
            options.add_argument('--no-sandbox')
            options.add_argument('--disable-dev-shm-usage')
            
            self.local_driver.driver = webdriver.Chrome(options=options)
        
        return self.local_driver.driver
    
    def check_url(self, url):
        """Проверяем одну URL"""
        driver = self.get_driver()
        try:
            driver.get(url)
            return {
                'url': url,
                'title': driver.title,
                'status': 'ok',
                'load_time': driver.execute_script("return performance.timing.loadEventEnd - performance.timing.navigationStart")
            }
        except Exception as e:
            return {
                'url': url,
                'status': 'error',
                'error': str(e)
            }
    
    def check_multiple_urls(self, urls):
        """Проверяем множество URLs параллельно"""
        with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
            results = list(executor.map(self.check_url, urls))
        
        return results
    
    def cleanup(self):
        if hasattr(self.local_driver, 'driver'):
            self.local_driver.driver.quit()

# Использование
pool = SeleniumPool(max_workers=4)
urls = ['https://google.com', 'https://github.com', 'https://stackoverflow.com']

results = pool.check_multiple_urls(urls)
for result in results:
    print(f"{result['url']}: {result.get('title', result.get('error'))}")

pool.cleanup()

Интеграция с системами мониторинга

Для продакшн-использования важно интегрировать Selenium с системами мониторинга:

Prometheus метрики

from prometheus_client import Counter, Histogram, start_http_server
import time

# Метрики
selenium_requests_total = Counter('selenium_requests_total', 'Total selenium requests', ['status'])
selenium_request_duration = Histogram('selenium_request_duration_seconds', 'Request duration')

class MonitoredSelenium:
    def __init__(self):
        self.driver = self.create_driver()
        # Запускаем HTTP сервер для метрик
        start_http_server(8000)
    
    @selenium_request_duration.time()
    def monitored_get(self, url):
        try:
            self.driver.get(url)
            selenium_requests_total.labels(status='success').inc()
            return True
        except Exception as e:
            selenium_requests_total.labels(status='error').inc()
            raise e

Логирование в ELK Stack

import logging
import json
from datetime import datetime

# Настройка логирования в JSON формате для Logstash
class JSONFormatter(logging.Formatter):
    def format(self, record):
        log_entry = {
            'timestamp': datetime.utcnow().isoformat(),
            'level': record.levelname,
            'message': record.getMessage(),
            'module': record.module,
            'function': record.funcName,
            'line': record.lineno
        }
        
        if hasattr(record, 'url'):
            log_entry['url'] = record.url
        if hasattr(record, 'duration'):
            log_entry['duration'] = record.duration
        if hasattr(record, 'error'):
            log_entry['error'] = record.error
            
        return json.dumps(log_entry)

# Настройка логгера
logger = logging.getLogger('selenium_monitor')
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)

# Использование
def monitored_action(url):
    start_time = time.time()
    try:
        # Selenium действия
        result = perform_selenium_action(url)
        
        duration = time.time() - start_time
        logger.info("Selenium action completed", 
                   extra={'url': url, 'duration': duration})
        
        return result
        
    except Exception as e:
        duration = time.time() - start_time
        logger.error("Selenium action failed", 
                    extra={'url': url, 'duration': duration, 'error': str(e)})
        raise

Статистика и производительность

По данным различных бенчмарков:

  • Selenium WebDriver: ~2-5 секунд на страницу, 50-200 МБ RAM на браузер
  • Playwright: ~1-3 секунды на страницу, 30-150 МБ RAM на браузер
  • Puppeteer: ~1-2 секунды на страницу, 40-120 МБ RAM на браузер
  • Requests: ~0.1-0.5 секунд на страницу, 10-50 МБ RAM

Для серверного использования рекомендую следующую конфигурацию:

  • CPU: минимум 2 ядра, рекомендуется 4+ для параллельного выполнения
  • RAM: минимум 2 ГБ, рекомендуется 4+ ГБ для стабильной работы
  • Дисковое пространство: минимум 10 ГБ для Chrome и логов
  • Сеть: стабильное соединение 10+ Мбит/с

Новые возможности и интересные факты

Selenium 4 принёс много интересных возможностей:

  • Относительные локаторы — можно искать элементы относительно других: driver.find_element(with_tag_name("input").above(password_field))
  • Новый API для скриншотов — можно делать скриншоты отдельных элементов
  • Улучшенная поддержка мобильных устройств — эмуляция touch событий
  • Интеграция с Docker — официальные образы для headless режима

Нестандартные способы использования:

  • Генерация PDF из веб-страниц — используй driver.execute_cdp_cmd('Page.printToPDF', {})
  • Перехват сетевых запросов — с помощью Chrome DevTools Protocol
  • Автоматизация SSH-туннелей — для доступа к внутренним админкам
  • Создание динамических дашбордов — скриншоты графиков по расписанию

Интересные факты:

  • Selenium первоначально создавался для тестирования внутренних приложений ThoughtWorks в 2004 году
  • Название происходит от элемента селена, который используется для тестирования отравления ртутью (намёк на Mercury QTP)
  • Google Chrome команда активно участвует в развитии WebDriver стандарта
  • Selenium Grid может управлять тысячами браузеров одновременно

Заключение и рекомендации

Selenium WebDriver остаётся одним из самых мощных инструментов для автоматизации браузеров, особенно в серверной среде. Несмотря на появление более быстрых альтернатив, его универсальность и зрелость экосистемы делают его отличным выбором для большинства задач.

Рекомендую использовать Selenium когда:

  • Нужна поддержка разных браузеров
  • Требуется стабильное решение для долгосрочного проекта
  • Команда уже знакома с инструментом
  • Нужна интеграция с существующими тестовыми фреймворками

Стоит рассмотреть альтернативы если:

  • Критична производительность (выбирай Playwright или Puppeteer)
  • Работаешь только с простыми статическими сайтами (хватит Requests)
  • Нужны продвинутые возможности современного веба (Playwright)

Для продакшн-использования обязательно:

  • Используй Docker для изоляции
  • Настрой мониторинг ресурсов
  • Реализуй ротацию логов
  • Добавь алерты на критические ошибки
  • Регулярно обновляй драйверы браузеров

Selenium WebDriver — это не просто инструмент для тестирования, это целая экосистема для автоматизации веб-задач. Правильно настроенный и оптимизированный, он станет незаменимым помощником в твоей серверной инфраструктуре.

Полезные ссылки:


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

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

Leave a reply

Your email address will not be published. Required fields are marked