К основному содержанию
правило

selenium — правило для Cursor: что делает и как установить

Задаёт стандарты написания скриптов на Selenium в Python: обязывает использовать Page Object Model, явные ожидания и headless-режим.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/selenium.mdc
Открыть на GitHub

Что делает selenium

Правило подключается к файлам **/*.py и заставляет Cursor писать код на Selenium по паттерну Page Object Model (POM). Локаторы и методы страниц выносятся в отдельные классы вроде BasePage, отделяясь от логики тестов и парсинга.

В инструкциях прописан строгий запрет на time.sleep() и неявные ожидания: вместо них генератор применяет WebDriverWait и expected_conditions. Приоритет в выборе селекторов отдаётся By.ID и By.CSS_SELECTOR, а хрупкий абсолютный By.XPATH исключается.

Для запуска браузера правило настраивает флаги Chrome (--headless=new, --no-sandbox, --disable-dev-shm-usage) и автоматическое управление драйверами через Selenium Manager. Все сценарии оборачиваются в try...finally с вызовом driver.quit(), потому что забытый процесс Chrome быстро съедает память на сервере.

Какие задачи решает

  • отделить локаторы от сценариев тестов через Page Object Model
  • устранить нестабильные падения тестов заменой time.sleep() на WebDriverWait
  • сконфигурировать headless-режим Chrome для CI и Docker-контейнеров
  • гарантировать закрытие браузера через try...finally

Примеры запросов агенту

  • Напиши парсер для авторизации на сайте через Page Object Model на Python
  • Сделай ожидание появления динамической кнопки с помощью WebDriverWait и клик по ней
  • Настрой запуск Chrome в headless-режиме с нужными флагами для контейнера

Как установить selenium

Вручную: положить файлы

.cursor/rules/selenium.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Вопросы о selenium

Как установить selenium в Cursor?

Скопируйте файл правила по пути .cursor/rules/selenium.mdc в корне вашего проекта.

Что требует правило selenium от структуры кода?

Оно обязывает делить код на базовые классы и классы страниц по паттерну Page Object Model. Селекторы и действия с элементами инкапсулируются в методах страниц, а не смешиваются с тестами.

Какие ожидания предписывает использовать правило?

Инструкция запрещает time.sleep() и требует применять WebDriverWait вместе с expected_conditions для ожидания конкретных состояний элементов.

Исходный текст

selenium.mdc · CC0-1.0
---
description: Definitive guidelines for writing robust, maintainable, and readable Selenium automation scripts in Python, focusing on modern best practices for testing and web scraping.
globs: **/*.py
---
# selenium Best Practices

This guide outlines the definitive best practices for using Selenium with Python. Adhere to these rules to ensure your automation scripts are robust, maintainable, and performant.

## 1. Code Organization: Page Object Model (POM)

Always structure your Selenium code using the Page Object Model (POM). This separates UI elements and interactions from your test or scraping logic, making your code highly maintainable and reusable.

❌ **BAD: Logic and locators mixed**
```python
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://example.com/login")
driver.find_element(By.ID, "username").send_keys("user")
driver.find_element(By.ID, "password").send_keys("pass")
driver.find_element(By.XPATH, "//button[text()='Login']").click()
# ... more logic
```

✅ **GOOD: Page Object Model**
```python
# pages/base_page.py
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

class BasePage:
    def __init__(self, driver: WebDriver, timeout: int = 10):
        self.driver = driver
        self.wait = WebDriverWait(driver, timeout)

    def _find_element(self, by: By, value: str):
        return self.wait.until(EC.presence_of_element_located((by, value)))

# pages/login_page.py
from pages.base_page import BasePage
from selenium.webdriver.common.by import By

class LoginPage(BasePage):
    URL = "https://example.com/login"
    _USERNAME_INPUT = (By.ID, "username")
    _PASSWORD_INPUT = (By.ID, "password")
    _LOGIN_BUTTON = (By.XPATH, "//button[text()='Login']")

    def open(self):
        self.driver.get(self.URL)

    def login(self, username, password):
        self._find_element(*self._USERNAME_INPUT).send_keys(username)
        self._find_element(*self._PASSWORD_INPUT).send_keys(password)
        self._find_element(*self._LOGIN_BUTTON).click()

# tests/test_login.py (or main scraping script)
from selenium import webdriver
from pages.login_page import LoginPage

def test_successful_login():
    driver = webdriver.Chrome()
    try:
        login_page = LoginPage(driver)
        login_page.open()
        login_page.login("valid_user", "valid_pass")
        assert "dashboard" in driver.current_url # Example assertion
    finally:
        driver.quit()
```

