Cara Memecahkan CaptchaFox di Python dengan requests dan httpx

Untuk memecahkan CaptchaFox di Python, panggil solver.captchafox() dari paket capskip dengan sitekey dan URL halaman, masukkan token yang dikembalikannya ke field form cf-captcha-response, lalu kirim permintaan itu dengan user agent yang dikembalikan bersama token tersebut. Langkah terakhir inilah tempat kode Python biasanya salah. Secara default, requests dan httpx sama-sama memperkenalkan dirinya di header User-Agent, dan situs yang mengharapkan token datang dari browser yang menerbitkannya akan menolak permintaan itu, sehingga pemecahan yang berhasil sempurna tetap bisa gagal saat dikirim. CapSkip menambahkan CaptchaFox pada versi 1.4.0. Panduan ini membahas key, pemanggilan, pengiriman, percobaan ulang, dan menjalankan beberapa pemecahan secara berdampingan.
Apa yang Anda butuhkan
- CapSkip 1.4.0 atau lebih baru yang berjalan di komputer Windows. Rilis itu menambahkan CaptchaFox, bersama Friendly Captcha dan Capy Puzzle.
- Python 3.10 atau lebih baru dan paket capskip versi 1.3.0 atau lebih baru, rilis pertama yang memiliki metode captchafox(). Contoh kodenya juga memakai requests, dan bagian tentang pemecahan paralel memakai httpx.
- Dua nilai dari halaman target: sitekey, dan URL halaman tempat widget berjalan. Langkah 1 menunjukkan letak key tersebut dan tag script mana yang perlu Anda periksa sekalian.
- Sebuah alamat untuk pemecah CAPTCHA. Dalam mode Local, CapSkip menjawab di 127.0.0.1 hanya untuk perangkat itu; dalam mode Server, CapSkip mendengarkan di alamat jaringan atau IP publik Anda, sehingga skrip di mesin lain dapat memanggilnya melalui API. Keduanya diatur di pengaturan koneksi.
# Quoted, so cmd.exe does not read >= as a redirect pip install "capskip>=1.3.0" requests httpx
Langkah 1: baca sitekey dan sumber widget
Sitekey bersifat publik, sama untuk setiap pengunjung, dan secara konvensi diawali sk_. Sebagian besar halaman menaruhnya di container widget, yaitu sebuah div dengan class captchafox dan atribut data-sitekey. Halaman yang membangun widget dari skripnya sendiri memberikan key itu ke pemanggilan captchafox.render, dan jika tidak satu pun dari keduanya muncul di HTML yang Anda ambil, key-nya ada di tab Network: key itu adalah segmen path setelah /captcha/ dalam permintaan ke api.captchafox.com.
Selagi Anda membaca halaman, periksa skrip mana yang memuat widget. Sebagian besar situs memuatnya dari cdn.captchafox.com dan mendapat token biasa. Beberapa platform justru menyematkan paket dari s.uicdn.com/mampkg/, dan situs tersebut mengharapkan token yang diawali MAM_. Memecahkan untuk sumber yang salah tetap menghasilkan token, tetapi dalam format yang kemudian ditolak situs, jadi pemeriksaan ini menghemat satu sore yang membingungkan. Di halaman MAM, key bisa berada di src milik skrip itu sendiri, setelah ?key=, dan CDN yang sama juga menyajikan paket lain yang tidak berhubungan, jadi cocokkan path paket captchafox, bukan host-nya.
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)
Pola class dibatasi oleh spasi, sehingga elemen pembungkus dengan class seperti captchafox-container tidak ikut cocok secara tidak sengaja. Pola ini mengharapkan tanda kutip ganda di sekitar nilai atribut, sesuai cara snippet resmi CaptchaFox menuliskannya.
Langkah 2: pemanggilan captchafox()
Untuk memecahkan CaptchaFox di Python, Anda cukup memakai satu metode, yang menerima sitekey dan URL halaman ditambah argumen keyword opsional. Untuk widget standar, hanya dua nilai itu yang dibutuhkan.
# 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-AgentHasilnya adalah dict biasa. token dan code berisi string yang sama, dan token dinamai sesuai field yang diisinya. userAgent adalah identitas browser yang menerbitkan token, yaitu browser milik CapSkip sendiri, bukan apa pun yang Anda kirim. Key userAgent hanya ada jika pemecahan melaporkannya, jadi bacalah dengan result.get() dan bukan dengan tanda kurung siku, atau pemecahan langka yang tidak memilikinya akan memunculkan KeyError di baris yang seharusnya mengirim form.
URL halaman harus berupa halaman tempat widget benar-benar berjalan. CaptchaFox mendaftarkan setiap key terhadap daftar domain yang diizinkan dan memeriksa host sebelum menerbitkan apa pun, sehingga key yang dikirim dengan halaman yang salah selalu ditolak, bukan sesekali. Redirect, tautan yang dipendekkan, atau hasil pencarian tidak akan berhasil.
Opsi yang diterima metode ini
Untuk halaman yang memuat paket MAM, berikan path paket dari tag script-nya sebagai api_server. SDK membuang argumen keyword apa pun yang bernilai None sebelum permintaan dikirim, jadi Anda bisa memberikan opsi itu di setiap pemanggilan dan membiarkan pemeriksaan di Langkah 1 yang menentukannya.
# 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,
)Selain api_server, captchafox() menerima proxy, proxytype dan useragent, ditambah timeout dan polling_interval per panggilan dalam detik. Opsi useragent diterima demi kompatibilitas dengan layanan lain dan sengaja tidak diterapkan, karena CapSkip memecahkan di browser sungguhan dengan identitas browser itu sendiri yang konsisten. Keyword lain apa pun, sitekey atau URL yang kosong, dict proxy tanpa type dan uri, atau tipe proxy selain HTTP, HTTPS, SOCKS5 atau SOCKS5H memicu ValidationException sebelum permintaan dikirim.
Langkah 3: kirim dengan user agent yang menerbitkan token
Saat Anda memecahkan CaptchaFox di Python, inilah langkah yang menentukan apakah situs menerima token. Secara bawaan, requests mengirim User-Agent berupa python-requests diikuti nomor versinya, dan httpx mengirim python-httpx diikuti nomor versinya sendiri. Keduanya bukan browser yang menghasilkan token. Salin nilai yang dikembalikan ke permintaan yang membawa token itu.
# 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)Header yang diberikan ke post() digabungkan di atas default session hanya untuk permintaan itu, sehingga session tetap menyimpan cookie-nya dan setiap permintaan berikutnya dikirim seperti biasa. Sebaliknya, menyetel session.headers akan menempelkan user agent dari satu pemecahan ke setiap permintaan sesudahnya, termasuk pengiriman token berikutnya. Dengan httpx, ambil halaman dan kirim form melalui satu httpx.Client agar cookie ikut terbawa, lalu berikan data, headers dan timeout ke post() miliknya dengan cara yang sama.
Dua aturan lagi berasal dari cara CaptchaFox memeriksa token di sisi situs. Setiap token hanya bisa diverifikasi sekali, dan hanya dalam waktu singkat, jadi pecahkan saat Anda siap mengirim, lalu langsung kirim. Selain itu, perlakukan token sebagai string opaque: jangan memotong, meng-encode ulang, atau mengubah formatnya. Sebagian situs mengirimnya di body JSON, bukan lewat form post, jadi kirim form sekali secara manual dengan DevTools terbuka, lalu tiru persis apa yang dikirim halaman itu.
Langkah 4: percobaan ulang, tipe challenge, dan timeout
Anda tidak memilih challenge mana yang ditampilkan CaptchaFox. Sebagian besar pemecahan tidak menampilkan apa pun, karena bukti dari browser sudah lolos dengan sendirinya, dan jika puzzle geser muncul, CapSkip biasanya menyelesaikannya. Challenge pilih gambar dan audio jarang muncul dan tidak dipecahkan: keduanya kembali sebagai ApiException yang pesannya berisi ERROR_CAPTCHA_UNSOLVABLE, dalam hitungan detik, bukan di akhir timeout. Percobaan baru biasanya memunculkan challenge lain, jadi ada dua cara untuk mencoba ulang.
- Di CapSkip. Bagian CaptchaFox di pengaturan memiliki Retries (0-3), bernilai 0 secara default. Jika dinaikkan, CapSkip dengan sendirinya mengulang pemecahan saat menemui challenge yang tidak didukung, percobaan yang kehabisan waktu, atau error browser, tetapi tidak pernah mencoba ulang key yang ditolak situs. Setiap percobaan ulang tambahan bisa menambah waktu hingga satu Row Timeout, 150 detik secara default, pada satu pemanggilan, jadi berikan timeout yang lebih panjang ke captchafox() saat Anda menaikkannya.
- Di kode Anda. Tangkap exception-nya dan panggil lagi, seperti di bawah. Satu-satunya jebakan adalah key yang ditolak juga terbaca sebagai tidak bisa dipecahkan melalui API, sehingga key yang dipakai di domain yang salah ikut dicoba ulang. Key itu gagal dalam hitungan detik di setiap percobaan dan tidak pernah sekali pun berhasil, dan itulah tandanya.
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() melakukan polling dengan recaptchaTimeout milik klien, 300 detik secara default, karena ini adalah sesi browser sungguhan. CapSkip juga menjalankan timer-nya sendiri. Sebuah tugas bisa menunggu hingga 250 detik (Wait Timeout) untuk salah satu dari 10 thread CaptchaFox (Max. Threads), dan satu percobaan mendapat 150 detik (Row Timeout). Dengan Retries bernilai 0 dan ada thread yang kosong, percobaan yang gagal sampai ke Anda sebagai ApiException dari CapSkip jauh sebelum 300 detik milik SDK habis; jika tugas lama mengantre, SDK bisa mencapai batasnya lebih dulu dan justru memunculkan TimeoutException.
Memecahkan beberapa token sekaligus
AsyncCapSkip adalah klien asyncio sungguhan di Python, bukan alias, sehingga asyncio.gather menjalankan beberapa pemecahan secara berdampingan. Pasangkan dengan klien async milik httpx, dan simpan setiap token bersama user agent-nya sendiri sampai token itu dikirim.
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,
)Ada dua batasan. CapSkip menjalankan 10 pemecahan CaptchaFox sekaligus secara default, dan sisanya menunggu thread yang kosong hingga batas Wait Timeout 250 detik, jadi gather atas lima puluh job masih aman dengan waktu pemecahan normal; untuk batch yang lebih besar, naikkan Max. Threads atau jalankan gather dalam kelompok yang lebih kecil. Selain itu, CaptchaFox menilai jaringan, bukan hanya browser, jadi banyak pemecahan dari satu alamat akan menaikkan frekuensi challenge. Konfigurasikan proxy di bagian CaptchaFox pada CapSkip, atau berikan dict proxy dengan type dan uri di setiap pemanggilan, dan kirim form melalui alamat keluar yang sama. Pembahasan lebih lanjut tentang pola asyncio ada di panduan memecahkan CAPTCHA secara paralel di Python.
Menjalankan solver di mesin lain
127.0.0.1 sudah benar selama skrip dan CapSkip berada di PC Windows yang sama. Begitu kode Python dipindahkan ke VPS, container, CI runner, atau notebook yang di-host, loopback menunjuk ke mesin yang salah dan pemecahan pertama memunculkan NetworkException. Alihkan CapSkip ke mode Server dan ia akan mendengarkan di alamat jaringan atau IP publik Anda, sehingga semua lingkungan itu dapat memanggilnya melalui API yang sama. Gunakan IP publik statis jika rutenya melewati internet, aktifkan validasi API key, dan batasi port hanya untuk alamat yang Anda harapkan dengan aturan Windows Firewall. Pemecah CAPTCHA tetap berupa mesin Windows milik Anda sendiri, dan pemecahannya tetap tanpa kuota.
SDK tidak membaca variabel lingkungan dengan sendirinya. Baca CAPSKIP_HOST, CAPSKIP_PORT dan CAPSKIP_API_KEY di kode Anda dan berikan ke konstruktor, seperti pada contoh lengkap, agar skrip yang sama bisa berjalan di komputer Anda maupun di server.
Contoh lengkap yang berfungsi
# 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))Jika pemecahan langsung gagal setiap kali dijalankan, periksa URL halaman sebelum hal lain, karena key yang dipakai di luar domain terdaftarnya gagal dengan cara yang sama setiap kali. Ketika regex tidak menemukan apa pun, halaman membangun widget dari skrip, dan key-nya ada di pemanggilan render atau di tab Network seperti dijelaskan di Langkah 1. Endpoint mentah di balik metode ini didokumentasikan di referensi API CaptchaFox.
Kesalahan umum dan artinya
| Apa yang Anda lihat | Penyebab | Perbaiki |
|---|---|---|
| Situs menolak token yang dikembalikan CapSkip sebagai berhasil dipecahkan | Pengiriman dilakukan sebagai python-requests atau python-httpx, bukan sebagai browser yang menerbitkan token | Kirim result.get("userAgent") sebagai header User-Agent pada permintaan itu |
| Ditolak padahal user agent sudah cocok | Halaman memuat paket MAM tetapi pemecahan memakai widget default, atau sebaliknya | Baca tag script dan setel api_server agar sesuai dengannya |
| KeyError pada userAgent | Pemecahan tidak melaporkan user agent, dan key userAgent hanya ada jika user agent dilaporkan | Baca dengan result.get() dan kirim header hanya jika ada nilainya |
| ApiException langsung muncul, setiap kali, untuk satu key | URL halaman berada di luar domain tempat key didaftarkan, atau key itu sendiri salah | Kirim halaman tempat widget berjalan, bukan redirect atau hasil pencarian, dan periksa ulang key-nya |
| ApiException sesekali yang berisi ERROR_CAPTCHA_UNSOLVABLE | CaptchaFox menampilkan challenge pilih gambar atau audio, atau varian geser yang tidak bisa dibaca CapSkip | Coba ulang di kode, atau naikkan Retries di pengaturan CaptchaFox pada CapSkip |
| Token yang berhasil sekali gagal pada kali kedua | Setiap token hanya bisa diverifikasi sekali dan cepat kedaluwarsa | Pecahkan token baru untuk setiap pengiriman, dan langsung kirim |
| Challenge makin sering, lalu penolakan, seiring berjalannya proses | Setiap pemecahan berasal dari satu alamat, dan CaptchaFox menilai jaringannya | Sebarkan pemecahan ke pool proxy, dan kirim melalui alamat keluar yang sama |
| ValidationException sebelum apa pun terkirim | Sitekey atau URL kosong, argumen keyword yang tidak diterima metode ini, atau tipe proxy yang tidak diterima CapSkip | Pastikan sitekey ditemukan, dan perbaiki atau buang argumen yang disebut dalam pesan |
| NetworkException pada pemanggilan pertama | CapSkip tidak berjalan, atau host dan port-nya salah | Jalankan CapSkip, lalu periksa apakah ia harus berada di mode Local atau mode Server |
FAQ
Apakah result["code"] berbeda dari result["token"]?
Tidak, untuk CaptchaFox keduanya adalah string yang sama. code adalah field yang diisi oleh setiap metode CapSkip, sehingga kode lama tetap berfungsi tanpa perubahan, dan token adalah nama yang sesuai dengan yang diharapkan form. Gunakan token di kode baru agar terbaca seperti field yang diisinya.
Bisakah saya memakai token di sesi Playwright atau Selenium?
Bisa, asalkan pengiriman dilakukan dengan user agent yang dikembalikan CapSkip. Playwright menetapkan user agent saat context dibuat, jadi pecahkan dulu, buka context dengan browser.new_context(user_agent=ua), muat form, tulis token ke field cf-captcha-response, lalu kirim. Di Selenium dengan Chrome, tambahkan switch user-agent dengan nilai itu ke opsi Chrome sebelum driver dimulai, atau ubah sesi yang sedang berjalan dengan driver.execute_cdp_cmd("Network.setUserAgentOverride", {"userAgent": ua}). Jika otomatisasi Anda tidak membutuhkan browser untuk hal lain, cara dengan requests di atas lebih sederhana.
Bisakah skrip Python di platform hosting menjangkau pemecah CAPTCHA?
Bisa. Alihkan CapSkip ke mode Server di pengaturan koneksi agar ia mendengarkan di alamat jaringan, bukan di loopback, baca alamat itu dari CAPSKIP_HOST di skrip Anda, lalu berikan ke CapSkip(). VPS, container host, CI runner, dan notebook yang di-host semuanya terhubung melalui API HTTP yang sama. Gunakan IP publik statis dan aturan firewall jika rutenya melewati internet. Pemecah CAPTCHA tetap berada di perangkat milik Anda, jadi tidak ada yang berubah soal cara pemecahan dihitung.
Apa bedanya dengan versi C#?
Pemanggilan dan aturannya sama; jebakannya yang berbeda. Di C#, HttpClient sama sekali tidak mengirim User-Agent kecuali Anda menambahkannya. Di Python, kedua klien yang umum justru mengirim namanya sendiri, python-requests atau python-httpx, yang sama mudahnya ditolak situs. Sisi .NET dibahas di panduan CaptchaFox untuk C#.
Versi singkatnya
Untuk memecahkan CaptchaFox di Python, baca sitekey dari container captchafox, pemanggilan render, atau tab Network, lalu catat apakah halaman memuat paket MAM. Panggil solver.captchafox() dengan sitekey dan URL halaman yang sebenarnya, dan tambahkan api_server hanya untuk halaman MAM. Kirim result["token"] di cf-captcha-response dengan result.get("userAgent") sebagai header User-Agent, sekali saja dan secepatnya. Coba ulang challenge yang tidak bisa dipecahkan, tambahkan proxy seiring volume bertambah, dan beralihlah ke mode Server begitu skrip tidak lagi berada di mesin pemecah CAPTCHA.
- Cara kerja CaptchaFox dan apa saja yang dicakup pemecah CAPTCHA: halaman pemecah CaptchaFox.
- Setiap tipe CAPTCHA yang ditangani paket Python: halaman pemecah CAPTCHA Python.
Mencoba ulang saat CaptchaFox menampilkan challenge pilih gambar adalah satu-satunya kebiasaan yang dibutuhkan tipe ini, dan dengan pemecah captcha lokal di mesin Anda sendiri, setiap percobaan ulang hanya memakan beberapa detik, bukan satu pemecahan berbayar lagi.
