Ağ İsteklerini Yakalamadan Selenium ile ALTCHA Nasıl Çözülür

Selenium ile ALTCHA çözmek için widget’ın işini bitirmesini asla beklemezsiniz. ALTCHA bir tanıma yöntemi değil, iş kanıtı yöntemidir: site bir hash problemi verir ve istemci, geçmesine izin verilmeden önce onu sağlayan sayıyı bulmak zorundadır. Bakılacak da tıklanacak da bir şey yoktur, dolayısıyla tarayıcı akışın geri kalanı için oradadır, CAPTCHA için değil. Selenium’da Playwright’in response bekleme çağrısının tek satırlık bir karşılığı yoktur ve bu, o eksikliğin size hiçbir şeye mal olmadığı ender durumlardan biridir: widget kendi challenge uç noktasını bir attribute içinde adlandırır ve çözücünün ihtiyaç duyduğu tek şey de budur.
Neye ihtiyacınız var
- Bir Windows makinesinde çalışan CapSkip 1.2.6 veya üzeri. ALTCHA desteği o sürümle geldi, dolayısıyla daha eski bir yapıda çağrılacak bir metot yok.
- Python 3.10 veya daha yenisi; Selenium ve CapSkip paketleri kurulu olmalı, ayrıca uyumlu bir tarayıcı gerekir.
- Widget’ın üzerinde bulunduğu sayfanın URL’si. Sitekey yoktur, çünkü ALTCHA’da sitekey diye bir şey bulunmaz.
- Çözücü için bir adres. Local modu yalnızca o cihaz için 127.0.0.1 üzerinden yanıt verir; Server modu ise ağ adresinizi veya genel IP’nizi dinler, böylece bir Grid node’u, bir CI runner’ı ya da başka bir makine aynı API üzerinden ona ulaşabilir. Hangisinin geçerli olduğunu 5. adım anlatıyor; ikisi de şurada ayarlanır: bağlantı ayarları.
# pip install selenium capskip pip install selenium capskip
1. Adım: challenge uç noktasını widget’tan okuyun
Widget elementi, challenge’ını isteyeceği uç noktayı kendi üzerinde adlandırır. Bunu hangi attribute’un tuttuğu widget kuşağına göre değişir, o yüzden varsaymak yerine sayfa kaynağını okuyun.
| Widget nesli | Challenge’ı adlandıran öznitelik |
|---|---|
| v1 ve v2 | Bir endpoint için challengeurl, challenge satır içi olduğunda ayrı bir challengejson özniteliği |
| v3 ve sonrası | challenge; bu tek attribute ya bir URL ya da challenge verisinin kendisini alır |
Burada iki Selenium alışkanlığı önemli ve ikisi de aşikâr değil. Selenium bir elementi otomatik olarak beklemez; sayfa widget’ı DOM’a koymadan önce onu sorgularsanız yeniden deneme değil NoSuchElementException alırsınız. Sıradan attribute çağrısı ise melez bir çağrıdır: önce o addaki JavaScript property’sini dener ve ancak sonra markup’a düşer. Bir web component kendi attribute’ları için property tanımlar, dolayısıyla geri gelen değer okuyabildiğiniz HTML’e değil widget sürümüne bağlıdır. DOM attribute çağrısında böyle bir geri düşme yoktur ve markup ne diyorsa onu döndürür; istediğiniz de budur. Python API referansı aradaki farkı şurada açıklıyor: WebElement sayfası.
# pip install selenium capskip
from urllib.parse import urljoin
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
PAGE_URL = "https://example.com/signup"
driver = webdriver.Chrome()
driver.get(PAGE_URL)
# Nothing auto-waits in Selenium, so wait for the element.
widget = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "altcha-widget"))
)
# v1 and v2 use challengeurl or challengejson; v3 uses challenge.
value = (widget.get_dom_attribute("challengeurl")
or widget.get_dom_attribute("challengejson")
or widget.get_dom_attribute("challenge"))
if value is None:
raise SystemExit("no challenge attribute on the widget")Bu üç attribute’tan ikisi size bir işaretçi değil belgenin kendisini verir, o yüzden elinize geçeni URL gibi kullanmadan önce test edin. URL’nin kendine ait bir adımı daha vardır: markup genellikle baştaki bir eğik çizgi ve bir klasör adı gibi aynı kaynaktan bir yol taşır ve bir HTTP istemcisi bunu tek başına çekemez. Önce sayfa URL’sine göre çözümleyin.
import json
challenge, endpoint = None, None
if value.lstrip().startswith("{"):
# challengejson, or a v3 challenge holding the data inline.
challenge = json.loads(value)
else:
# A path in the markup becomes an absolute URL here.
endpoint = urljoin(PAGE_URL, value)Widget’ın type attribute’undaki üç etkileşim stili, yani native, checkbox ve switch, tamamen görseldir ve asla çözücüye ulaşmaz; ayrı bir attribute olan display de aynı şekilde görseldir. ALTCHA hepsini şurada belgeliyor: kendi widget rehberi.
2. Adım: challenge’ı tarayıcının oturumuyla çekin
Uç nokta herkese açıksa bu adımı atlayabilirsiniz ve pek çoğu açıktır. URL’yi CapSkip’e verin, challenge’ı kendisi çeksin. Bu adımın var olma nedeni, bazı sitelerin challenge’ı onu isteyen oturuma bağlamasıdır; çözücü ise sizin makinenizden çerezsiz istek yapar, dolayısıyla geri aldığı şey kimseye ait değildir. Sonuçta cevap doğru olur ve site yine de kabul etmez.
Çözüm, challenge’ı tarayıcının oturumu içinde çekmek ve işaretçi yerine belgenin kendisini geçirmektir. Selenium’un halihazırda tuttuğu çerezleri bir HTTP istemcisine kopyalayın, aynı user agent’ı taşıyın ve isteği kendiniz yapın.
import requests
if endpoint:
session = requests.Session()
for cookie in driver.get_cookies():
session.cookies.set(cookie["name"], cookie["value"],
domain=cookie["domain"])
session.headers["User-Agent"] = driver.execute_script(
"return navigator.userAgent")
# Referer matters on sites that check where the ask came from.
challenge = session.get(endpoint,
headers={"Referer": PAGE_URL}).json()O satırdaki bir JSON çözümleme hatası, işinize yarayan hatadır. Uç noktanın HTML ile, genellikle bir giriş sayfası veya bir onay duvarıyla yanıt verdiği anlamına gelir; bu da isteğin yabancı olarak gittiğini ve bu adımın doğru karar olduğunu söyler. Çözümü, çekme işleminin hemen ardından başlatın. Pencere kısadır ve saat, siz onu kullanmaya sıra geldiğinde değil site challenge’ı yayınladığında başlar.
3. Adım: challenge’ı tek ALTCHA metoduna verin
Tek bir metot ve tam anlatımı şu sayfada: ALTCHA çözücü sayfası. Bu metot challenge’ı iki biçimde de kabul eder. Belgeyi geçirin, hiç istek gitmez. Uç noktayı geçirin, çözücü onu kendisi çeker; iş kuyrukta ilkinin süresi dolacak kadar beklediyse yenisini çeker.
from capskip import CapSkip solver = CapSkip(host="127.0.0.1", port=8080) # The document from step 2, so nothing is fetched twice. result = solver.altcha(url=PAGE_URL, challenge_json=challenge) # Or hand over the endpoint and let CapSkip fetch it. # result = solver.altcha(url=PAGE_URL, challenge_url=endpoint) print(result["token"]) # base64 payload for the form field print(result["number"]) # the counter that satisfied it
O sonuçtaki iki anahtar yalnızca ALTCHA için var. token anahtarı formun istediği base64 veriyi, number anahtarı ise challenge’ı çözen sayacı tutar. code anahtarı token ile aynı dizeyi taşır, yani ikisi de iş görür; ama token anahtarı, gideceği alanın adını taşıyor. GeeTest anahtarları ve Turnstile kullanıcı ajanı burada yok.
Çözücünün kapsadığı algoritmalar
Eski şema SHA-1, SHA-256, SHA-384 ve SHA-512 ile, iş kanıtı v2 ise PBKDF2 ve yinelemeli SHA ile karşılanır. PBKDF2, ALTCHA’nın kendi önerdiği varsayılandır, dolayısıyla canlı sitelerin büyük çoğunluğu bunu kullanır. Argon2id ve scrypt istisnadır ve denenmek yerine reddedilir: bunlardan birini isteyen bir challenge yaklaşık saniyenin üçte biri içinde ERROR_CAPTCHA_UNSOLVABLE olarak geri döner ve asla yeniden denenmez, çünkü bellek yoğun bir fonksiyon yeniden denemeyle düzelecek bir şey değildir. Bu türde o sonuç, okunamayan bir görüntüyü değil algoritmayı işaret eder ve bu hata kodu şurada anlatılıyor: kendine ait bir rehber.
4. Adım: token’ı gizli alana yazın
Widget, payload’ını adı kendi name attribute’undan gelen bir gizli input içinde gönderir; bu adın varsayılanı altcha’dır. Challenge attribute’unu okuduğunuz gibi bunu da varsaymak yerine okuyun. Bu çalıştırmada widget’ı hiçbir şey doğrulamadı, dolayısıyla o alanı da hiçbir şey doldurmadı; onu siz dolduruyorsunuz.
Selenium bir WebElement’i doğrudan bir script’e geçirebilir; bu da doğru formu bulmanın en temiz yolunu düğmenin kendisi yapar. Gönder düğmesini verin ve onun form property’sini okuyun: bir kayıt sayfası çoğu zaman birden fazla form taşır ve düğme başka bir forma aitken alanı sayfadaki ilk forma eklemeniz, sunucunun hiçbir zaman bir değer görmemesi demektir.
SET_FIELD = """
const form = arguments[0].form || document.querySelector('form');
let field = form.querySelector('[name="' + arguments[1] + '"]');
if (!field) {
field = document.createElement('input');
field.type = 'hidden';
field.name = arguments[1];
form.appendChild(field);
}
field.value = arguments[2];
"""
button = driver.find_element(By.CSS_SELECTOR, "button[type=submit]")
field_name = widget.get_dom_attribute("name") or "altcha"
driver.execute_script(SET_FIELD, button, field_name, result["token"])
button.click()Dizeyi olduğu gibi geçirin. Token, alanları sunucunun HMAC imzası kapsamında olan bir JSON belgesinin base64 hâlidir; bu yüzden düzeltme gibi görünen her şey onu bozar: boşluk kırpmak, çözüp yeniden kodlamak ya da JSON’u anahtarlar başka sırada olacak şekilde yeniden kurmak. Bazı entegrasyonlar veriyi bir form alanı yerine bir JSON gövde alanından okur ve widget bunu bir çerezle teslim edecek şekilde de yapılandırılabilir; o yüzden sayfanın kendi gönderiminin ne yolladığına bakın ve aynısını yapın.
Gönder düğmesi hiçbir zaman tıklanabilir hale gelmiyorsa sayfa, düğmeyi alanın bir değer tutmasına değil kendi script’inin widget’ın başarılı olduğunu duymasına bağlıyordur. Burada dürüst iki cevap var. Sayfanın neyi dinlediğini bulup onu karşılayın ya da düğmeyi atlayıp formun alanlarını tarayıcının zaten sahip olduğu çerezlerle doğrudan gönderin; bu genelde daha kısa ve her zaman daha kararlıdır.
5. Adım: script’iniz yer değiştirdiğinde çözücü nerede çalışır
Örnekler 127.0.0.1 kullanıyor, çünkü script’iniz ile CapSkip aynı makineyi paylaşırken doğru olan budur. Çözücüyü tarayıcı ya da sayfa değil, sizin Python kodunuz çağırır; dolayısıyla adres, Chrome’un değil test sürecinin nerede çalıştığına bağlıdır. Selenium bunu ters anlamayı kolaylaştırır, çünkü tarayıcı zaten çok sık başka bir yerdedir.
| Python sürecinin çalıştığı yer | Hangi bağlantı modu |
|---|---|
| CapSkip makinesinde, yerel bir tarayıcı sürerek | Local modu. 127.0.0.1 gerçekten doğru |
| Kendi makinenizde, uzak bir WebDriver veya bir Grid node’u sürerken | Yerel mod. Tarayıcı çözücüyle hiç konuşmaz |
| Aynı ağdaki başka bir makinede | Server modu, çözücü makinenin özel adresinde |
| Bir container’da, bir CI runner’da veya bir VPS’te | Statik bir genel IP ve bir güvenlik duvarı kuralı ile Server modu |
CapSkip’i Server moduna geçirin; loopback yerine ağ adresinizi veya genel IP’nizi dinler ve runner, yerelde kullanacağı aynı HTTP API üzerinden bağlanır. Rota internetten geçiyorsa statik bir genel IP önerilir ve yalnızca beklediğiniz adreslere izin veren bir güvenlik duvarı kuralı eklenmelidir. Server modu çözücünün nerede dinlediğinden başka hiçbir şeyi değiştirmez: donanım yine sizin donanımınızdır ve çözüm başına ücretlendirme yine yoktur. Testlerin kendisini bir Grid üzerinde çalıştırmanın kendine ait tuzakları var; onlar ayrıca şurada anlatılıyor: Selenium Grid rehberi.
Tek bir script’in her iki yerde de çalışması için host ve port değerlerini ortamdan okuyun. İstemci CAPSKIP_HOST ve CAPSKIP_PORT değerlerini kendi başına okumaz; bu yüzden, aşağıdaki tam örnekte olduğu gibi, bunları yapıcıya geçirin.
Proxy’lerle ilgili ALTCHA’ya özgü bir not. Burada proxy destekleniyor, ama yalnızca challenge’ın indirilmesi için kullanılıyor. Üzerinden yönlendirilecek bir tarayıcı oturumu yok, yani iş kanıtının kendisine hiçbir etkisi olmuyor; challenge belgesini satır içi geçtiğinizde ise hiçbir işe yaramıyor.
Tam çalışan örnek
import json, os, requests
from urllib.parse import urljoin
from capskip import CapSkip, ApiException, NetworkException, TimeoutException
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
PAGE_URL = "https://example.com/signup"
SET_FIELD = """
const form = arguments[0].form || document.querySelector('form');
let field = form.querySelector('[name="' + arguments[1] + '"]');
if (!field) {
field = document.createElement('input');
field.type = 'hidden';
field.name = arguments[1];
form.appendChild(field);
}
field.value = arguments[2];
"""
solver = CapSkip(
host=os.environ.get("CAPSKIP_HOST", "127.0.0.1"),
port=int(os.environ.get("CAPSKIP_PORT", 8080)),
)
driver = webdriver.Chrome()
try:
driver.get(PAGE_URL)
widget = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "altcha-widget"))
)
value = (widget.get_dom_attribute("challengeurl")
or widget.get_dom_attribute("challengejson")
or widget.get_dom_attribute("challenge"))
if value is None:
raise SystemExit("no challenge attribute on the widget")
if value.lstrip().startswith("{"):
challenge = json.loads(value)
else:
endpoint = urljoin(PAGE_URL, value)
session = requests.Session()
for cookie in driver.get_cookies():
session.cookies.set(cookie["name"], cookie["value"],
domain=cookie["domain"])
session.headers["User-Agent"] = driver.execute_script(
"return navigator.userAgent")
challenge = session.get(endpoint,
headers={"Referer": PAGE_URL}).json()
try:
result = solver.altcha(url=PAGE_URL, challenge_json=challenge)
except ApiException:
raise SystemExit("refused: Argon2id, scrypt, or an expired challenge")
except NetworkException:
raise SystemExit("solver unreachable: check host and connection mode")
except TimeoutException:
raise SystemExit("no answer inside defaultTimeout")
button = driver.find_element(By.CSS_SELECTOR, "button[type=submit]")
field_name = widget.get_dom_attribute("name") or "altcha"
driver.find_element(By.NAME, "email").send_keys("[email protected]")
driver.execute_script(SET_FIELD, button, field_name, result["token"])
button.click()
finally:
driver.quit()Dört istisnanın hepsi CapSkipError’dan türer, dolayısıyla onu yakalamak SDK’nın verebileceği her hatayı tek bir blokta karşılar. Yanıt farklılaştığında yukarıdaki gibi özel olanları, farklılaşmadığında CapSkipError’ı yakalayın. Hangi TimeoutException’ı yakaladığınıza dikkat edin: CapSkip’inki ile Selenium’un kendi sınıfı aynı adı taşır, ikisi de kapsamdaysa birini takma adla import edin.
Diğer tipler aynı istemciden aynı şekilde çalışıyor. reCAPTCHA ve Turnstile bir sitekey ile bir sayfa URL’si alır, GeeTest bir gt değeri, bir challenge ve sayfa URL’sini alır, görsel çözme ise bir dosya yolu, bir URL veya base64 alır. Paketin sunduğu bütün metotlar şurada listeleniyor: Python CAPTCHA çözücü sayfası, tarayıcı tarafının tamamı ise şurada: Selenium CAPTCHA çözücü sayfası.
Sık görülen hatalar ve anlamları
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
| Widget’ta NoSuchElementException | Element henüz DOM’a eklenmemişti; markup’ı script oluşturduğunda böyle olur ve Selenium kendiliğinden beklemez | Aramayı, elementin sayfada bulunmasını bekleyen bir explicit wait içine alın |
| Üç attribute okumasının üçü de None dönüyor | Widget tamamen JavaScript’ten yapılandırılmış, dolayısıyla üç addan hiçbiri markup’ta yok | Yapılandırmayı sayfanın kendi script’inden okuyun ya da ağ panelinde görebildiğiniz uç noktayı kullanın |
| Sayfa kaynağında açıkça bir değer varken boş dönen attribute | Sıradan attribute çağrısı, web component’in tanımladığı ve boş olan bir property döndürdü | Markup’ı okuyan ve property’ye düşmeyen DOM attribute çağrısını kullanın |
| HTTP istemcisinden, eğik çizgiyle başlayan bir değeri gösteren MissingSchema | Markup aynı kaynaktan bir yol tutuyor ve DOM attribute çağrısı onu yazıldığı gibi döndürüyor | Çekmeden ve çözücüye geçirmeden önce sayfa URL’sine göre çözümleyin |
| Attribute değeri süslü parantezle başlıyor | Bir challengejson attribute’u ya da URL yerine belgeyi satır içinde taşıyan bir v3 widget’ı | JSON olarak ayrıştırın ve satır içi challenge olarak geçirin |
| Uç noktayı çekerken JSON çözümleme hatası | Uç nokta HTML ile yanıt verdi, yani istek tarayıcının oturumu olmadan ulaştı | Çekmeden önce çerezleri ve user agent’ı kopyalayın |
| Az önce yakaladığınız bir challenge’da ApiException | Satır içi challenge’ın süresi çoktan dolmuştu, çözücü de hashlemek yerine onu reddetti | Çekme ve çözmeyi tek nefeste yapın ya da uç nokta oturuma bağlı değilse, çözücünün yeniden çekebilmesi için uç noktayı geçirin |
| Yaklaşık saniyenin üçte biri içinde, bir ApiException içinde ERROR_CAPTCHA_UNSOLVABLE | Challenge, Argon2id veya scrypt kullanıyor | Yeniden denenecek bir şey yok. Bu ikisi tasarım gereği reddedilir |
| Günlüğünüzün çözüldüğünü gösterdiği bir token’la, çıplak bir doğrulama hatası | Challenge’ın süresi, çözüm ile gönderim arasında doldu | Arada yavaş hiçbir şey olmadan yakalayın, çözün ve gönderin |
| İlk çözümde bir NetworkException | CapSkip çalışmıyor ya da script bir konteynerde ve loopback’e yönlendirilmiş | CapSkip’i başlatın, sonra Yerel mod ile Sunucu modu arasında seçim yapın |
| 120 saniyeyi işaret eden bir TimeoutException | Çözücü, ALTCHA’nın daha uzun reCAPTCHA değeri yerine kullandığı varsayılan yoklama zaman aşımı içinde yanıt vermedi | Çözücünün çalıştığını ve dolu olmadığını kontrol edin. Tavanı yükseltmek aynı cevabı yalnızca geciktirir |
| Form gönderiliyor ama sunucu eksik bir altcha değeri bildiriyor | Gizli alan, sayfadaki başka bir forma eklendi | Örnekteki gibi form property’sini gönder düğmesinden okuyun |
| Gönder düğmesi devre dışı kalıyor | Sayfa bunu, kendi script’inin widget’ın başarılı olduğunu görmesine bağlıyor | Form alanlarını doğrudan gönderin ya da sayfanın dinlediği her neyse onu karşılayın |
| Çağrıda bir ValidationException | Challenge seçeneklerinden hiçbiri verilmedi ya da ALTCHA’nın almadığı bir seçenek geçildi | Uç noktayı ya da belgeyi geçin ve başka her şeyi bırakın |
FAQ
ALTCHA’yı çözmek için tarayıcıya ihtiyacım var mı?
Hayır. ALTCHA bir hash problemidir, dolayısıyla cevabı CPU verir ve cevaba hiçbir tarayıcı karışmaz. Selenium’u açmanızın tek nedeni CAPTCHA idiyse kapatın: challenge’ı bir HTTP istemcisiyle çekip token’ı geri gönderin. Bunu baştan sona düz Python rehberi anlatıyor. Selenium, akışın geri kalanı gerçek bir sayfaya ihtiyaç duyduğunda hak ettiği yeri bulur: çerez kuran bir giriş, çok adımlı bir form ya da yalnızca script çalıştıktan sonra var olan markup gibi.
Widget attribute’u neden boş dönüyor?
Çünkü sıradan attribute çağrısı melez bir çağrıdır. Element bir property tanımlıyorsa onu döndürür ve ancak sonra markup’a düşer; bir web component de kendi attribute’ları için property tanımladığından, boş bir property sayfa kaynağında gördüğünüz değere üstün gelir. DOM attribute çağrısında böyle bir geri düşme yoktur ve markup ne diyorsa onu döndürür. Diğer neden de önünüzdeki kuşak için yanlış adı okuyor olmanızdır, o yüzden attribute yok demeden önce üçünü de deneyin.
Bir CI runner’ı veya bir container çözücüye ulaşabilir mi?
Evet, Server modu üzerinden. CapSkip’i bağlantı ayarlarından loopback yerine ağ adresinize veya genel IP’nize alın, sonra host ortam değişkenini oraya yöneltin. Runner ile çözücü o zaman tek makinedeymiş gibi aynı HTTP API’yi konuşur. Rota internetten geçiyorsa statik bir genel IP kullanın ve bir güvenlik duvarı kuralıyla kısıtlayın. Uzak bir Grid node’u ayrı bir konudur ve genellikle hiçbir şey gerektirmez, çünkü tarayıcıyı node çalıştırır; çözücüyü çağıran script’iniz ise başlattığınız yerde kalır.
Selenium’un kendi zaman aşımları çözümü yarıda keser mi?
Hayır, çünkü çözüm bir WebDriver komutu değildir. Implicit wait, sayfa yükleme zaman aşımı ve script zaman aşımı; hepsi Selenium’un tarayıcıya gönderdiği çağrıları kapsar, sizin çözücü çağrınız ise bunların ikisinin arasında duran sıradan Python kodudur. Geçerli olan tavan, istemcinin 120 saniyelik varsayılan yoklama zaman aşımıdır; ALTCHA bunu daha uzun reCAPTCHA değeri yerine kullanır, çünkü bu iş bir tarayıcı oturumu değil CPU işidir. Bunun yerine testin tamamını saran bir sınıra dikkat edin: test başına bir eklenti zaman aşımı veya bir CI iş sınırı gibi.
Kısa özet
Widget’ı bekleyin, challenge attribute’unu DOM attribute çağrısıyla okuyun, bir yolu sayfa URL’sine göre çözümleyin ve site challenge’ı bir oturuma bağlıyorsa o uç noktayı tarayıcının oturumu içinde çekin. Belgeyi ya da URL’yi sayfa URL’si ile birlikte tek ALTCHA metoduna geçirin, sonra token’ı gönder düğmesinin ait olduğu formda, adı widget’ın kendi name attribute’undan gelen gizli alana yazın. Token’a yolda dokunmayın. Çekme, çözme ve gönderme işlemlerini birbirine yakın tutun, çünkü pencere iki dakika içinde kapanabilir ve süresi dolmuş bir challenge tıpatıp yanlış cevap gibi görünür.
- Bu tipin ne olduğu ve nasıl çalıştığı: ALTCHA çözücü sayfası.
- Aynı işin hiç tarayıcı olmadan yapılışı: düz Python ile ALTCHA çözme.
Yeniden denemeyi nasıl tasarlayacağınızı değiştiren son bir nokta daha var. Bu yolun sonundaki sınırsız captcha çözücü iş kanıtını zaten sahip olduğunuz donanımda hesapladığı için, çöpe giden bir challenge size yalnızca kendi CPU’nuzdan birkaç milisaniyeye mal olur, başka hiçbir şeye değil; bu yüzden yenisi için sayfayı yeniden yüklemek, bayat bir token’ı uzun bir test boyunca idare etmeye çalışmaktan her zaman daha ucuzdur.
