Camoufox’ta Main World Eval Kullanarak CAPTCHA Nasıl Çözülür

Camoufox’ta bir captcha adımı diğerlerinin hepsine benzer: sitekey'i okuyun, bir çözücüye gönderin, token'ı sayfaya yazın. Camoufox’un farkı üçüncü hamlededir. evaluate’e verdiğiniz JavaScript'i, sayfanın göremediği yalıtılmış bir kapsamda çalıştırır ve yalıtılmış bir kapsam sayfanın DOM'unu değiştiremez. Yazma işleminiz hata vermeden geri döner, textarea boş kalır ve form doğrulamayı geçemez. Çözüm, tek bir başlatma seçeneği ve iki karakterlik bir önektir.
Neye ihtiyacınız var
- Python 3.10 veya daha yenisi. Camoufox 0.5, Playwright sürümünü kendisi sabitler; bu yüzden çözümlemeyi pip'e bırakın.
- fetch komutuyla bir kez indirilmiş Camoufox tarayıcısı. Bu bir Firefox sürümüdür, Chromium değil.
- Korumalı formun sayfa URL’si. Sitekey çalışma zamanında okunur.
- Betik ile çözücü aynı makinedeyse Yerel modda, değilse Sunucu modunda çalışan CapSkip. Her ikisi de şurada açıklanıyor: bağlantı ayarları.
# The geoip extra is optional and worth having if you use proxies. pip install -U capskip "camoufox[geoip]" # Downloads the browser itself. Run once per machine. camoufox fetch
Alışıldık token enjeksiyonu burada neden hiçbir işe yaramaz
Camoufox, Playwright’ın etrafına ince bir Python sarmalayıcı geçirilmiş, yamalanmış bir Firefox’tur. Sarmalayıcı sınıf bir Playwright context manager'ıdır; dolayısıyla ondan geri aldığınız şey sıradan bir Playwright tarayıcı nesnesidir ve halihazırda bildiğiniz her locator, tıklama ve gezinme değişmeden çalışır. İyi haber bu ve kütüphanenin büyük kısmı da bundan ibaret.
İstisna, script çalıştırmadır. Camoufox tüm JavaScript'i sayfaya görünmeyen yalıtılmış bir kapsamda çalıştırır; zaten var olma nedeni de budur: bir site, kendisini kurcalayan otomasyonu göremez. Okuma bundan etkilenmez, çünkü Playwright’ın kendi locator metotları o kapsamdan değil, tarayıcı protokolü üzerinden ilerler. Yazma ise etkilenir ve akılda tutulması gereken cümle şudur: yalıtılmış bir kapsam DOM'u değiştiremez. Oradaki bir token ataması sessizce atılır.
Camoufox’un buna yanıtı bir main world kaçış kapağıdır. Başlatırken main_world_eval geçirin, ardından gerçek sayfaya dokunması gereken her script'in başına mw: ekleyin; script sayfanın kendi kapsamında çalışır. Bunun iki bedeli var. Site, orada çalışan kodu tespit edebilir; bu yüzden onu yalnızca enjeksiyon için kullanın, başka hiçbir şey için değil. Ayrıca main world dışına element referansları döndüremezsiniz, yalnızca JSON olarak hayatta kalan değerleri döndürebilirsiniz.
Adım 1: main world etkin şekilde başlatın
Seçenek varsayılan olarak kapalıdır ve başlatma anında ayarlanması gerekir. Sonradan tek bir çağrı için açmanın bir yolu yoktur.
# pip install camoufox[geoip]
from camoufox.sync_api import Camoufox
with Camoufox(main_world_eval=True, headless=True) as browser:
page = browser.new_page()
page.goto("https://example.com/page-with-recaptcha")
# browser is a normal Playwright Browser from here on.
print(page.title())Devam etmeden önce bilinmeye değer iki komşu seçenek var. humanize, imleci insan görünümlü bir yol boyunca hareket ettirir ve pencereyi geçmesi yaklaşık 1,5 saniyeyi bulur; token enjekte etmek yerine widget'a kendiniz tıklıyorsanız bu önemlidir. disable_coop ise Cross-Origin-Opener-Policy'yi devre dışı bırakır; böylece aralarında Cloudflare Turnstile onay kutusunun da bulunduğu, cross-origin iframe'lerin içindeki öğelere tıklamak mümkün hale gelir.
Adım 2: sitekey'i sayfadan okuyun
Sitekey, widget iframe’inin içinde değil, ana belgede yer alır. Google’ın işaretlemesi onu bir kapsayıcıya data-sitekey özniteliği olarak koyar ve sıradan bir Playwright locator'ı bunu okur. Burada main world önekine gerek yoktur, çünkü bu yol yalıtılmış kapsamdan hiç geçmez.
# Locators wait by default, so this doubles as a wait
# condition for a widget that renders late.
holder = page.locator("div.g-recaptcha")
holder.wait_for(state="attached", timeout=15000)
sitekey = holder.get_attribute("data-sitekey")
print(sitekey) # 6LxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxBazı siteler sitekey'i ana sayfada hiç açığa çıkarmaz ve onu yalnızca widget iframe’inin URL'sinde geçirir. Bu durumda değeri sorgu dizesinden okuyun.
# Fallback: the k= parameter on the anchor iframe.
from urllib.parse import urlparse, parse_qs
src = page.locator("iframe[src*='recaptcha/api2/anchor']").get_attribute("src")
sitekey = parse_qs(urlparse(src).query)["k"][0]Üzerine bir çözüm harcamadan önce değeri kontrol edin. Boş bir sitekey ta çözücüye kadar gider ve geriye şu döner: ERROR_GOOGLEKEY, yani asıl başarısız olan locator'dan çok uzak bir nokta.
Adım 3: kendi makinenizde çözün
Python SDK'sı CapSkip ile 8080 portu üzerinden konuşur ve token'ı düz bir dize olarak döndürür. Tek bir metot reCAPTCHA v2, Invisible, Enterprise ve v3'ü kapsar; çeşitler ayrı çağrılar olarak değil, seçenek olarak geçirilir.
# pip install capskip from capskip import CapSkip solver = CapSkip(host="127.0.0.1", port=8080) # Invisible v2 takes invisible=1, Enterprise takes enterprise=1, # and v3 takes version="v3" with an action. result = solver.recaptcha(sitekey=sitekey, url=PAGE_URL) token = result["code"] # the g-recaptcha-response value
Turnstile ve GeeTest'in kendi metotları vardır ve aynı biçimi alır. Turnstile ayrıca çözümün yapıldığı user agent'ı da döndürür; bir challenge sayfası, o user agent'ı token ile birlikte geri göndermezseniz token'ı reddeder. Tam parametre listeleri şurada: CapSkip API dokümantasyonu.
Camoufox bir de async sınıfla gelir ve Python SDK'sındaki AsyncCapSkip, senkron olanın takma adı değil, gerçek bir asyncio uygulamasıdır. Aynı anda birden fazla context sürüyorsanız ikisini birlikte kullanın; böylece bir sayfadaki çözüm diğerlerini bekletmez.
Adım 4: token'ı main world içinde enjekte edin
İşte bu tarayıcıya özgü olan kısım. Yanıt textarea'sı display:none ile gizlenmiştir; bu yüzden hiçbir otomasyon aracı içine yazamaz ve değeri JavaScript ile atamanız gerekir. Script'in başına mw: ekleyin ki sayfanın kendi kapsamında çalışsın; dizeyi de f-string yerine json.dumps ile kurun, çünkü bir JSON dize sabiti, tırnak ve kaçış karakterleri dahil, aynı zamanda geçerli bir JavaScript dize sabitidir.
# The mw: prefix is what makes this write land.
import json
page.evaluate(
"mw:document.getElementById('g-recaptcha-response').value = "
+ json.dumps(token)
)
page.click("button[type=submit]")Token'ın yerine ulaştığını doğrulamanın bir püf noktası var. main world dışına bir element veremezsiniz; bu yüzden düğüm yerine bir değer döndürün. Bir uzunluk yeterlidir ve tam olarak öğrenmek istediğiniz şeyi söyler.
# Return a number, never the element itself.
length = page.evaluate(
"mw:document.getElementById('g-recaptcha-response').value.length"
)
print(length) # 0 means the injection did not landSite, form gönderilirken textarea'yı okumak yerine bir başarı callback'i tanımlıyorsa, değeri ayarladıktan sonra o callback'i çağırın. main world kullanımının yalnızca kullanışlı değil, zorunlu olduğu durum budur; çünkü sayfanın tanımladığı bir fonksiyon yalıtılmış kapsamda hiç bulunmaz. Fonksiyon adını tahmin etmek yerine sayfanın kendi işaretlemesinden okuyun. Her iki gönderim biçimi de temelde sıradan reCAPTCHA v2'dir ve ikisi de ayrıntılı olarak şurada anlatılıyor: reCAPTCHA v2 çözücü sayfası.
Tam çalışan örnek
Yukarıdakilerin tamamı tek bir script'te. Çözücü bir kez oluşturulur, blok bittiğinde tarayıcı kendini kapatır ve sitekey, üzerine bir çözüm harcanmadan önce kontrol edilir.
# pip install capskip camoufox[geoip]
import json
from camoufox.sync_api import Camoufox
from capskip import CapSkip
PAGE_URL = "https://example.com/page-with-recaptcha"
solver = CapSkip(host="127.0.0.1", port=8080)
with Camoufox(main_world_eval=True, headless=True) as browser:
page = browser.new_page()
page.goto(PAGE_URL)
holder = page.locator("div.g-recaptcha")
holder.wait_for(state="attached", timeout=15000)
sitekey = holder.get_attribute("data-sitekey")
if not sitekey:
raise RuntimeError("Widget found but data-sitekey was empty.")
result = solver.recaptcha(sitekey=sitekey, url=PAGE_URL)
page.evaluate(
"mw:document.getElementById('g-recaptcha-response').value = "
+ json.dumps(result["code"])
)
page.click("button[type=submit]")
page.wait_for_load_state("networkidle")
print(page.url) # where you land after submittingÇözücüyü başka bir makinede çalıştırmak
Camoufox çoğu zaman script'i yazdığınız makineden daha büyük bir makinede çalışmaya başlar ve öyle olduğunda doğru yapılması gereken bir platform ayrıntısı vardır. headless'a virtual dizesini geçirmek bir Xvfb ekranı başlatır; bu yalnızca Linux'a özgü bir özelliktir: Windows ve macOS'ta aynı değer bunun yerine desteklenmiyor hatası verir. Düz headless her yerde çalışır; bu yüzden bilerek Linux üzerinde değilseniz boolean değeri kullanın.
Çözücünün tarayıcıyla birlikte yolculuk etmesi gerekmez. CapSkip’in iki bağlantı modu vardır. Local, 127.0.0.1 adresine bağlanır ve yalnızca o cihaza yanıt verir; script'i uygulamanın çalıştığı makinede yazarken doğru ayar budur. Server ise ağınıza ya da genel IP’nize bağlanır; böylece bir kazıma VM'i, ikinci bir iş istasyonu veya Camoufox çalıştıran bir Linux makinesi aynı Windows makinesini API üzerinden çağırır. Sabit bir genel IP, o adresi kararlı tutar. Kodda host dışında hiçbir şey değişmez, maliyetle ilgili de hiçbir şey değişmez, çünkü donanım yine sizindir.
# Same SDK, same call. Only the host moves. solver = CapSkip(host="10.0.0.12", port=8080, apiKey="YOUR_API_KEY")
Çözücü bir ağ adresini dinlemeye başladığında anahtar doğrulamasını açın ve her makineye kendi anahtarını verin; böylece biri, diğerlerine dokunulmadan iptal edilebilir. Her iki mod da şurada adım adım anlatılıyor: CapSkip kurulum kılavuzu.
Sık görülen hatalar ve anlamları
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
| Token ayarlandı ama form yine de başarısız oluyor | Yazma işlemi yalıtılmış kapsamda çalıştı ve atıldı | main_world_eval ile başlatın ve script'in başına mw: ekleyin |
| Evaluate desteklenmeyen bir dönüş değeri hatası veriyor | main world dışına bir düğüm referansı döndürüldü | Element yerine bir uzunluk ya da bir dize döndürün |
| Callback fonksiyonu tanımsız | Sayfanın global değişkenleri yalıtılmış kapsamda bulunmaz | Onu aynı önekle main world içinden çağırın |
| Turnstile onay kutusuna tıklanamıyor | Bir cross-origin iframe içinde yer alıyor | disable_coop ile başlatın ya da tıklamak yerine bir token enjekte edin |
| ERROR_GOOGLEKEY | Çözücüye boş bir sitekey ulaştı | recaptcha çağrısından önce değeri doğrulayın |
| NetworkException | CapSkip çalışmıyor ya da ana makine adresi yanlış | Uygulamayı başlatın veya host değerini sunucu adresine yöneltin |
| TimeoutException | Çözüm recaptchaTimeout süresini aştı | Varsayılan 300 saniyenin üzerine çıkarın |
| Sanal ekran desteklenmiyor | Linux dışında headless değeri virtual olarak ayarlandı | Bunun yerine headless=True kullanın |
FAQ
Main world eval, tespit edilmemi kolaylaştırır mı?
Main world içinde çalışan her şey sayfaya görünürdür, dolayısıyla ilke olarak evet. Pratikte maruz kalma, mikrosaniyeler süren tek bir atamadan ibarettir ve bir insan doğrulamayı geçtiğinde widget'ın kendi script'inin yaptığıyla birebir aynı görünür. Diğer bütün script'leri yalıtılmış kapsamda tutun, enjeksiyonu birkaç çağrıya bölmek yerine tek bir çağrıda yapın; o zaman karşı tarafa fazla bir şey vermiş olmazsınız.
Mevcut Playwright kodumu yeniden kullanabilir miyim?
Neredeyse tamamını. Başlatıcı size gerçek bir Playwright tarayıcısı verir; dolayısıyla locator'lar, context'ler, route'lar ve bekleme çağrıları her zamanki gibi davranır. Gözden geçirmeniz gereken iki şey var: DOM'a evaluate üzerinden yazan her çağrı, ki bunlar öneke ihtiyaç duyar, ve Chromium varsaydığınız her şey, çünkü burada Firefox var. O motora dair daha geniş tablo şurada: Playwright CAPTCHA çözücü sayfası.
Token enjekte etmek yerine widget'a tıklamalı mıyım?
Yalnızca Turnstile için ve yalnızca bazen. Managed modundaki bir Turnstile onay kutusu, tarayıcı inandırıcı görünüyorsa kendi başına geçebilir; Camoufox da tam bunun içindir ve ona tıklamak için önce Cross-Origin-Opener-Policy'nin devre dışı bırakılması gerekir. Bir reCAPTCHA onay kutusuna tıklamak ise yalnızca bir görsel doğrulama açar; dolayısıyla orada kazanılacak bir şey yoktur. Widget tarafındaki ayrıntılar için şunu inceleyin: Cloudflare Turnstile çözücü sayfasını.
Crawler'ım bir Linux VPS üzerinde çalışıyor. CapSkip nereye gitmeli?
Kontrol ettiğiniz bir Windows makinesine, Server modu açık olarak. VPS de onu, herhangi bir dahili servisi çağırdığı gibi API üzerinden çağırır; böylece Camoufox ile çözücünün aynı işletim sistemini, hatta aynı ağ segmentini paylaşması gerekmez. host argümanını o adrese yönlendirin, anahtar doğrulamasını etkinleştirin ve VPS’e kendi anahtarını verin.
Kısa özet
Camoufox’u main_world_eval açık olarak başlatın, sitekey'i sıradan bir locator ile okuyun, 127.0.0.1:8080 üzerindeki CapSkip ile çözün, ardından token'ı başına mw: eklenmiş bir evaluate çağrısıyla enjekte edip gönderin. Bütün püf nokta bu önektir; çünkü onsuz yazma işleminiz sayfanın hiç görmediği bir kapsama düşer. Selenium ve Playwright dahil Python tarafının geri kalanı için bkz. Python CAPTCHA çözücü sayfası.
Bir taramayı büyütmeden önce bilinmeye değer bir şey daha var. CapSkip, zaten sahip olduğunuz donanımda çalışan bir yerel captcha çözücü olduğundan, bin sayfayı yeniden deneyen bir çalıştırma, on sayfayı yeniden deneyen bir çalıştırmayla tam olarak aynıya mal olur.
