Selenium Wire extends Selenium with the ability to intercept and modify HTTP requests — something standard Selenium can't do. This unlocks powerful CAPTCHA-solving workflows: extracting sitekeys from API calls, injecting tokens into intercepted responses, and routing requests through proxies.
This guide covers request interception, CAPTCHA detection from network traffic, proxy integration, and automated solving with CaptchaAI.
What Selenium Wire Adds
| Feature | Standard Selenium | Selenium Wire |
|---|---|---|
| Read requests | No | Yes |
| Modify headers | Limited | Full control |
| Intercept responses | No | Yes |
| Proxy support | Basic | Auth proxy support |
| Network logging | DevTools only | Python objects |
| HAR export | No | Yes |
Setup
pip install seleniumwire selenium webdriver-manager requests
Basic Integration
from seleniumwire import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import requests
import time
import json
class SeleniumWireCaptchaSolver:
BASE_URL = "https://ocr.captchaai.com"
def __init__(self, api_key, proxy=None):
self.api_key = api_key
self.proxy = proxy
self.driver = None
def create_driver(self, headless=True):
options = webdriver.ChromeOptions()
if headless:
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("--window-size=1920,1080")
wire_options = {}
if self.proxy:
wire_options["proxy"] = {
"http": self.proxy,
"https": self.proxy,
}
self.driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options,
seleniumwire_options=wire_options,
)
return self.driver
def detect_captcha_from_requests(self):
"""Detect CAPTCHA type from intercepted network requests."""
for request in self.driver.requests:
url = request.url
if "recaptcha/api2/anchor" in url or "recaptcha/enterprise/anchor" in url:
# Extract sitekey from reCAPTCHA iframe URL
import re
match = re.search(r"k=([A-Za-z0-9_-]+)", url)
if match:
return {
"type": "recaptcha_v2",
"sitekey": match.group(1),
"page_url": self.driver.current_url,
}
if "recaptcha/api2/reload" in url or "recaptcha/enterprise/reload" in url:
return {
"type": "recaptcha_v3",
"sitekey": self._extract_v3_sitekey(),
"page_url": self.driver.current_url,
}
if "challenges.cloudflare.com" in url:
sitekey = self._extract_turnstile_sitekey()
if sitekey:
return {
"type": "turnstile",
"sitekey": sitekey,
"page_url": self.driver.current_url,
}
return None
def _extract_v3_sitekey(self):
for request in self.driver.requests:
if "recaptcha" in request.url and "render=" in request.url:
import re
match = re.search(r"render=([A-Za-z0-9_-]+)", request.url)
if match:
return match.group(1)
return self.driver.execute_script(
"return document.querySelector('[data-sitekey]')?.getAttribute('data-sitekey')"
)
def _extract_turnstile_sitekey(self):
return self.driver.execute_script(
"return document.querySelector('.cf-turnstile[data-sitekey]')?.getAttribute('data-sitekey')"
)
def solve_captcha(self, captcha_info):
"""Solve detected CAPTCHA via CaptchaAI API."""
params = {"key": self.api_key, "json": 1}
if captcha_info["type"] == "recaptcha_v2":
params.update({
"method": "userrecaptcha",
"googlekey": captcha_info["sitekey"],
"pageurl": captcha_info["page_url"],
})
elif captcha_info["type"] == "recaptcha_v3":
params.update({
"method": "userrecaptcha",
"googlekey": captcha_info["sitekey"],
"pageurl": captcha_info["page_url"],
"version": "v3",
"action": "verify",
"min_score": 0.7,
})
elif captcha_info["type"] == "turnstile":
params.update({
"method": "turnstile",
"key": captcha_info["sitekey"],
"pageurl": captcha_info["page_url"],
})
# Submit
resp = requests.post(f"{self.BASE_URL}/in.php", data=params)
data = resp.json()
if data["status"] != 1:
raise Exception(f"Submit: {data['request']}")
task_id = data["request"]
# Poll
for _ in range(60):
time.sleep(5)
resp = requests.get(f"{self.BASE_URL}/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1,
})
data = resp.json()
if data["request"] == "CAPCHA_NOT_READY":
continue
if data["status"] != 1:
raise Exception(f"Solve: {data['request']}")
return data["request"]
raise Exception("Timeout")
def inject_token(self, captcha_type, token):
"""Inject solved token into the page."""
if captcha_type in ("recaptcha_v2", "recaptcha_v3"):
self.driver.execute_script(f"""
document.querySelector('#g-recaptcha-response').value = '{token}';
// Try hidden textareas in iframes
document.querySelectorAll('[name="g-recaptcha-response"]').forEach(
el => el.value = '{token}'
);
""")
elif captcha_type == "turnstile":
self.driver.execute_script(f"""
const input = document.querySelector('[name="cf-turnstile-response"]');
if (input) input.value = '{token}';
""")
def close(self):
if self.driver:
self.driver.quit()
Complete Workflow
def automate_login():
solver = SeleniumWireCaptchaSolver(
api_key="YOUR_API_KEY",
proxy="http://user:pass@proxy.example.com:8080"
)
try:
driver = solver.create_driver(headless=True)
# Navigate and wait for CAPTCHA resources to load
driver.get("https://example.com/login")
time.sleep(3)
# Fill form
driver.find_element("id", "email").send_keys("user@example.com")
driver.find_element("id", "password").send_keys("password123")
# Detect CAPTCHA from network requests
captcha = solver.detect_captcha_from_requests()
if captcha:
print(f"Found {captcha['type']} (sitekey: {captcha['sitekey'][:20]}...)")
token = solver.solve_captcha(captcha)
solver.inject_token(captcha["type"], token)
print(f"Token injected: {token[:50]}...")
# Submit
driver.find_element("id", "submit").click()
time.sleep(3)
print(f"Current URL: {driver.current_url}")
finally:
solver.close()
automate_login()
Intercepting and Modifying Requests
Add Custom Headers
def add_headers_interceptor(request):
request.headers["X-Custom-Header"] = "value"
request.headers["Accept-Language"] = "en-US,en;q=0.9"
driver = solver.create_driver()
driver.request_interceptor = add_headers_interceptor
Block Tracking Scripts
def block_trackers(request):
blocked = ["analytics", "tracking", "ads", "facebook.net", "doubleclick"]
if any(b in request.url for b in blocked):
request.abort()
driver.request_interceptor = block_trackers
Modify Response Content
def modify_response(request, response):
if "captcha-config" in request.url:
# Modify CAPTCHA configuration response
import json
body = json.loads(response.body.decode("utf-8"))
body["difficulty"] = "easy"
response.body = json.dumps(body).encode("utf-8")
driver.response_interceptor = modify_response
Extracting CAPTCHA Parameters from API Calls
Some sites load CAPTCHA parameters via AJAX. Selenium Wire captures these:
def extract_captcha_from_api(driver, timeout=10):
"""Watch network for CAPTCHA configuration API calls."""
start = time.time()
while time.time() - start < timeout:
for request in driver.requests:
if request.response and "captcha" in request.url.lower():
try:
data = json.loads(request.response.body.decode())
if "sitekey" in str(data) or "siteKey" in str(data):
return data
except (json.JSONDecodeError, UnicodeDecodeError):
pass
time.sleep(0.5)
return None
Proxy Rotation per Request
from seleniumwire import webdriver
proxies = [
"http://user:pass@proxy1.example.com:8080",
"http://user:pass@proxy2.example.com:8080",
"http://user:pass@proxy3.example.com:8080",
]
current_proxy = [0]
def rotate_proxy(request):
proxy = proxies[current_proxy[0] % len(proxies)]
request.headers["Proxy-Authorization"] = None # Reset
current_proxy[0] += 1
wire_options = {
"proxy": {
"http": proxies[0],
"https": proxies[0],
}
}
driver = webdriver.Chrome(seleniumwire_options=wire_options)
Network Traffic Analysis
def analyze_captcha_traffic(driver):
"""Analyze all CAPTCHA-related network traffic."""
captcha_requests = []
for request in driver.requests:
if any(k in request.url for k in ["recaptcha", "turnstile", "hcaptcha", "geetest"]):
captcha_requests.append({
"url": request.url,
"method": request.method,
"status": request.response.status_code if request.response else None,
"content_type": request.response.headers.get("Content-Type") if request.response else None,
"size": len(request.response.body) if request.response and request.response.body else 0,
})
print(f"\nCAPTCHA Network Traffic ({len(captcha_requests)} requests):")
for req in captcha_requests:
print(f" [{req['status']}] {req['method']} {req['url'][:80]}...")
return captcha_requests
HAR Export for Debugging
from seleniumwire.utils import decode
def export_har(driver, filename="captcha_traffic.har"):
"""Export HAR file for debugging CAPTCHA issues."""
import json
har = {
"log": {
"version": "1.2",
"entries": []
}
}
for request in driver.requests:
if not request.response:
continue
entry = {
"request": {
"method": request.method,
"url": request.url,
"headers": [{"name": k, "value": v} for k, v in request.headers.items()],
},
"response": {
"status": request.response.status_code,
"headers": [{"name": k, "value": v} for k, v in request.response.headers.items()],
},
}
har["log"]["entries"].append(entry)
with open(filename, "w") as f:
json.dump(har, f, indent=2)
print(f"HAR exported: {filename} ({len(har['log']['entries'])} entries)")
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
seleniumwire import error |
Not installed | pip install seleniumwire |
| No requests captured | Page loaded too fast | Add time.sleep(3) after navigation |
| SSL errors with proxy | Certificate issues | Set seleniumwire_options['verify_ssl'] = False |
| Memory leak | Request storage grows | Call del driver.requests periodically |
| Slow page loads | All traffic proxied | Use exclude_hosts in wire options |
| CAPTCHA not detected | Loaded via iframe | Check driver.requests for iframe URLs |
FAQ
What's the difference between Selenium Wire and standard Selenium?
Selenium Wire wraps Selenium WebDriver to add HTTP request/response interception. It's a drop-in replacement — same API with extra network capabilities.
When should I use Selenium Wire vs Puppeteer?
Use Selenium Wire for Python projects that need request interception. Use Puppeteer (Node.js) if you're already in the JavaScript ecosystem.
Does Selenium Wire work with undetected-chromedriver?
Yes. Replace webdriver.Chrome with uc.Chrome from undetected-chromedriver while keeping Selenium Wire's interception features.
How does request interception help with CAPTCHAs?
It lets you detect CAPTCHA types from network traffic (more reliable than DOM parsing), extract parameters from API responses, and inject tokens into intercepted requests.
Related Guides
- Python Selenium + CaptchaAI Complete Guide
- Chrome DevTools Protocol + CaptchaAI
- Proxy Quality and CAPTCHA Solve Rates
Master request interception for CAPTCHA automation — get your CaptchaAI key and build with Selenium Wire.
Discussions (0)
Join the conversation
Sign in to share your opinion.
Sign InNo comments yet.