Playwright bietet im Vergleich zu Selenium eine schnellere Ausführung, native Async-Unterstützung und Multi-Browser-Unterstützung. Dieser Leitfaden behandelt die vollständige Integration mit CaptchaAI zum Lösen von reCAPTCHA-, Turnstile- und Bild-CAPTCHAs in Playwright-Automatisierungsskripten.
Voraussetzungen
pip install playwright aiohttp
playwright install chromium
Asynchroner CaptchaAI-Löser
import aiohttp
import asyncio
API_KEY = "YOUR_API_KEY"
async def solve_captcha(method, **params):
"""Async CaptchaAI solver for Playwright workflows."""
async with aiohttp.ClientSession() as session:
# Submit task
submit_data = {
"key": API_KEY,
"method": method,
"json": 1,
**params,
}
async with session.post("https://ocr.captchaai.com/in.php", data=submit_data) as resp:
data = await resp.json(content_type=None)
if data.get("status") != 1:
raise Exception(f"Submit error: {data.get('request')}")
task_id = data["request"]
# Poll for result
for _ in range(30):
await asyncio.sleep(5)
async with session.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}) as resp:
result = await resp.json(content_type=None)
if result.get("status") == 1:
return result["request"]
if result.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
raise Exception("CAPTCHA unsolvable")
raise TimeoutError("Solve timed out")
Playwright-Browser konfigurieren
from playwright.async_api import async_playwright
async def create_browser():
"""Launch Playwright browser for CAPTCHA automation."""
pw = await async_playwright().start()
browser = await pw.chromium.launch(
headless=False,
args=[
"--disable-blink-features=AutomationControlled",
],
)
context = await browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
viewport={"width": 1920, "height": 1080},
locale="en-US",
)
page = await context.new_page()
return pw, browser, context, page
reCAPTCHA v2 mit Playwright
import re
async def solve_recaptcha_v2_playwright(page, url):
"""Complete reCAPTCHA v2 solve in Playwright."""
await page.goto(url, wait_until="networkidle")
# Extract sitekey from the page
content = await page.content()
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]{40})["\']', content)
if not match:
raise ValueError("reCAPTCHA sitekey not found")
sitekey = match.group(1)
print(f"Sitekey: {sitekey}")
# Solve via CaptchaAI
token = await solve_captcha(
"userrecaptcha",
googlekey=sitekey,
pageurl=url,
)
print(f"Token: {token[:50]}...")
# Inject token
await page.evaluate(f"""() => {{
document.getElementById('g-recaptcha-response').value = '{token}';
document.getElementById('g-recaptcha-response').style.display = 'block';
}}""")
# Trigger callback if available
await page.evaluate(f"""() => {{
if (typeof ___grecaptcha_cfg !== 'undefined') {{
var clients = ___grecaptcha_cfg.clients;
for (var key in clients) {{
var client = clients[key];
try {{
Object.keys(client).forEach(function(k) {{
if (client[k] && client[k].callback) {{
client[k].callback('{token}');
}}
}});
}} catch(e) {{}}
}}
}}
}}""")
# Submit form
await page.click("button[type='submit'], input[type='submit']")
await page.wait_for_load_state("networkidle")
return token
Cloudflare Turnstile mit Playwright
async def solve_turnstile_playwright(page, url):
"""Complete Turnstile solve in Playwright."""
await page.goto(url, wait_until="networkidle")
content = await page.content()
# Extract sitekey
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', content)
if not match:
match = re.search(r"sitekey\s*:\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", content)
if not match:
raise ValueError("Turnstile sitekey not found")
sitekey = match.group(1)
print(f"Turnstile sitekey: {sitekey}")
# Solve via CaptchaAI
token = await solve_captcha(
"turnstile",
sitekey=sitekey,
pageurl=url,
)
# Inject token into hidden inputs
await page.evaluate(f"""() => {{
document.querySelectorAll('[name="cf-turnstile-response"]')
.forEach(el => el.value = '{token}');
}}""")
# Submit
await page.click("button[type='submit'], input[type='submit']")
await page.wait_for_load_state("networkidle")
return token
Bild-CAPTCHA mit Playwright
async def solve_image_captcha_playwright(page, captcha_selector):
"""Solve image CAPTCHA visible on the page."""
captcha_element = page.locator(captcha_selector)
# Screenshot the CAPTCHA image
img_bytes = await captcha_element.screenshot()
import base64
img_base64 = base64.b64encode(img_bytes).decode()
# Solve via CaptchaAI
answer = await solve_captcha("base64", body=img_base64)
print(f"Answer: {answer}")
# Type the answer
captcha_input = page.locator("input[name='captcha'], input[name='code'], input.captcha-input")
await captcha_input.fill(answer)
return answer
Abfangen von Netzwerkanfragen
Der Playwright zeichnet sich durch das Abfangen auf Anfrage aus. Verwenden Sie es, um CAPTCHA-Parameter aus API-Aufrufen zu extrahieren:
async def intercept_captcha_params(page, url):
"""Intercept network requests to find CAPTCHA parameters."""
captcha_params = {}
async def handle_request(route, request):
if "recaptcha" in request.url or "turnstile" in request.url:
from urllib.parse import urlparse, parse_qs
parsed = urlparse(request.url)
params = parse_qs(parsed.query)
captcha_params.update(params)
print(f"Intercepted: {request.url}")
await route.continue_()
await page.route("**/*", handle_request)
await page.goto(url, wait_until="networkidle")
await page.unroute("**/*")
return captcha_params
Komplette Automatisierungsklasse
import re
import asyncio
import aiohttp
import base64
from playwright.async_api import async_playwright
API_KEY = "YOUR_API_KEY"
class PlaywrightCaptchaSolver:
"""Complete Playwright + CaptchaAI automation class."""
def __init__(self, api_key, headless=False):
self.api_key = api_key
self.headless = headless
self.pw = None
self.browser = None
self.context = None
self.page = None
async def start(self):
"""Initialize the browser."""
self.pw = await async_playwright().start()
self.browser = await self.pw.chromium.launch(
headless=self.headless,
args=["--disable-blink-features=AutomationControlled"],
)
self.context = await self.browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
viewport={"width": 1920, "height": 1080},
)
await self.context.add_init_script(
"Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
)
self.page = await self.context.new_page()
async def stop(self):
"""Close the browser."""
if self.browser:
await self.browser.close()
if self.pw:
await self.pw.stop()
async def navigate(self, url):
"""Navigate and wait for page to load."""
await self.page.goto(url, wait_until="networkidle")
async def detect_captcha(self):
"""Detect which CAPTCHA type is present."""
content = await self.page.content()
if re.search(r'data-sitekey=["\'][A-Za-z0-9_-]{40}["\']', content):
if "recaptcha" in content.lower():
return "recaptcha_v2"
if "cf-turnstile" in content or "challenges.cloudflare.com/turnstile" in content:
return "turnstile"
if re.search(r"render=[A-Za-z0-9_-]{40}", content):
return "recaptcha_v3"
img_count = await self.page.locator(
"img.captcha, img[alt*='captcha'], img[src*='captcha']"
).count()
if img_count > 0:
return "image"
return None
async def solve_and_submit(self, url, form_data=None):
"""Full workflow: navigate, detect, solve, fill, submit."""
await self.navigate(url)
captcha_type = await self.detect_captcha()
if captcha_type:
print(f"Detected: {captcha_type}")
await self._solve(captcha_type)
if form_data:
for name, value in form_data.items():
try:
await self.page.fill(f"[name='{name}']", value)
except Exception:
pass
await self.page.click("button[type='submit'], input[type='submit']")
await self.page.wait_for_load_state("networkidle")
return self.page.url
async def _solve(self, captcha_type):
content = await self.page.content()
url = self.page.url
if captcha_type == "recaptcha_v2":
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]{40})["\']', content)
token = await self._api_solve("userrecaptcha", googlekey=match.group(1), pageurl=url)
await self.page.evaluate(f"""() => {{
document.getElementById('g-recaptcha-response').value = '{token}';
}}""")
elif captcha_type == "turnstile":
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', content)
token = await self._api_solve("turnstile", sitekey=match.group(1), pageurl=url)
await self.page.evaluate(f"""() => {{
document.querySelectorAll('[name="cf-turnstile-response"]')
.forEach(el => el.value = '{token}');
}}""")
elif captcha_type == "image":
img = self.page.locator("img.captcha, img[alt*='captcha'], img[src*='captcha']").first
img_bytes = await img.screenshot()
answer = await self._api_solve("base64", body=base64.b64encode(img_bytes).decode())
await self.page.fill("input[name='captcha'], input[name='code']", answer)
async def _api_solve(self, method, **params):
async with aiohttp.ClientSession() as session:
async with session.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key, "method": method, "json": 1, **params,
}) as resp:
data = await resp.json(content_type=None)
if data.get("status") != 1:
raise Exception(f"Submit error: {data.get('request')}")
task_id = data["request"]
for _ in range(30):
await asyncio.sleep(5)
async with session.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key, "action": "get", "id": task_id, "json": 1,
}) as resp:
result = await resp.json(content_type=None)
if result.get("status") == 1:
return result["request"]
raise TimeoutError("Solve timed out")
# Usage
async def main():
solver = PlaywrightCaptchaSolver(API_KEY)
await solver.start()
try:
result = await solver.solve_and_submit(
"https://example.com/login",
form_data={"email": "user@example.com", "password": "pass123"},
)
print(f"Result: {result}")
finally:
await solver.stop()
asyncio.run(main())
Playwright vs. Selenium zum Lösen von CAPTCHAs
| Funktion | Playwright | Selen |
|---|---|---|
| Asynchron nativ | Ja | Nein (erfordert Einfädeln) |
| Browser-Konfiguration | Bessere Standardeinstellungen | Erfordert mehr Konfiguration |
| Geschwindigkeit | Schneller | Langsamere Seitenladevorgänge |
| Fordern Sie ein Abfangen an | Eingebaut | Erfordert Proxy/extension |
| Multibrowser | Chromium, Firefox, WebKit | Chrome, Firefox, Edge, Safari |
| API-Stil | Versprechensbasiert, modern | Imperativ, traditionell |
Fehlerbehebung
| Symptom | Ursache | Beheben |
|---|---|---|
page.evaluate schlägt fehl |
Inhalt nicht geladen | Verwenden Sie wait_until="networkidle" |
| Token-Injection funktioniert nicht | Falscher Elementselektor | Überprüfen Sie mit page.content(), um das tatsächliche Element zu finden |
| Erkennung von Playwrightn | Fehlendes Init-Skript | Webdriver-Überschreibung in add_init_script hinzufügen |
Zeitüberschreitung bei networkidle |
Unendliche Abfrageskripte | Verwenden Sie stattdessen wait_until="domcontentloaded" |
| Der Bild-Screenshot ist leer | Element ausgeblendet | Scrollen Sie in die Ansicht: await element.scroll_into_view_if_needed() |
Häufig gestellte Fragen
Sollte ich Playwright oder Selenium zum Lösen von CAPTCHAs verwenden?
Verwenden Sie Playwright für neue Projekte – es bietet eine bessere Leistung und native Async-Unterstützung. Verwenden Sie Selenium, wenn Sie bereits über eine Selenium-Codebasis verfügen.
Kann Playwright im Headless-Modus laufen?
Ja. Legen Sie headless=True in launch() fest. Einige Websites erkennen den Headless-Modus. Testen Sie daher beide Konfigurationen. CaptchaAI löst auf seiner eigenen Infrastruktur, sodass Headless vs. Headed keinen Einfluss auf den Lösungserfolg haben.
Wie gehe ich mit Seiten um, die CAPTCHA dynamisch laden?
Verwenden Sie page.wait_for_selector, um zu warten, bis das CAPTCHA-Element angezeigt wird, oder verwenden Sie page.wait_for_function, um zu warten, bis das CAPTCHA-JavaScript bereit ist.
Zusammenfassung
Python Playwright + CaptchaAI liefert einen modernen asynchronen CAPTCHA-Automatisierungs-Stack. PlaywrightCaptchaSolver übernimmt den vollständigen Erkennungs-, Lösungs- und Einreichungs-Workflow mit nativer async-Unterstützung und Netzwerkabfang.
Verwandte Leitfäden
- Python Seleniumium + CaptchaAI
- Node.js Playwright + CaptchaAI
- Playwright CAPTCHA-Verwaltung