undetected-chromedriver'da CAPTCHA Nasıl Çözülür (Python)

undetected-chromedriver, otomasyon bayrakları sızmasın diye Chrome'a yama uygular. Bu sizi sayfaya sokar. Ama bir reCAPTCHA onay kutusunu aşmanızı sağlamaz; çünkü bir widget parmak izi kontrolü değil, token gereksinimidir. undetected-chromedriver captcha'sının yine de çözülmesi ve yanıtın DOM'a enjekte edilmesi gerekir.
Dört adım: yamalı sürücüyü başlatın, sitekey'i sayfadan okuyun, yerel olarak çözün, token'ı sayfanın beklediği yere koyun. Tamamı Python'da aşağıda.
undetected-chromedriver neyi yapar, neyi yapmaz
| Sinyal | Sürücü tarafından halledilir |
|---|---|
navigator.webdriver ve CDP'nin ele veren izleri | Evet |
| Yamalı ikili dosya sayesinde sürücü, sürücü olarak algılanmaz | Evet |
| Bir giriş formundaki reCAPTCHA v2 onay kutusu | Hayır |
| Sayfanın tetiklediği görünmez bir v2 veya v3 challenge'ı | Hayır |
| Bir Turnstile widget'ı | Hayır |
Bu ayrım önemli, çünkü engellenen bir kazıyıcı için verilen olağan tavsiye “stealth ekle” oluyor. Ekranda bir widget varsa, hiçbir stealth katmanı onu ortadan kaldırmaz. Size bir token gerekir.
Neye ihtiyacınız var
- Chrome kurulu olmalı ve CapSkip şu adreste çalışıyor olmalı:
127.0.0.1:8080. Uygulamayı kurulum kılavuzu sayfası anlatır. - Python 3.10 veya daha yenisi.
- Üç paket.
# the patched driver, selenium itself, and the local solver pip install undetected-chromedriver selenium capskip
Adım 1: yamalı sürücüyü başlatın
Şu şekilde içe aktarın: uc ve tarayıcıyı düz Selenium'da yapacağınız gibi kurun. Seçenekler şuradan gelir: uc.ChromeOptions(), Selenium'unkilerden değil; çünkü kütüphane bunlara yol boyunca yama uygular:
# pip install undetected-chromedriver
import undetected_chromedriver as uc
options = uc.ChromeOptions()
options.add_argument("--window-size=1280,800")
# use_subprocess keeps the patched binary alive long enough
# to shut down cleanly on Windows.
driver = uc.Chrome(options=options, use_subprocess=True)
driver.get("https://example.com/login")Bunun üstüne başka bir stealth eklentisi yığmayın. Aynı özellikler üzerinde çekişen iki yamalayıcı başlı başına bir tespit sinyalidir ve eskiden çalışan bir kurulumun aniden durmasının yaygın nedenlerinden biridir.
Adım 2: sitekey'i sayfadan okuyun
Sitekey, widget elemanı üzerindeki genel bir özniteliktir. Kodun içine gömmek yerine canlı DOM'dan okuyun; çünkü birçok site anahtarları ortama göre değiştirir:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# The widget is injected by script, so wait for it.
widget = WebDriverWait(driver, 20).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "[data-sitekey]"))
)
sitekey = widget.get_attribute("data-sitekey")
page_url = driver.current_url
print(sitekey)Kullan driver.current_url kullanılır, istediğiniz URL değil. Site sizi bir challenge yoluna yönlendirdiyse, çözücüye gerçekte indiğiniz sayfanın bildirilmesi gerekir.
Adım 3: yerel olarak çözün
CapSkip kendi makinenizde çalışır, dolayısıyla çözüm localhost'a yapılan bir çağrıdır. Hesap yok, çözüm başına ücret yok; sitekey ve sayfa URL'si dışında makineden hiçbir şey çıkmaz:
# pip install capskip
from capskip import CapSkip
solver = CapSkip(
host="127.0.0.1",
port=8080,
recaptchaTimeout=300, # seconds, also covers Turnstile
)
result = solver.recaptcha(sitekey=sitekey, url=page_url)
token = result["code"] # the g-recaptcha-response valueVaryantlar farklı metotlar değil, seçeneklerdir. Şunları ekleyin: invisible=1 görünmez bir v2 widget'ı için, version="v3" şununla: action v3 için ve enterprise=1 Enterprise ürünü için.
Adım 4: token'ı enjekte edin ve geri çağırmayı tetikleyin
Token'ın gizli g-recaptcha-response textarea'sına düşmesi gerekir. Düz bir form gönderimi için bu tek başına yeterlidir, çünkü alan formun geri kalanıyla birlikte gönderilir:
driver.execute_script(
"document.getElementById('g-recaptcha-response')"
".innerHTML = arguments[0];",
token,
)
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()Tek sayfalık uygulamalar farklıdır. textarea'yı hiç okumazlar; token'ı kendilerine verecek olan, widget'ın kendi geri çağırma fonksiyonunu beklerler. Fonksiyon adı eleman üzerinde tanımlıdır, dolayısıyla onu doğrudan çağırabilirsiniz:
callback = widget.get_attribute("data-callback")
if callback:
# Call the page's own handler with the token, exactly as
# the widget would have done.
driver.execute_script(f"{callback}(arguments[0]);", token)Enjeksiyondan sonra hiçbir şey olmuyorsa ve ortada şu yoksa: data-callback, sayfa geri çağırmayı işaretleme yerine JavaScript içinde bağlıyordur. Bu durumda onu nasıl bulacağınızı reCAPTCHA v2 callback çözücü sayfası anlatıyor.
Aynı sürücüde Turnstile
Cloudflare Turnstile de iki ad değişikliğiyle aynı şekilde çalışır. Yanıt alanı şudur: cf-turnstile-response, üstelik bu bir textarea değil, input'tur:
result = solver.turnstile(sitekey=sitekey, url=page_url)
driver.execute_script(
"document.querySelector('[name=cf-turnstile-response]')"
".value = arguments[0];",
result["code"],
)Bu, bir forma gömülü widget'ı kapsar. Tam sayfa bir ara sayfa (interstitial) challenge'ı ise iki ek değere ve çözümün yapıldığı user agent'a ihtiyaç duyar; bunu Turnstile çözücü sayfası açıklıyor.
Tam çalışan örnek
# pip install undetected-chromedriver selenium capskip
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from capskip import (
CapSkip, NetworkException, ApiException, TimeoutException,
)
URL = "https://example.com/login"
solver = CapSkip(host="127.0.0.1", port=8080)
driver = uc.Chrome(options=uc.ChromeOptions(), use_subprocess=True)
try:
driver.get(URL)
widget = WebDriverWait(driver, 20).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "[data-sitekey]"))
)
sitekey = widget.get_attribute("data-sitekey")
result = solver.recaptcha(sitekey=sitekey, url=driver.current_url)
driver.execute_script(
"document.getElementById('g-recaptcha-response')"
".innerHTML = arguments[0];",
result["code"],
)
callback = widget.get_attribute("data-callback")
if callback:
driver.execute_script(f"{callback}(arguments[0]);", result["code"])
else:
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
except NetworkException:
print("CapSkip is not running on 127.0.0.1:8080")
except (ApiException, TimeoutException) as err:
print(f"solve failed: {err}")
finally:
driver.quit() # always, or the patched binary lingersÇözüm ve gönderimi tek bir çalıştırmada yapın. Bir reCAPTCHA token'ı yaklaşık iki dakika boyunca kabul edilir; yani çözen, sonra otuz saniye başka iş yapan ve ardından gönderen bir betik sorunsuzdur. Token'ları sonrası için kuyruğa alan bir betik ise değildir.
Yaygın hatalar
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
This version of ChromeDriver only supports Chrome version N | Yamalı sürücü, yanlış Chrome ana sürümünü tahmin etti | Açıkça belirtin: uc.Chrome(version_main=N) burada N, kurulu Chrome ana sürümünüzdür |
OSError: [WinError 6] The handle is invalid çıkışta | Sürücü, kapanmadan önce çöp toplayıcı tarafından temizlendi | Çağırın: driver.quit() finally bloğu içinde; ayrıca şunu koruyun: use_subprocess=True |
NoSuchElementException şunu bulmaya çalışırken: [data-sitekey] | Widget bir iframe içinde ya da henüz render edilmemiş | Yukarıdaki gibi bekleyin. Bir iframe için sitekey'i iframe'in src sorgu dizesinden okuyun |
ERROR_GOOGLEKEY | Çözücüye boş ya da kırpılmış bir sitekey ulaştı | Çözmeden önce yazdırın. Bakın: ERROR_GOOGLEKEY hatasını düzeltme |
NetworkException | CapSkip çalışmıyor ya da port farklı | Uygulamayı başlatın ve ayarlarından portu kontrol edin |
| Token enjekte edildi, form yine de reddetti | Sayfa bir geri çağırma kullanıyor ve textarea'yı hiç okumuyor | Çağırın: data-callback fonksiyonunu token ile çağırın |
Her hata kodu ve parametre şurada listelenmiştir: API dokümantasyonu.
Sık sorulan sorular
undetected-chromedriver CAPTCHA'ları kendi başına çözer mi?
Hayır. Bir tarayıcının işaretlenmesine yol açan otomasyon sinyallerini gizler. Render edilmiş bir widget yine de geçerli bir token bekler; yani onu siz çözer ve sonucu enjekte edersiniz. Bu iki iş birbirinin alternatifi değil, tamamlayıcısıdır.
Headless modda çalıştırabilir miyim?
Evet, şununla: uc.Chrome(headless=True), bu, Selenium'un bayrağı yerine kütüphanenin kendi headless yamalarını uygular. Headed moda kıyasla daha fazla challenge bekleyin. Token enjeksiyonunun kendisi her iki durumda da aynı şekilde çalışır.
Çözüm için proxy'ye ihtiyacım var mı?
Yalnızca tarayıcı zaten bir proxy üzerinden gidiyorsa. Aynısını şu şekilde iletin: proxy={"type": "HTTPS", "uri": "user:pass@host:port"} böylece çözüm ile gönderim aynı ağ yolunu paylaşır. Proxy'ler reCAPTCHA, Turnstile ve GeeTest için geçerlidir; görsel CAPTCHA'lar için asla.
Bu, düz Selenium ile de çalışır mı?
Evet. 2 ile 4 arasındaki adımlar sıradan WebDriver çağrılarıdır; bu yüzden standart Selenium'da, Selenium Grid'de ve uzak sürücülerde değişmeden çalışır. Yalnızca 1. adım yamalı kütüphaneye özgüdür.
Özet
Parmak izini undetected-chromedriver'a bırakın, widget'ı ise kendiniz halledin. Şunu bekleyin: [data-sitekey], localhost üzerinden çözün, token'ı şuraya yazın: g-recaptcha-response, ardından şunu çağırın: data-callback sayfa böyle bir tane bildiriyorsa. Sürücüyü bir finally bloğu içinde kapatın ki yamalı ikili dosya ortalıkta kalmasın.
Daha geniş Selenium yüzeyi Selenium CAPTCHA çözücü sayfasında, tam metot listesi ise Python CAPTCHA çözücü sayfasında; ayrıca web scraping için CAPTCHA çözme bunu yüksek hacimde çalıştırmayı ele alıyor. CapSkip bir yerel captcha çözücü, dolayısıyla yukarıdaki her çözüm kendi makinenizde gerçekleşir.
