Python Selenium Web Driver Complete Tutorial

Written by

in

Welcome to the ultimate Python Selenium WebDriver complete tutorial! Whether you’re a seasoned developer looking to automate repetitive web tasks or a QA engineer diving into browser testing, this guide will walk you through everything you need to know—from installation to advanced tricks. By the end, you’ll be able to write robust, maintainable Selenium scripts that run smoothly across Chrome, Firefox, Edge, and even headless environments.

What Is Selenium WebDriver?

Selenium WebDriver is a powerful, open‑source tool that enables programmatic control of web browsers. Unlike Selenium IDE, which records clicks, WebDriver interacts directly with the browser’s native automation APIs, providing:

  • Cross‑browser support (Chrome, Firefox, Safari, Edge)
  • Fine‑grained control over page elements
  • Integration with testing frameworks like unittest and pytest
  • Support for headless execution—perfect for CI/CD pipelines

When paired with Python, Selenium becomes an intuitive, readable way to automate web interactions.

Installing Python & Selenium

Step 1: Install Python

Make sure you have Python 3.8+ installed. You can download it from python.org or use a package manager:

# macOS
brew install python

# Ubuntu/Debian
sudo apt-get update && sudo apt-get install python3 python3-pip

Step 2: Install Selenium via pip

Open a terminal and run:

pip install selenium

This pulls the latest stable Selenium bindings for Python.

Step 3: Get the Browser Driver

Each browser requires its own driver executable:

  • Chrome → chromedriver (download from chromium.org)
  • Firefox → geckodriver (download from GitHub)
  • Edge → msedgedriver (download from Microsoft)

Place the driver binary in a folder that’s on your system PATH or specify its location when creating the driver instance.

Setting Up the WebDriver in Python

Below is a minimal script that launches Chrome, navigates to example.com, and closes the browser:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

# Automatically download the correct driver version
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

driver.get("https://www.example.com")
print(driver.title)  # prints the page title

driver.quit()

Using webdriver_manager (install via pip install webdriver-manager) eliminates manual driver handling, making your scripts more portable.

Core Selenium Commands

Navigating Pages

  • driver.get(url) – Open a URL.
  • driver.back() – Navigate back.
  • driver.forward() – Navigate forward.
  • driver.refresh() – Reload the current page.

Finding Elements

Selenium offers several locator strategies. The most common are:

# By ID
elem = driver.find_element(By.ID, "username")

# By CSS Selector
elem = driver.find_element(By.CSS_SELECTOR, "input[name='email']")

# By XPath
elem = driver.find_element(By.XPATH, "//button[text()='Submit']")

Always import the By class:

from selenium.webdriver.common.by import By

Interacting with Elements

# Click a button
button = driver.find_element(By.ID, "login")
button.click()

# Enter text
search = driver.find_element(By.NAME, "q")
search.clear()
search.send_keys("Selenium Python tutorial")
search.submit()

Handling Waits: Implicit vs. Explicit

Web pages load asynchronously, so hard‑coded time.sleep() statements are fragile. Selenium provides two reliable waiting mechanisms:

Implicit Wait

# Apply globally – wait up to 10 seconds for any element
driver.implicitly_wait(10)

It polls the DOM until the element appears or the timeout expires.

Explicit Wait

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Wait for a specific condition (e.g., element to be clickable)
wait = WebDriverWait(driver, 15)
login_btn = wait.until(EC.element_to_be_clickable((By.ID, "login")))
login_btn.click()

Explicit waits are more precise and recommended for complex pages.

Working with Frames, Alerts, and Pop‑ups

Frames & iFrames

# Switch to a frame by name or index
driver.switch_to.frame("payment-frame")

# Perform actions inside the frame
driver.find_element(By.ID, "card-number").send_keys("4111111111111111")

# Return to the default content
driver.switch_to.default_content()

JavaScript Alerts

# Accept an alert
alert = driver.switch_to.alert
alert.accept()

# Dismiss an alert
alert.dismiss()

# Retrieve alert text
msg = alert.text

Taking Screenshots & Saving Page Source

Capturing the state of a page is essential for debugging and reporting.

# Full‑page screenshot (Chrome 59+)
driver.save_screenshot("homepage.png")

# Save HTML source
with open("source.html", "w", encoding="utf-8") as f:
    f.write(driver.page_source)

Running Tests Headlessly

Headless mode runs browsers without a UI, ideal for CI pipelines.

# Chrome headless example
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--disable-gpu")  # Windows workaround
driver = webdriver.Chrome(service=service, options=options)

driver.get("https://www.python.org")
print(driver.title)
driver.quit()

Integrating Selenium with PyTest

PyTest provides a clean structure for test discovery and reporting.

# test_login.py
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

@pytest.fixture(scope="function")
def driver():
    service = Service(ChromeDriverManager().install())
    options = webdriver.ChromeOptions()
    options.add_argument("--headless")
    _driver = webdriver.Chrome(service=service, options=options)
    yield _driver
    _driver.quit()

def test_google_search(driver):
    driver.get("https://www.google.com")
    search_box = driver.find_element(By.NAME, "q")
    search_box.send_keys("Selenium Python")
    search_box.submit()
    assert "Selenium Python" in driver.title

Run the suite with pytest -v and enjoy detailed output.

Best Practices for Stable Selenium Scripts

  • Use explicit waits instead of static sleeps.
  • Prefer CSS selectors over XPath for speed and readability.
  • Encapsulate page actions using the Page Object Model (POM) to keep tests DRY.
  • Separate test data from test logic—use JSON, CSV, or fixtures.
  • Run browsers in headless mode on CI servers, but keep a visual mode for debugging.
  • Leverage webdriver_manager to avoid driver version mismatches.

Common Pitfalls & How to Fix Them

  1. StaleElementReferenceException – The element you stored becomes outdated after a page refresh. Re‑locate the element just before interacting.
  2. ElementNotInteractableException – The element is hidden or disabled. Use JavaScript click as a fallback:
    driver.execute_script("arguments[0].click();", element)
  3. SessionNotCreatedException – Mismatch between browser version and driver. Update the driver via webdriver_manager or download the matching version.
  4. TimeoutException – Waits are too short or the locator is wrong. Double‑check the selector and increase the wait time.

Putting It All Together: A Mini‑Project

Let’s build a quick script that logs into a demo site, navigates to a profile page, takes a screenshot, and logs out.

import time
from selenium import webdriver
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

def login(driver, username,

Comments

Leave a Reply

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