Tarayıcı Çalıştırmadan Python ile ALTCHA Nasıl Çözülür

Python ile ALTCHA çözmek için bir HTTP istemcisinden başka hiçbir şeye ihtiyacınız yok. ALTCHA bir tanıma yöntemi değil, iş kanıtı yöntemidir: site bir challenge yayınlar ve geçmek isteyen kişi, onu sağlayan sayıyı bulana kadar hash almak zorundadır. Bakılacak hiçbir şey olmadığı için tarayıcı, WebDriver veya user agent işin içine girmez ve cevap tahmin edilmez, hesaplanır. Bu da çözümün deterministik olduğu anlamına gelir. Ya sayıyı milisaniyeler içinde bulur ya da challenge’ın kendisi bozuktur veya süresi çoktan geçmiştir. CapSkip bu türü 1.2.6 sürümünde ekledi ve Python SDK bunu tek bir metot olarak sunuyor.
Neye ihtiyacınız var
- Bir Windows makinesinde CapSkip 1.2.6 veya üzeri. ALTCHA bu sürümle geldi.
- Python 3.10 veya üzeri ve CapSkip paketi.
- Widget’ı barındıran sayfanın URL’si ve widget’ın challenge’ını çektiği endpoint.
- Çözücü için bir adres. Local modu 127.0.0.1 üzerinden dinler ve yalnızca o cihaza hizmet verir; Server modu ağ adresinizi veya genel IP’nizi dinler, böylece başka bir makine de ona ulaşabilir. İkisi de şurada ayarlanır: bağlantı ayarları.
# pip install capskip pip install capskip requests
1. adım: çözüm çağrısı ve onu hangi adrese yönlendireceğiniz
Sayfa URL’sini ve challenge endpoint’ini verin. CapSkip challenge’ı kendisi çeker, sayacı bulana kadar hash alır ve formun beklediği payload’ı geri verir.
# pip install capskip
from capskip import CapSkip
solver = CapSkip(host="127.0.0.1", port=8080)
# CapSkip fetches the challenge, then brute-forces the counter.
result = solver.altcha(
url="https://example.com/signup",
challenge_url="https://example.com/altcha/challenge",
)
print(result["token"]) # base64 payload for the form field
print(result["number"]) # the counter that satisfied itBu sözlükteki iki anahtar yalnızca ALTCHA için vardır. token anahtarı base64 payload’ı tutar, number anahtarı ise challenge’ı çözen sayacı tutar. code anahtarı token ile aynı dizeyi taşır, yani hangisini kullanırsanız kullanın çalışır; ancak token anahtarı, değerin gireceği alanın adını taşır.
Sayaç her iki ALTCHA nesli için de raporlanır ve bu, kulağa geldiğinden daha faydalıdır; çünkü payload’lar sayacın nerede durduğu konusunda birbirini tutmuyor. Legacy bir payload sayacı en üst düzeyde taşır, proof-of-work v2 payload’ı ise taşımaz ve onun yerine bir solution nesnesinin içinde tutar. CapSkip bu değeri kendi API yanıtında solution nesnesinden okur, böylece site hangi nesli çalıştırıyorsa çalıştırsın tek bir alan elde edersiniz.
Loopback yalnızca aynı makineyi paylaştığınız sürece doğrudur
Betik taşındığında değiştirmeniz gereken tek satır o host argümanıdır. Python süreci ile çözücü aynı makinede olduğu sürece 127.0.0.1 doğrudur. Betik bir konteynerde, bir VPS’te, bir CI çalıştırıcısında veya yönetilen bir platformda zamanlanmış bir iş olarak çalışmaya başladığında loopback artık çözücüyü değil o ortamı işaret eder ve ilk çağrı bir NetworkException yükseltir.
Cevap Server modu. Bu mod, CapSkip’in loopback yerine ağ adresinizi veya genel IP’nizi dinlemesini sağlar, böylece bu ortamların hepsi aynı çözücüye API üzerinden ulaşabilir. Trafik internetten geçiyorsa statik bir genel IP ve yalnızca beklediğiniz adreslerle sınırlı bir güvenlik duvarı kuralı kullanın. Başka hiçbir şey değişmez: çözücü yine sizin donanımınızda çalışır ve kullanımı yine sınırsızdır, yalnızca adresi farklıdır. Değeri koda gömmek yerine ortamdan okuyun, çünkü istemci hâlihazırda CAPSKIP_HOST, CAPSKIP_PORT ve CAPSKIP_API_KEY değişkenlerine bakıyor.
2. adım: challenge nereden gelir ve onu vermenin iki yolu
DevTools’u açın, Network sekmesine geçin ve sayfayı yeniden yükleyin. Widget, challenge’ı için genellikle içinde altcha geçen bir yola tek bir istek gönderir. Verdiğiniz şey bu URL’dir. İsteğin döndürdüğü JSON ise challenge belgesidir ve onun yerine bu belgeyi de verebilirsiniz.
Özniteliği tahmin etmek yerine sayfa kaynağını okuyun, çünkü bu öznitelik widget nesilleri arasında değişti.
| 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 öznitelik hem bir URL hem de challenge verisini kabul eder |
Widget’ın görünümü burada önemsizdir. native, checkbox ve switch varyantlarının hepsi aynı payload’ı gönderir ve aradaki fark asla çözücüye ulaşmaz, dolayısıyla algılanacak bir şey yok. Bir challenge’ın alan alan açıklaması için ALTCHA’nın kendi kaynağına bakabilirsiniz: widget ve sunucu dokümantasyonu.
Kazıyıcınızda belge zaten varsa onu doğrudan verin ve çekme adımını tamamen atlayın. Parametre bir sözlük alır ve onu sizin için serileştirir; elinizde tuttuğunuz şey bir JSON dizesiyse onu da kabul eder.
# The document is already here, so no request goes out.
result = solver.altcha(
url="https://example.com/signup",
challenge_json={
"algorithm": "SHA-256",
"challenge": "YOUR_CHALLENGE_HASH",
"salt": "YOUR_SALT",
"signature": "YOUR_SIGNATURE",
"maxnumber": 1000000,
},
)İkisini birlikte vermek serbesttir ve satır içi belge kazanır, çünkü çekme işlemi yalnızca sizin az önce verdiğiniz şeyi yeniden almak olurdu. İki yol, işler kuyruğa girdiğinde önemli olan tek bir noktada farklılaşır: süresi çoktan geçmiş bir satır içi challenge, boşuna hash alınmak yerine hemen reddedilir; buna karşılık bir endpoint, iş beklerken ilk challenge öldüyse çözücünün yeni bir challenge çekmesine izin verir.
Çözücünün kapsadığı algoritmalar
Tek bir metot her iki nesli de karşılar. Legacy şema SHA-1, SHA-256, SHA-384 ve SHA-512 ile desteklenir; proof-of-work v2 ise PBKDF2 ve iteratif SHA ile desteklenir. PBKDF2, ALTCHA’nın kendisinin önerdiği varsayılandır, dolayısıyla bu, yayındaki sitelerin büyük çoğunluğu demektir.
Argon2id ve scrypt istisnadır. Denenmek yerine reddedilirler: bu ikisinden 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 fonksiyonu yeniden denemek düzeltmez.
3. adım: token’ı süresi geçmeden, hiç dokunmadan geri gönderin
Widget, payload’ını altcha adlı bir form alanında gönderir. Dizeyi tam olarak geldiği şekilde yollayın.
import requests
# No strip(), no re-encoding, no rebuilding the JSON.
r = requests.post("https://example.com/signup", data={
"email": "someone@example.com",
"altcha": result["token"],
})Bu payload, alanları sunucunun HMAC imzasıyla korunan bir JSON belgesinin base64 hâlidir; bu yüzden her düzenleme onu geçersiz kılar. Üzerinde strip çağırmak, çözüp yeniden kodlamak veya sözlüğü anahtarları başka bir sırada olacak şekilde yeniden oluşturmak; bunların hepsi sitenin reddettiği bir token üretir. Bazı entegrasyonlar bunu form alanı yerine bir JSON gövde alanından okur, bu yüzden sayfanın kendi gönderiminin ne yolladığını kontrol edip aynısını yapın.
Bir site, logunuzda çözülmüş görünen bir token’ı reddediyorsa, bozulmuş bir challenge ihtimalinden çok süresi geçmiş bir challenge ihtimali söz konusudur. Challenge pencereleri kısadır ve bazıları iki dakika içinde kapanır; süresi geçmiş bir challenge, tam olarak yanlış cevap gibi görünen yalın bir doğrulama hatası olarak geri döner. Çekme, çözme ve gönderme işlemlerini tek bir iş biriminde yapın ve bir kişi formu doldururken elinizde asla token tutmayın.
Burada sizi sınırlayan şey istemcinin kendi yoklama zaman aşımları değil, çünkü challenge penceresi ikisinden de çok önce kapanır. Yine de hangisinin geçerli olduğunu bilmeye değer; çünkü ALTCHA bu ayrımın kısa tarafında yer alıyor. Bir tarayıcı oturumu değil CPU işi olduğundan, daha uzun olan reCAPTCHA’nınki yerine varsayılan yoklama zaman aşımını kullanır.
| Yapıcı seçeneği | Varsayılan | Neyi kapsar |
|---|---|---|
| defaultTimeout | 120 saniye | ALTCHA ve görsel CAPTCHA yoklaması |
| recaptchaTimeout | 300 saniye | reCAPTCHA, Turnstile ve GeeTest yoklaması |
| pollingInterval | En fazla 5 saniye | Yoklama 0,25 saniyeden başlar ve kademeli olarak bu değere kadar çıkar |
4. adım: her challenge bayatlamadan bir yığını çözmek
Async istemcinin baştan ayrı olarak yazıldığı tek SDK Python’dır: burada AsyncCapSkip gerçek anlamda asyncio’dur. Node.js ve .NET paketlerinde bu ad, metotları zaten asenkron olan sıradan istemcinin bir takma adıdır; PHP ise baştan sona senkrondur.
Kısıt eşzamanlılık değil, tazeliktir. Yüz tane challenge çekip sonra hepsini çözmek yanlış bir kurgudur, çünkü yığın ilerlerken en erken alınanların süresi dolar. Bunun yerine çekme ve çözme işlemini aynı görevin içinde yapın, sayfa başına bir görev açın ve dağıtımı gather üstlensin.
# pip install capskip
import asyncio
from capskip import AsyncCapSkip
async def solve_one(solver, page_url, challenge_url):
# One fresh challenge per page, fetched and solved together.
result = await solver.altcha(url=page_url, challenge_url=challenge_url)
return page_url, result["token"]
async def main():
solver = AsyncCapSkip()
pages = [
("https://example.com/signup", "https://example.com/altcha/challenge"),
("https://example.com/contact", "https://example.com/altcha/challenge"),
]
for page_url, token in await asyncio.gather(
*(solve_one(solver, p, c) for p, c in pages)
):
print(page_url, token[:24])
asyncio.run(main())İş kanıtı CPU’ya bağlıdır, dolayısıyla üst sınırı açık bağlantılar değil çekirdekler belirler ve bunu tahmin etmek yerine gerçekten kullandığınız makinede ölçmeye değer. Beklemenin hash almak yerine bir tarayıcı oturumu olduğu türler de dahil, toplu çözüm için genel kalıp şurada: CAPTCHA'ları paralel çözme kılavuzu.
Tam çalışan örnek
# pip install capskip
import os
import requests
from capskip import CapSkip, ApiException, NetworkException, TimeoutException
solver = CapSkip(host=os.environ.get("CAPSKIP_HOST", "127.0.0.1"), port=8080)
try:
result = solver.altcha(
url="https://example.com/signup",
challenge_url="https://example.com/altcha/challenge",
)
# Submit here, while the challenge is still fresh.
r = requests.post("https://example.com/signup", data={
"email": "someone@example.com",
"altcha": result["token"],
})
print(r.status_code, "solved with counter", result["number"])
except ApiException as exc:
# ERROR_CAPTCHA_UNSOLVABLE here means Argon2id or scrypt.
print("refused:", exc)
except NetworkException:
print("CapSkip is not answering on that host and port")
except TimeoutException:
print("gave up waiting, which on this type means something is wrong")Diğer türler aynı biçimdedir, yalnızca metot değişir. reCAPTCHA v2, v3 ve Enterprise için bir çağrı, Turnstile için bir çağrı, GeeTest v3 için bir çağrı ve görsel CAPTCHA’lar için bir çağrı var; tam liste şurada: Python CAPTCHA çözücü sayfası.
Node.js, PHP ve .NET paketleri aynı metot adlarını sunar. Her CapSkip SDK’sı şurada anlatılıyor: SDK sayfası.
Sık görülen hatalar ve anlamları
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
| Siteden gelen yalın bir doğrulama hatası, üstelik sorunsuz çözülmüş bir token üzerinde | Form gönderilmeden önce challenge’ın süresi doldu | Çekme, çözme ve gönderme işlemlerini tek bir fonksiyonun içinde yapın |
| Saniyenin üçte biri sonra, bir ApiException içinde ERROR_CAPTCHA_UNSOLVABLE | Challenge, Argon2id veya scrypt istiyor | Yeniden denenecek bir şey yok. Bu ikisi bilerek reddedilir |
| Çağrıda bir ValidationException | İki challenge parametresinden hiçbiri verilmedi ya da ALTCHA’nın kabul etmediği bir parametre verildi | Challenge endpoint’ini ya da challenge belgesini verin ve gerisini çıkarın |
| Hiç hash alınmadan önce bir NetworkException | CapSkip çalışmıyor ya da host ve port yanlış | CapSkip’i başlatın, ardından Local modunda mı yoksa Server modunda mı olması gerektiğini kontrol edin |
| token anahtarında bir KeyError | Bu anahtarı yalnızca bir ALTCHA sonucu taşır | altcha metodunu çağırın veya aynı dizeyi tutan code anahtarını okuyun |
| Bir yığındaki ilk çözümler başarısız oluyor, sondakiler geçiyor | Challenge’lar baştan toplu çekildi ve kuyrukta beklerken süreleri doldu | Çekme işlemini gather’dan önce değil, her görevin içinde yapın |
| Sitenin her seferinde reddettiği bir token | Bir şey payload’ı kırptı veya yeniden kodladı | Dizeyi hiç dokunmadan geçirin |
FAQ
ALTCHA bulunan bir sayfa için Selenium veya Playwright gerekir mi?
ALTCHA kısmı için gerekmez. Challenge bir hash problemidir ve cevap, bir form alanına gönderdiğiniz bir dizedir; dolayısıyla requests veya httpx yeterlidir ve çözüm milisaniyeler içinde biter. Sayfanın geri kalanı tarayıcı gerektiriyorsa yine tarayıcı kullanmak isteyeceksiniz; örneğin oturum çerezi JavaScript ile ayarlanıyorsa veya form istemci tarafında oluşturuluyorsa. Bu durumda tarayıcıyı gezinme için tutun ve widget’ı çalıştırmaya uğraşmak yerine token için doğrudan çözücüyü çağırın.
Barındırılan bir platformdaki bir betik çözücüye erişebilir mi?
Evet. Bağlantı ayarlarından Server modunu açın; böylece CapSkip loopback yerine bir ağ adresini dinler. Sonra CAPSKIP_HOST’u o adrese yönlendirin. Bir Docker konteyneri, bir VPS, yönetilen bir platformdaki zamanlanmış bir iş ve bir CI çalıştırıcısı; hepsi aynı şekilde, aynı HTTP API üzerinden bağlanır. Rota internetten geçiyorsa statik bir genel IP ve yalnızca beklediğiniz adreslere izin veren bir güvenlik duvarı kuralı kullanın. Her iki durumda da çözücü sizin donanımınızda çalışmaya devam eder, dolayısıyla lisans ve sınırsız çözme etkilenmez.
ALTCHA neden reCAPTCHA’ya göre çok daha hızlı çözülüyor?
Çünkü ikisi farklı şeyler istiyor. reCAPTCHA ve Turnstile, makul bir geçmişe sahip bir tarayıcının orada olduğunun kanıtını ister; bu da gerçek bir oturum ve gerçek bir süre gerektirir. ALTCHA ise yalnızca bir miktar CPU harcandığının kanıtını ister, dolayısıyla iş, durma koşulu bilinen bir hash döngüsüdür. Cevabın bir yargı değil, deterministik olmasının nedeni de bu: challenge’ı sağlayan bir sayı vardır ve o sayı ya bulunur ya da challenge bozuktur. Bunun karşılığında o sayı, bir iki dakika sonra değersiz hâle gelir.
Bir token’ı birden fazla istekte yeniden kullanabilir miyim?
Hayır ve nedenini açıkça söylemeye değer. Payload tek bir challenge’a karşı imzalanır, o challenge bir kez verilir ve sunucu onu takip eder; dolayısıyla aynı token’ın ikinci kez gönderilmesi, tasarımın tam da engellemek için var olduğu replay girişiminin kendisidir. Her gönderim için bir kez çözün. Bu, ücretlendirilen bir servisin aksine burada göze alınabilir bir şeydir; çünkü iş, faturalanan bir çağrı değil, kendi CPU’nuzun birkaç milisaniyesidir. Kolayca yeniden hesaplayabileceğiniz bir şeyi önbelleğe almanın hiçbir nedeni yok.
Kısa özet
Challenge endpoint’ini widget’tan okuyun, sayfa URL’si ile birlikte tek ALTCHA metoduna verin ve token’ı düzenlemeden altcha adlı alana gönderin. Çekme, çözme ve gönderme işlemlerini bir arada tutun, çünkü bir challenge iki dakika içinde ölebilir ve süresi geçmiş olan, sade bir doğrulama hatası olarak bildirilir. Bir yığın için async istemciyle dağıtım yapın ve her challenge’ı önce toplamak yerine kendi görevinin içinde çekin. ERROR_CAPTCHA_UNSOLVABLE hatasını yalnızca Argon2id ve scrypt’ten bekleyin.
- Challenge’ın kendisi nasıl çalışır: ALTCHA çözücü sayfası.
- Python paketinin sunduğu diğer tüm metotlar: Python çözücü sayfası.
Yeniden deneme mantığınıza yerleştirmeye değer bir sonuç var. Yerel olarak çalışan bir captcha çözücü hash işlemini zaten sahip olduğunuz bir makinede yapar, dolayısıyla boşa giden bir çözüm kredi değil milisaniye maliyeti çıkarır. Bu nedenle bayat bir challenge karşısında doğru tepki, yenisini çekip tekrar denemektir.
