Python’da requests ve httpx ile CaptchaFox Nasıl Çözülür

Python ile CaptchaFox çözmek için capskip paketindeki solver.captchafox() metodunu sitekey ve sayfa URL’siyle çağırın, dönen token’ı cf-captcha-response form alanına koyun ve bu isteği, token’ın yanında dönen user agent ile gönderin. Python kodu genellikle bu son adımda hata yapar. requests ve httpx varsayılan olarak User-Agent başlığında kendi adlarını bildirir; token’ın onu üreten tarayıcıdan gelmesini bekleyen bir site de bu isteği reddeder. Böylece kusursuz çalışmış bir çözüm bile gönderimde başarısız olabilir. CapSkip, CaptchaFox desteğini 1.4.0 sürümünde ekledi. Bu rehber anahtarı, çağrıyı, gönderimi, yeniden denemeleri ve çözümleri yan yana çalıştırmayı ele alıyor.
Neye ihtiyacınız var
- Bir Windows makinesinde çalışan CapSkip 1.4.0 veya üzeri. CaptchaFox desteği, Friendly Captcha ve Capy Puzzle ile birlikte bu sürümle geldi.
- Python 3.10 veya üzeri ve capskip paketinin 1.3.0 veya üzeri bir sürümü; captchafox() metodunu içeren ilk sürüm budur. Örnekler ayrıca requests kütüphanesini, paralel çözümler bölümü ise httpx kütüphanesini kullanır.
- Hedef sayfadan iki değer: sitekey ve widget’ın çalıştığı sayfanın URL’si. Anahtarın nerede durduğunu ve oradayken hangi script etiketine bakmanız gerektiğini 1. adım gösteriyor.
- Çözücü için bir adres. Local modunda CapSkip 127.0.0.1 üzerinden yalnızca o cihaza yanıt verir; Server modunda ise ağ adresinizi veya genel IP’nizi dinler, böylece başka bir makinedeki bir betik onu API üzerinden çağırabilir. İkisi de şurada ayarlanır: bağlantı ayarları.
# Quoted, so cmd.exe does not read >= as a redirect pip install "capskip>=1.3.0" requests httpx
1. Adım: sitekey’i ve widget kaynağını okuyun
Sitekey herkese açıktır, her ziyaretçi için aynıdır ve geleneksel olarak sk_ ile başlar. Çoğu sayfa onu widget’ın kapsayıcısında taşır: captchafox sınıfına ve bir data-sitekey özniteliğine sahip bir div. Widget’ı kendi script’inden oluşturan bir sayfa ise anahtarı bunun yerine bir captchafox.render çağrısına verir. Çektiğiniz HTML’de bunların hiçbiri görünmüyorsa anahtar Network sekmesindedir: api.captchafox.com adresine giden istekte /captcha/ sonrasındaki yol parçasıdır.
Sayfayı okurken widget’ı hangi script’in yüklediğini de kontrol edin. Çoğu site onu cdn.captchafox.com adresinden yükler ve düz bir token alır. Bazı platformlar ise bunun yerine s.uicdn.com/mampkg/ altından bir paket gömer ve bu siteler MAM_ ile başlayan bir token bekler. Yanlış olan için çözmek yine bir token döndürür, ancak sitenin reddedeceği bir biçimde; bu yüzden bu kontrol sizi kafa karıştırıcı bir öğleden sonradan kurtarır. MAM sayfalarında anahtar, script’in kendi src değerinde ?key= sonrasında durabilir. Aynı CDN ilgisiz paketler de sunduğu için host’a göre değil, captchafox paket yoluna göre eşleştirin.
import re import requests PAGE_URL = "https://example.com/signup" session = requests.Session() html = session.get(PAGE_URL, timeout=30).text # The container: <div class="captchafox" data-sitekey="sk_..."> tag = re.search(r'<[^>]*class="(?:[^"]*\s)?captchafox(?:\s[^"]*)?"[^>]*>', html) key = tag and re.search(r'data-sitekey="([^"]+)"', tag.group(0)) # MAM pages may carry the key in the script src instead. key = key or re.search(r'captchafox[^"]*/api\.js\?key=([^"&]+)', html) sitekey = key.group(1) if key else None # The MAM build expects a MAM_ token; everything else is the default. uses_mam = "mampkg/@mamdev/core.frontend.libs.captchafox" in html print(sitekey, uses_mam)
Sınıf deseni boşluklarla sınırlandırılmıştır, böylece captchafox-container gibi bir sınıfa sahip sarmalayıcı bir öğe yanlışlıkla eşleşmez. Desen, öznitelik değerlerinin etrafında çift tırnak bekler; CaptchaFox’un kendi kod parçacığı da onları böyle yazar.
2. Adım: captchafox() çağrısı
Python ile CaptchaFox çözmek için tek bir metoda ihtiyacınız var; bu metot sitekey’i ve sayfa URL’sini, ayrıca isteğe bağlı anahtar kelime argümanlarını alır. Standart widget için bu ikisi yeterlidir.
# pip install "capskip>=1.3.0"
from capskip import CapSkip
solver = CapSkip(host="127.0.0.1", port=8080)
result = solver.captchafox("YOUR_SITEKEY", "https://example.com/signup")
print(result["token"]) # goes in cf-captcha-response
print(result.get("userAgent")) # send this as the User-AgentSonuç düz bir dict’tir. token ve code aynı dizeyi tutar; token adını doldurduğu alandan alır. userAgent, token’ı üreten tarayıcının kimliğidir; bu tarayıcı CapSkip’in kendi tarayıcısıdır, sizin gönderdiğiniz herhangi bir şey değildir. Bu anahtar yalnızca çözüm bir user agent bildirdiğinde bulunur. Bu yüzden onu köşeli parantezle değil result.get() ile okuyun; aksi hâlde user agent içermeyen nadir bir çözüm, formu göndermesi gereken satırda bir KeyError fırlatır.
Sayfa URL’si, widget’ın gerçekten çalıştığı sayfa olmalıdır. CaptchaFox her anahtarı izin verilen alan adlarından oluşan bir listeye kaydeder ve herhangi bir şey vermeden önce host’u kontrol eder; dolayısıyla yanlış sayfayla gönderilen bir anahtar ara sıra değil, her seferinde reddedilir. Bir yönlendirme, kısaltılmış bir bağlantı ya da bir arama sonucu işe yaramaz.
Metodun kabul ettiği seçenekler
MAM paketini yükleyen bir sayfa için, script etiketindeki paket yolunu api_server olarak verin. SDK, değeri None olan her anahtar kelime argümanını istek gönderilmeden önce çıkarır; böylece seçeneği her çağrıda verebilir ve kararı 1. adımdaki kontrole bırakabilirsiniz.
# Copied from the script tag on MAM pages.
MAM_PACKAGE = "https://s.uicdn.com/mampkg/@mamdev/core.frontend.libs.captchafox/"
result = solver.captchafox(
sitekey,
PAGE_URL,
# None is dropped, so the standard widget sends nothing extra.
api_server=MAM_PACKAGE if uses_mam else None,
)captchafox() metodu api_server dışında proxy, proxytype ve useragent değerlerini, ayrıca saniye cinsinden çağrı başına bir timeout ve polling_interval alır. useragent seçeneği diğer servislerle uyumluluk için kabul edilir ve bilinçli olarak uygulanmaz, çünkü CapSkip gerçek bir tarayıcıda, o tarayıcının kendi tutarlı kimliğiyle çözer. Başka herhangi bir anahtar kelime, boş bir sitekey veya URL, type ve uri içermeyen bir proxy dict’i ya da HTTP, HTTPS, SOCKS5 veya SOCKS5H dışında bir proxy türü, daha hiçbir istek gönderilmeden bir ValidationException fırlatır.
3. Adım: token’ı üreten user agent ile gönderin
Python ile CaptchaFox çözerken sitenin token’ı kabul edip etmeyeceğine karar veren adım budur. Varsayılan ayarlarda requests, User-Agent olarak python-requests ve ardından sürüm numarasını gönderir; httpx de python-httpx ve ardından kendi sürüm numarasını gönderir. İkisi de token’ı üreten tarayıcı değildir. Dönen değeri, token’ı taşıyan isteğe kopyalayın.
# session is the one Step 1 fetched the page with, so it carries its cookies.
ua = result.get("userAgent")
resp = session.post(
PAGE_URL, # or wherever the form's action attribute points
data={"email": "YOUR_EMAIL", "cf-captcha-response": result["token"]},
# Per request, not on session.headers: the next token may differ.
headers={"User-Agent": ua} if ua else {},
timeout=30,
)
print(resp.status_code)Bir başlığı post() metoduna verdiğinizde bu başlık, yalnızca o istek için oturumun varsayılan başlıklarıyla birleştirilir ve onların üzerine yazılır; böylece oturum çerezlerini korur ve sonraki her istek eskisi gibi gider. Bunun yerine session.headers ayarlamak, tek bir çözümün user agent’ını sonraki her isteğe, bir sonraki token’ın gönderimi dahil, damgalar. httpx kullanıyorsanız sayfayı tek bir httpx.Client üzerinden çekin ve gönderimi de onunla yapın, böylece çerezler aktarılır; data, headers ve timeout değerlerini de bu istemcinin post() metoduna aynı şekilde verin.
İki kural daha, CaptchaFox’un token’ı site tarafında nasıl kontrol ettiğinden doğar. Her token yalnızca bir kez ve kısa bir süre içinde doğrulanabilir, bu yüzden göndermeye hazır olduğunuzda çözün ve hemen gönderin. Ayrıca token’ı opak kabul edin: kırpmayın, yeniden kodlamayın ve biçimini değiştirmeyin. Bazı siteler token’ı form gönderimi yerine bir JSON gövdesinde gönderir; bu yüzden DevTools açıkken formu bir kez elle gönderin ve sayfanın gönderdiğini birebir taklit edin.
4. Adım: yeniden denemeler, challenge türleri ve zaman aşımları
CaptchaFox’un hangi challenge’ı çıkaracağını siz seçmezsiniz. Çözümlerin çoğunda hiçbir challenge çıkmaz, çünkü tarayıcı kanıtları tek başına yeterli olur; bir kaydırmalı bulmaca çıktığında ise CapSkip onu genellikle tamamlar. Görsel seçme ve ses challenge’ları nadirdir ve çözülmez: zaman aşımının sonunda değil, saniyeler içinde, mesajında ERROR_CAPTCHA_UNSOLVABLE geçen bir ApiException olarak geri dönerler. Yeni bir deneme genellikle başka bir challenge getirir, bu yüzden yeniden denemenin iki yolu var.
- CapSkip’te. Ayarların CaptchaFox bölümünde Retries (0-3) seçeneği bulunur ve varsayılanı 0’dır. Değer yükseltildiğinde CapSkip, desteklenmeyen challenge’larda, süresi dolan denemelerde ve tarayıcı hatalarında kendi başına yeni bir challenge ister; sitenin reddettiği bir anahtarı ise hiçbir zaman yeniden denemez. Her ek yeniden deneme tek bir çağrıya en fazla bir Row Timeout, yani varsayılan olarak 150 saniye ekleyebilir; bu yüzden bu değeri yükselttiğinizde captchafox() metoduna daha uzun bir timeout verin.
- Kodunuzda. İstisnayı yakalayın ve aşağıdaki gibi yeniden çağırın. Tek pürüz şu: reddedilen bir anahtar da API üzerinden çözülemez olarak görünür, bu yüzden yanlış alan adında kullanılan bir anahtar da yeniden denenir. Böyle bir anahtar her denemede saniyeler içinde başarısız olur ve bir kez bile başarılı olmaz; onu ele veren işaret de budur.
from capskip.exceptions import ApiException
def solve_captchafox(sitekey, url, attempts=3, **options):
for attempt in range(1, attempts + 1):
try:
return solver.captchafox(sitekey, url, **options)
except ApiException as exc:
# Select, audio and unreadable slide draws come back
# unsolvable; redraw. Anything else, such as a wrong
# API key, is final.
if "UNSOLVABLE" not in str(exc) or attempt == attempts:
raisecaptchafox(), istemcinin varsayılanı 300 saniye olan recaptchaTimeout değeriyle yoklama yapar, çünkü bu gerçek bir tarayıcı oturumudur. CapSkip de kendi zamanlayıcılarını çalıştırır. Bir görev, 10 CaptchaFox thread’inden (Max. Threads) biri için en fazla 250 saniye (Wait Timeout) bekleyebilir ve tek bir deneme 150 saniye (Row Timeout) alır. Retries değeri 0 iken ve boş bir thread varsa başarısız bir deneme, SDK’nın 300 saniyesi dolmadan çok önce size CapSkip’ten gelen bir ApiException olarak ulaşır; görev uzun süre kuyrukta beklerse SDK önce kendi sınırına ulaşabilir ve bunun yerine bir TimeoutException fırlatabilir.
Aynı anda birden fazla token çözmek
AsyncCapSkip, Python’da bir takma ad değil, gerçek bir asyncio istemcisidir; bu yüzden asyncio.gather birkaç çözümü yan yana çalıştırır. Onu httpx’in async istemcisiyle eşleştirin ve her token’ı gönderilene kadar kendi user agent’ıyla birlikte tutun.
import asyncio
import httpx
from capskip import AsyncCapSkip
solver = AsyncCapSkip(host="127.0.0.1", port=8080)
async def solve_and_submit(client, sitekey, url, form):
await client.get(url) # the form's cookies land in client
result = await solver.captchafox(sitekey, url)
ua = result.get("userAgent")
return await client.post(
url,
data={**form, "cf-captcha-response": result["token"]},
headers={"User-Agent": ua} if ua else {},
)
async def main(jobs):
async with httpx.AsyncClient(timeout=30) as client:
return await asyncio.gather(
*(solve_and_submit(client, *job) for job in jobs),
return_exceptions=True,
)İki sınır geçerlidir. CapSkip varsayılan olarak aynı anda 10 CaptchaFox çözümü çalıştırır; geri kalanlar boş bir thread için en fazla 250 saniyelik Wait Timeout süresi kadar bekler. Bu yüzden normal çözüm sürelerinde elli iş üzerinde bir gather sorunsuz çalışır; daha büyük partiler için Max. Threads değerini yükseltin ya da daha küçük gruplar hâlinde gather yapın. Ayrıca CaptchaFox yalnızca tarayıcıyı değil ağı da puanlar, bu yüzden tek bir adresten gelen çok sayıda çözüm challenge oranını yükseltir. Proxy’leri CapSkip’in CaptchaFox bölümünde yapılandırın ya da her çağrıda type ve uri içeren bir proxy dict’i verin; gönderimi de aynı çıkış üzerinden yapın. Daha fazla asyncio kalıbı şurada: Python’da paralel CAPTCHA çözme rehberi.
Çözücüyü başka bir makinede çalıştırmak
Betik ve CapSkip aynı Windows bilgisayarı paylaştığı sürece 127.0.0.1 doğru adrestir. Python kodu bir VPS’e, bir konteynere, bir CI runner’a ya da barındırılan bir notebook’a taşındığında loopback yanlış makineyi gösterir ve ilk çözüm bir NetworkException fırlatır. CapSkip’i Server moduna alın; o zaman ağ adresinizi veya genel IP’nizi dinler, böylece bunların hepsi onu aynı API üzerinden çağırabilir. Rota internetten geçiyorsa statik bir genel IP kullanın, API anahtarı doğrulamasını açın ve bir Windows Firewall kuralıyla portu yalnızca beklediğiniz adreslerle sınırlayın. Çözücü hâlâ sizin kendi Windows makinenizdir ve çözüm başına ücretlendirme hâlâ yoktur.
SDK ortam değişkenlerini kendiliğinden okumaz. Tam örnekte olduğu gibi CAPSKIP_HOST, CAPSKIP_PORT ve CAPSKIP_API_KEY değerlerini kodunuzda okuyup constructor’a verin; böylece aynı betik hem masanızda hem de bir sunucuda çalışır.
Tam çalışan örnek
# pip install "capskip>=1.3.0" requests
import os
import re
import requests
from capskip import CapSkip
from capskip.exceptions import (ApiException, CapSkipError,
TimeoutException, ValidationException)
PAGE_URL = "https://example.com/signup"
# Copied from the script tag on MAM pages.
MAM_PACKAGE = "https://s.uicdn.com/mampkg/@mamdev/core.frontend.libs.captchafox/"
solver = CapSkip(
apiKey=os.getenv("CAPSKIP_API_KEY", "capskip"),
host=os.getenv("CAPSKIP_HOST", "127.0.0.1"),
port=int(os.getenv("CAPSKIP_PORT", "8080")),
)
session = requests.Session()
html = session.get(PAGE_URL, timeout=30).text
tag = re.search(r'<[^>]*class="(?:[^"]*\s)?captchafox(?:\s[^"]*)?"[^>]*>', html)
key = tag and re.search(r'data-sitekey="([^"]+)"', tag.group(0))
key = key or re.search(r'captchafox[^"]*/api\.js\?key=([^"&]+)', html)
if not key:
raise SystemExit("No sitekey in the HTML; find it in DevTools.")
api_server = MAM_PACKAGE if "mampkg/@mamdev/core.frontend.libs.captchafox" in html else None
try:
for attempt in range(1, 4):
try:
result = solver.captchafox(key.group(1), PAGE_URL,
api_server=api_server)
break
except ApiException as exc:
# Select, audio and unreadable slide draws come back unsolvable.
if "UNSOLVABLE" not in str(exc) or attempt == 3:
raise
print(f"attempt {attempt}: {exc}")
except ValidationException as exc:
raise SystemExit(f"not sent: {exc}")
except TimeoutException:
raise SystemExit("gave up waiting; recaptchaTimeout is 300 seconds")
except CapSkipError as exc:
# A third unsolvable draw, a refused key, or CapSkip unreachable.
raise SystemExit(f"solve failed: {exc!r}")
ua = result.get("userAgent")
resp = session.post(
PAGE_URL, # or wherever the form's action attribute points
data={"email": "YOUR_EMAIL", "cf-captcha-response": result["token"]},
headers={"User-Agent": ua} if ua else {},
timeout=30,
)
print(resp.status_code, "UA sent:", bool(ua))Çözüm her çalıştırmada anında başarısız oluyorsa her şeyden önce sayfa URL’sini kontrol edin, çünkü kayıtlı alan adlarının dışında kullanılan bir anahtar her seferinde aynı şekilde başarısız olur. Regex hiçbir şey bulamazsa sayfa widget’ı script ile oluşturuyordur ve anahtar, 1. adımda anlatıldığı gibi render çağrısında ya da Network sekmesindedir. Bu metodun arkasındaki ham endpoint şurada belgelenmiştir: CaptchaFox API referansı.
Sık görülen hatalar ve anlamları
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
| Site, CapSkip’in çözüldü olarak döndürdüğü bir token’ı reddediyor | Gönderim, token’ı üreten tarayıcı olarak değil, python-requests veya python-httpx olarak gitti | O istekte User-Agent başlığı olarak result.get("userAgent") değerini gönderin |
| User agent eşleştiği hâlde reddediliyor | Sayfa MAM paketini yüklüyor ama çözümde varsayılan widget kullanıldı ya da tam tersi | Script etiketini okuyun ve api_server değerini ona göre ayarlayın |
| userAgent üzerinde bir KeyError | Çözüm bir user agent bildirmedi; userAgent anahtarı yalnızca bildirdiğinde bulunur | Değeri result.get() ile okuyun ve başlığı yalnızca bir değer varsa gönderin |
| Tek bir anahtar için her seferinde hemen gelen bir ApiException | Sayfa URL’si, anahtarın kayıtlı olduğu alan adlarının dışında ya da anahtarın kendisi yanlış | Bir yönlendirmeyi ya da arama sonucunu değil, widget’ın çalıştığı sayfayı gönderin ve anahtarı yeniden kontrol edin |
| Ara sıra gelen, ERROR_CAPTCHA_UNSOLVABLE içeren bir ApiException | CaptchaFox bir görsel seçme veya ses challenge’ı ya da CapSkip’in okuyamadığı bir kaydırmalı bulmaca varyantı çıkardı | Kodda yeniden deneyin ya da CapSkip’in CaptchaFox ayarlarında Retries değerini yükseltin |
| Bir kez çalışan token ikinci seferde başarısız oluyor | Her token yalnızca bir kez doğrulanır ve süresi çabuk dolar | Her gönderim için yeni bir token çözün ve hemen gönderin |
| Çalışma ilerledikçe artan challenge’lar, ardından ret yanıtları | Her çözüm tek bir adresten geliyor ve CaptchaFox ağı puanlıyor | Çözümleri bir proxy havuzuna dağıtın ve gönderimi aynı çıkış üzerinden yapın |
| Daha hiçbir şey gönderilmeden ValidationException | Boş bir sitekey veya URL, metodun kabul etmediği bir anahtar kelime argümanı ya da CapSkip’in kabul etmediği bir proxy türü | Sitekey’in bulunduğunu kontrol edin ve mesajda adı geçen argümanı düzeltin ya da çıkarın |
| İlk çağrıda 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 |
FAQ
result["code"], result["token"] değerinden farklı mı?
Hayır, CaptchaFox için ikisi aynı dizedir. code, her CapSkip metodunun doldurduğu alandır ve eski kodun değişmeden çalışmaya devam etmesini sağlar; token ise formun beklediğiyle eşleşen addır. Yeni kodda token kullanın; böylece kod, doldurduğu alan gibi okunur.
Token’ı bir Playwright veya Selenium oturumunda kullanabilir miyim?
Evet, gönderim CapSkip’in döndürdüğü user agent ile yapıldığı sürece. Playwright user agent’ı bir context oluşturulurken sabitler; bu yüzden önce çözün, context’i browser.new_context(user_agent=ua) ile açın, formu yükleyin, token’ı cf-captcha-response alanına yazın ve gönderin. Chrome ile Selenium kullanıyorsanız driver başlamadan önce user-agent komut satırı argümanını bu değerle Chrome seçeneklerine ekleyin ya da çalışan bir oturumu driver.execute_cdp_cmd("Network.setUserAgentOverride", {"userAgent": ua}) ile değiştirin. Otomasyonunuzun başka hiçbir şey için tarayıcıya ihtiyacı yoksa yukarıdaki requests yolu daha basittir.
Barındırılan bir platformdaki Python betiği çözücüye erişebilir mi?
Evet. Bağlantı ayarlarından CapSkip’i Server moduna alın; böylece loopback yerine bir ağ adresini dinler. O adresi betiğinizde CAPSKIP_HOST değişkeninden okuyun ve CapSkip() çağrısına verin. Bir VPS, bir konteyner sunucusu, bir CI runner ve barındırılan bir notebook; hepsi aynı HTTP API üzerinden bağlanır. Rota internetten geçiyorsa statik bir genel IP ve bir güvenlik duvarı kuralı kullanın. Çözücü sizin sahip olduğunuz donanımda kalır, dolayısıyla çözümlerin nasıl sayıldığı konusunda hiçbir şey değişmez.
Bunun C# sürümünden farkı nedir?
Çağrı ve kurallar aynıdır; tuzaklar farklıdır. C#’ta HttpClient, siz eklemedikçe hiçbir User-Agent göndermez. Python’da ise yaygın iki istemci de bunun yerine kendi adını gönderir: python-requests veya python-httpx. Bir site bunları da aynı kolaylıkla reddedebilir. .NET tarafı şurada ele alınıyor: C# CaptchaFox rehberi.
Kısa özet
Python ile CaptchaFox çözmek için sitekey’i captchafox kapsayıcısından, render çağrısından ya da Network sekmesinden okuyun ve sayfanın MAM paketini yükleyip yüklemediğini not edin. solver.captchafox() metodunu sitekey ve gerçek sayfa URL’siyle çağırın; api_server seçeneğini yalnızca MAM sayfaları için ekleyin. result["token"] değerini, User-Agent başlığı olarak result.get("userAgent") ile birlikte cf-captcha-response alanında bir kez ve hemen gönderin. Çözülemeyen challenge’ları yeniden deneyin, hacim büyüdükçe proxy ekleyin ve betik çözücünün makinesinden ayrıldığında Server moduna geçin.
- CaptchaFox’un nasıl çalıştığı ve çözücünün neleri kapsadığı: CaptchaFox çözücü sayfası.
- Python paketinin desteklediği tüm CAPTCHA türleri: Python CAPTCHA çözücü sayfası.
Görsel seçme challenge’ı çıktığında yeniden denemek, bu türün gerektirdiği tek alışkanlıktır ve kendi makinenizde çalışan bir yerel captcha çözücü ile her yeniden deneme, faturalanan yeni bir çözüm yerine yalnızca birkaç saniyeye mal olur.