## 2. Robustness: Explicit Waits

Never use `time.sleep()` or rely solely on implicit waits. Use `WebDriverWait` with `expected_conditions` to explicitly wait for elements to be in a specific state. This prevents flaky tests and ensures scripts are resilient to dynamic page loading.

❌ **BAD: Arbitrary waits or implicit waits**
```python
import time
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.common.by import By

driver: WebDriver = ...
driver.implicitly_wait(10) # Still prone to issues
driver.get("https://example.com")
time.sleep(5) # NEVER DO THIS
element = driver.find_element(By.ID, "dynamic_content")
```

✅ **GOOD: Explicit Waits with Expected Conditions**
```python
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

driver: WebDriver = ...
driver.get("https://example.com")
wait = WebDriverWait(driver, 10)

# Wait for element to be visible
dynamic_element = wait.until(EC.visibility_of_element_located((By.ID, "dynamic_content")))

# Wait for element to be clickable
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".submit-btn")))
button.click()
```

## 3. Driver Management & Headless Execution

Always use Selenium Manager (built into Selenium 4.6+) or `webdriver-manager` to automatically handle browser driver binaries. Run browsers in headless mode for performance and CI/CD environments.

❌ **BAD: Manual driver downloads, visible browser**
```python
from selenium import webdriver
# Requires chromedriver.exe in PATH or specified manually
driver = webdriver.Chrome(executable_path="/path/to/chromedriver")
driver.get("https://example.com") # Opens a visible browser window
```

✅ **GOOD: Automated driver management, headless with optimized options**
```python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def get_headless_chrome_driver() -> webdriver.Chrome:
    options = Options()
    options.add_argument("--headless=new")  # Modern headless mode
    options.add_argument("--no-sandbox")    # Essential for CI/Docker
    options.add_argument("--disable-dev-shm-usage") # Avoids /dev/shm issues
    options.add_argument("--window-size=1920,1080") # Ensure consistent rendering
    options.add_argument("--disable-gpu") # Recommended for headless
    options.add_argument("--log-level=3") # Suppress verbose logging
    return webdriver.Chrome(options=options)

driver = get_headless_chrome_driver()
try:
    driver.get("https://example.com")
    print(driver.title)
finally:
    driver.quit() # ALWAYS quit the driver
```

## 4. Locator Strategy Prioritization

Choose locators that are robust and least likely to change. Prioritize `By.ID` and `By.CSS_SELECTOR`. Avoid fragile `By.XPATH` unless absolutely necessary, and `By.CLASS_NAME` for elements with multiple classes.

❌ **BAD: Fragile Locators**
```python
# Absolute XPath (breaks with any DOM change)
element = driver.find_element(By.XPATH, "/html/body/div[1]/div[2]/form/input[3]")
# Class name for multiple classes (ambiguous)
element = driver.find_element(By.CLASS_NAME, "btn btn-primary active")
```

✅ **GOOD: Robust Locators**
```python
# Unique ID (most reliable)
element = driver.find_element(By.ID, "submitButton")
# CSS Selector (flexible, powerful, and stable)
element = driver.find_element(By.CSS_SELECTOR, "button.submit-btn[name='action']")
# Partial Link Text (for navigation)
element = driver.find_element(By.PARTIAL_LINK_TEXT, "Read More")
```

## 5. Error Handling & Teardown

Implement robust `try...finally` blocks to ensure `driver.quit()` is always called, preventing lingering browser processes. Catch common Selenium exceptions for graceful failure and better debugging.

```python
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, TimeoutException

driver = get_headless_chrome_driver() # Using the good practice from above
try:
    driver.get("https://example.com/nonexistent")
    # Attempt to find an element that might not exist
    element = driver.find_element(By.ID, "some_element")
    element.click()
except NoSuchElementException:
    print("Element not found. Check locator or page state.")
except TimeoutException:
    print("Page load or element wait timed out.")
except Exception as e:
    print(f"An unexpected error occurred: {e}")
finally:
    driver.quit() # Ensures browser process is terminated
```

