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
unittestandpytest - 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_managerto avoid driver version mismatches.
Common Pitfalls & How to Fix Them
- StaleElementReferenceException – The element you stored becomes outdated after a page refresh. Re‑locate the element just before interacting.
- ElementNotInteractableException – The element is hidden or disabled. Use JavaScript click as a fallback:
driver.execute_script("arguments[0].click();", element) - SessionNotCreatedException – Mismatch between browser version and driver. Update the driver via
webdriver_manageror download the matching version. - 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,
Leave a Reply