Selenium Ecosystem, Installation, and First WebDriver Session: Guided Hands-On Workflow
Create the first reproducible Selenium project from a clean directory and prove every important state transition: dependency install, local fixture startup, session negotiation, navigation, interaction, evidence capture, and teardown.
Learning objectives
- Create an isolated Python environment and pin Selenium 4.47.0 at project scope.
- Run a loopback-only HTML fixture so the exercise cannot mutate a public or production application.
- Use the default Selenium Manager path to resolve a compatible local driver without hard-coded executable paths.
- Record session ID, browser/driver capabilities, URL, title, assertion state, and one screenshot as evidence.
-
Use
try/finallyso the session is terminated even when an assertion or command fails. - Use Manager debug settings only for diagnosis and sanitize personal paths before sharing logs.
1. Preflight and assumptions
Use Python 3.10 or newer, Selenium 4.47.0, and one supported local
Chromium-family browser. The first driver resolution may need
network access if the matching driver is not already cached. The
application target is http://127.0.0.1:8008/ only.
2. Create an isolated project environment
Windows PowerShell
The following example makes the Create an isolated project environment behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
New-Item -ItemType Directory selenium-ch02 -Force | Out-Null
Set-Location selenium-ch02
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install selenium==4.47.0
python -c "import sys, selenium; print(sys.version); print('selenium='+selenium.__version__)"
python -m pip freeze | Set-Content evidence-dependencies.txt
Linux/macOS shell
The following example makes the Create an isolated project environment behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
mkdir -p selenium-ch02 && cd selenium-ch02
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install selenium==4.47.0
python -c "import sys, selenium; print(sys.version); print('selenium='+selenium.__version__)"
python -m pip freeze > evidence-dependencies.txt
Pinning the binding makes the project dependency reproducible. It does not pin the system browser automatically. That is why the session evidence below records the actual browser and driver versions.
3. Create the disposable loopback fixture
Create fixture/index.html:
The following example makes the Create the disposable loopback fixture behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
<!doctype html>
<html lang="en">
<head><meta charset="utf-8"><title>Selenium Chapter 02 Fixture</title></head>
<body>
<main>
<h1 id="status">Local fixture ready</h1>
<button id="confirm" type="button">Confirm session</button>
<p id="result" aria-live="polite">not confirmed</p>
</main>
<script>
document.querySelector('#confirm').addEventListener('click', () => {
document.querySelector('#result').textContent = 'confirmed';
});
</script>
</body>
</html>
Create fixture_server.py:
The following example makes the Create the disposable loopback fixture behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
from functools import partial
from pathlib import Path
ROOT = Path(__file__).parent / "fixture"
server = ThreadingHTTPServer(("127.0.0.1", 8008), partial(SimpleHTTPRequestHandler, directory=str(ROOT)))
print("fixture=http://127.0.0.1:8008/")
try:
server.serve_forever()
except KeyboardInterrupt:
pass
finally:
server.server_close()
Start it in a second terminal from the activated project environment:
python fixture_server.py
Open http://127.0.0.1:8008/ manually once if you want a
read-only sanity check. The page should show “Local fixture ready.”
4. Create the first observable session
Create session.py:
The following example makes the Create the first observable session behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
import json
from pathlib import Path
from urllib.parse import urlparse
from selenium import __version__ as selenium_version
from selenium import webdriver
from selenium.webdriver.common.by import By
URL = "http://127.0.0.1:8008/"
EVIDENCE = Path("evidence")
EVIDENCE.mkdir(exist_ok=True)
def require_loopback(url: str) -> None:
host = urlparse(url).hostname
if host not in {"127.0.0.1", "localhost", "::1"}:
raise RuntimeError(f"Refusing non-loopback target: {host}")
def public_caps(caps: dict) -> dict:
chrome = caps.get("chrome", {})
return {
"selenium": selenium_version,
"browserName": caps.get("browserName"),
"browserVersion": caps.get("browserVersion"),
"platformName": caps.get("platformName"),
"driverVersion": chrome.get("chromedriverVersion", "not-reported"),
}
require_loopback(URL)
driver = None
try:
driver = webdriver.Chrome()
print(f"session_id={driver.session_id}")
data = public_caps(driver.capabilities)
print(json.dumps(data, indent=2))
(EVIDENCE / "capabilities.json").write_text(json.dumps(data, indent=2), encoding="utf-8")
driver.get(URL)
print(f"url={driver.current_url}")
print(f"title={driver.title}")
assert driver.title == "Selenium Chapter 02 Fixture"
assert driver.find_element(By.ID, "status").text == "Local fixture ready"
driver.find_element(By.ID, "confirm").click()
assert driver.find_element(By.ID, "result").text == "confirmed"
driver.save_screenshot(str(EVIDENCE / "session.png"))
finally:
if driver is not None:
driver.quit()
The sequence matters. The loopback guard proves target scope before
any browser command. The WebDriver constructor creates the session.
Returned capabilities prove what started. Navigation mutates only
the browser context. The click mutates only the fixture DOM. The
screenshot writes one local evidence file. The
finally block closes the session even if an assertion
fails.
5. Run and interpret the first execution
The following example makes the Run and interpret the first execution behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
python session.py
Expected output shape (your versions and session identifier will differ):
session_id=<opaque session id>
{
"selenium": "4.47.0",
"browserName": "chrome",
"browserVersion": "<installed or managed browser version>",
"platformName": "<platform>",
"driverVersion": "<reported driver version or not-reported>"
}
url=http://127.0.0.1:8008/
title=Selenium Chapter 02 Fixture
Verify that evidence/capabilities.json contains no
credential or profile path, evidence/session.png shows
the synthetic fixture, and no browser window remains after the
process exits.
6. Inspect Selenium Manager only when you need more evidence
Most successful runs should not require direct Manager interaction.
When resolution fails, current Selenium Manager accepts
environment-based configuration such as SE_DEBUG=true,
SE_SKIP_DRIVER_IN_PATH=true,
SE_OFFLINE=true, SE_CACHE_PATH, and
SE_PROXY. Use these as narrow diagnostic controls.
POSIX shell diagnostic example
The following example makes the Inspect Selenium Manager only when you need more evidence behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
SE_DEBUG=true SE_AVOID_STATS=true python session.py 2> manager-debug.log || true
# Review locally. Do not publish raw personal paths or proxy credentials.
PowerShell diagnostic example
The following example makes the Inspect Selenium Manager only when you need more evidence behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
$env:SE_DEBUG = "true"
$env:SE_AVOID_STATS = "true"
python session.py 2> manager-debug.log
Remove-Item Env:SE_DEBUG
Remove-Item Env:SE_AVOID_STATS
Debug output can include cache or executable paths. Treat the raw log as local diagnostic evidence; redact usernames, home directories, proxy credentials, and private filesystem locations before attaching it to a ticket.
7. Small challenge: prove a second clean session
Run session.py a second time. Compare the two session
IDs—they should differ because each run creates a fresh session.
Compare the browser/driver versions—they should normally be stable
within the same environment. Confirm the fixture result returns to
not confirmed on initial page load because page state
is recreated, and verify no prior browser session is reused.
Then add one line that prints
driver.capabilities.get("acceptInsecureCerts"). Do not
change the capability yet; simply observe the negotiated value. The
goal is to practice inspection before configuration.
Knowledge check
Why pin selenium==4.47.0 but still record browserVersion?
The project dependency and system/managed browser are independently versioned. Pinning the binding does not prove which browser binary the session used.
What does the loopback guard protect against?
It prevents a copied lab script from silently targeting a public or production host before the browser is created.
Why capture capabilities before complex interactions?
They provide environment provenance and can explain failures caused by browser, platform, or driver drift before locator or application logic is blamed.
When should SE_DEBUG be enabled?
For focused Selenium Manager diagnosis, not as permanent noisy output. Raw logs should be reviewed locally and sanitized before sharing.
What evidence proves clean lifecycle after two runs?
Different session IDs, expected fixture state on each run, successful assertions, and no browser/driver process intentionally left open by the test.
Official references and version notes
- Selenium 4.47 release notes — release baseline for this chapter.
- Selenium downloads — current stable language bindings and Selenium Server/Grid status.
-
Install a Selenium library
— project dependency installation and the current
selenium==4.47.0example. - WebDriver getting started and first script — browser/driver roles and first-session lifecycle.
- Selenium Manager — automated driver/browser discovery, download, cache, configuration, proxy, offline, PATH-skip, debug, and cache settings.
- Driver Service class — explicit local driver-service configuration and logging.
- Browser options — W3C capabilities and browser-specific options.
- Unable to locate driver — supported driver-location troubleshooting.
- Selenium Python 4.47.0 — Python 3.10+ requirement and package metadata.
Version-sensitive behavior was rechecked against current Selenium primary documentation on 2026-08-27. The mandatory path pins the Python binding to Selenium 4.47.0, requires Python 3.10+, uses one supported local Chromium-family browser for the runnable workflow, relies on Selenium Manager as the default driver-management path, and targets only a loopback fixture. The exact browser and driver versions are intentionally discovered from the created session rather than hard-coded. Selenium Grid, WebDriver BiDi, paid browser clouds, enterprise identity, and hosted CI are not required in Chapter 02.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.