## 6. Type Hints

Always use Python type hints. They improve code readability, enable static analysis, and reduce bugs, especially in larger projects and Page Object Models.

```python
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.by import By
from typing import Tuple

class MyPage:
    _SEARCH_INPUT: Tuple[By, str] = (By.ID, "search")

    def __init__(self, driver: WebDriver):
        self.driver = driver

    def search(self, query: str) -> None:
        search_box: WebElement = self.driver.find_element(*self._SEARCH_INPUT)
        search_box.send_keys(query)
        search_box.submit()
```

## 7. Virtual Environments & Packaging

Always use a virtual environment (`venv` or `uv`) for dependency management. For modern projects, use `uv` and `pyproject.toml` for fast, reproducible builds.

```bash
# Recommended modern setup with uv
uv init my-selenium-project
cd my-selenium-project
uv add selenium pytest # Add your dependencies

# Or classic venv
python -m venv .venv
source .venv/bin/activate # Linux/macOS
.venv\Scripts\Activate.ps1 # Windows PowerShell
pip install selenium pytest
```

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Похожие правила IDE

Все правила IDE по теме «Тесты и QA» →
selenium-automation Mindrally Скилл задаёт агенту правила написания тестов на Selenium WebDriver: Page Object Model, явные ожидания, устойчивые локаторы. CX Codex +1 1 200установок selenium-skill TestMu AI Генерирует готовые автотесты Selenium WebDriver на шести языках. Помогает настроить локальный запуск или прогон в облаке TestMu AI. CX Codex +1 310установок web-scraping Mindrally Скилл задаёт агенту правила парсинга: какие библиотеки брать для статики, динамики и больших обходов, как обходить блокировки и ошибки. CX Codex +1 4 500установок playwright-best-practices currents.dev Справочник по тестированию на Playwright: от написания E2E-сценариев до Page Object Model. Помогает разбирать флакующие тесты, настраивать мокирование API и проверять доступность. CX Codex +1 98 500установок playwright-stealth-verify liarjsdev Проверяет согласованность отпечатка браузера под автоматизацией. Нужен, чтобы измерить эффект настроек headless-режима или скрывающих плагинов в тестах. CX Codex +1 102 500установок browser-automation sickn33 Скилл помогает проверять браузерные сценарии по состоянию интерфейса и результату операции. Подходит для UI-тестов, диагностики таймингов и разрешённого сбора данных. CX Codex +1 6 700установок

Из того же набора240

Весь набор →
shadcn Правило для Cursor задаёт команде единый стиль работы с shadcn/ui: структура папок, типы, варианты через CVA, формы на React Hook Form и Zod. Пригодится, когда компонентов становится много. ★ 3 580звёзд репо setuptools Направляет ИИ-ассистента на сборку современных Python-пакетов через декларативный pyproject.toml и структуру src/. ★ 3 580звёзд репо servemux Правило подсказывает, как организовать HTTP-маршруты на http.ServeMux и использовать возможности Go 1.22+. Пригодится при разработке API на Go. ★ 3 580звёзд репо sentry Правило задаёт, как инициализировать Sentry в проекте: где ставить SDK, какие переменные окружения использовать, как не сломать чужой код. ★ 3 580звёзд репо seaborn Правило задаёт подход к графикам на Seaborn: от структуры данных и оформления до работы с большими наборами. Пригодится для Python-проектов с визуализацией данных. ★ 3 580звёзд репо scrapy Правило с набором практик для Scrapy: структура проекта, items, pipelines, middlewares. Пригодится, когда агент пишет парсеры на Python. ★ 3 580звёзд репо scipy Набор правил для написания научного кода на SciPy в Cursor: оформление docstrings, именованные аргументы и вычисления. ★ 3 580звёзд репо scikit-learn Правило направляет Cursor при работе с Python-кодом scikit-learn: помогает оформлять предобработку и модели через Pipeline и не допускать утечки данных. ★ 3 580звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой