Cara Memecahkan ALTCHA di Python Tanpa Menjalankan Browser

solve altcha in python - How to Solve ALTCHA in Python Without Running a Browser

Anda bisa memecahkan ALTCHA di Python hanya dengan sebuah klien HTTP dan tidak lebih. ALTCHA adalah proof of work, bukan pengenalan: situs menerbitkan sebuah challenge, dan siapa pun yang ingin lewat harus melakukan hashing sampai menemukan angka yang memenuhinya. Tidak ada yang perlu dilihat, jadi tidak ada browser, tidak ada WebDriver dan tidak ada user agent yang terlibat, dan jawabannya dihitung bukan ditebak. Itu juga berarti pemecahan bersifat deterministik. Hasilnya hanya dua: menemukan angkanya, dalam hitungan milidetik, atau challenge itu sendiri memang cacat atau sudah kedaluwarsa sebelumnya. CapSkip menambahkan tipe ini pada versi 1.2.6 dan SDK Python menyediakannya sebagai satu metode.

Apa yang Anda butuhkan

  • CapSkip 1.2.6 atau lebih baru di komputer Windows. Itulah rilis tempat ALTCHA hadir.
  • Python 3.10 atau lebih baru, dan paket CapSkip.
  • URL halaman yang memuat widget, plus endpoint tempat widget mengambil challenge-nya.
  • Sebuah alamat untuk pemecah CAPTCHA. Mode Local mendengarkan di 127.0.0.1 dan hanya melayani perangkat itu; mode Server mendengarkan di alamat jaringan atau IP publik Anda sehingga mesin lain dapat menjangkaunya. Keduanya diatur di pengaturan koneksi.
# pip install capskip
pip install capskip requests

Langkah 1: pemanggilan pemecahan, dan alamat mana yang harus dituju

Berikan URL halaman dan endpoint challenge. CapSkip mengambil sendiri challenge-nya, melakukan hashing sampai menemukan counter, dan mengembalikan payload yang diminta form.

# 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 it

Dua key dalam dictionary itu hanya ada untuk ALTCHA. Key token menyimpan payload base64, dan key number menyimpan counter yang memecahkan challenge. Key code membawa string yang sama dengan token, jadi salah satu saja sudah cukup, tetapi key token dinamai sesuai field tujuannya.

Counter dilaporkan untuk kedua generasi ALTCHA, yang lebih berguna daripada kelihatannya, karena payload keduanya tidak sepakat soal di mana nilai itu berada. Payload legacy membawanya di level teratas dan payload proof-of-work v2 tidak, melainkan menyimpannya di dalam objek solution. CapSkip membacanya dari objek solution pada respons API miliknya sendiri, jadi Anda mendapat satu field apa pun generasi yang dijalankan situs itu.

Loopback hanya benar selama Anda berbagi satu mesin

Argumen host itu adalah satu baris yang perlu diubah ketika skrip berpindah. 127.0.0.1 benar selama proses Python dan pemecah CAPTCHA berada di mesin yang sama. Begitu skrip berjalan di container, di VPS, di CI runner atau sebagai pekerjaan terjadwal pada platform terkelola, loopback justru menunjuk ke lingkungan itu dan pemanggilan pertama memunculkan NetworkException.

Mode Server adalah jawabannya. Mode itu membuat CapSkip mendengarkan di alamat jaringan atau IP publik Anda, bukan di loopback, sehingga semua lingkungan itu dapat menjangkau pemecah CAPTCHA yang sama melalui API. Gunakan IP publik statis jika lalu lintasnya melintasi internet, dengan aturan firewall yang dibatasi pada alamat yang Anda harapkan. Tidak ada hal lain yang berubah: pemecah CAPTCHA tetap berjalan di perangkat Anda sendiri dan tetap tanpa kuota, jadi hanya alamatnya yang berbeda. Baca nilainya dari environment daripada menuliskannya langsung di kode, karena klien sudah mencari CAPSKIP_HOST, CAPSKIP_PORT dan CAPSKIP_API_KEY.

Langkah 2: dari mana challenge berasal, dan dua cara memberikannya

Buka DevTools, pindah ke tab Network, dan muat ulang halaman. Widget mengirim satu permintaan untuk challenge-nya, biasanya ke path yang mengandung altcha. URL itulah yang Anda berikan. JSON yang dikembalikannya adalah dokumen challenge, dan Anda bisa memberikan dokumen itu sebagai gantinya.

Baca kode sumber halaman daripada menebak atributnya, karena atribut itu berubah antar generasi widget.

Generasi widgetAtribut yang menamai challenge
v1 dan v2challengeurl untuk endpoint, dengan atribut challengejson terpisah ketika challenge bersifat inline
v3 dan setelahnyachallenge, dan satu atribut itu menerima URL atau data challenge

Gaya tampilan widget tidak relevan di sini. Varian native, checkbox dan switch semuanya mengirim payload yang sama dan perbedaannya tidak pernah sampai ke pemecah CAPTCHA, jadi tidak ada yang perlu dideteksi. Untuk deskripsi challenge field demi field, ALTCHA menyediakan dokumentasi widget dan server.

Ketika scraper Anda sudah memiliki dokumennya, serahkan langsung dan lewati pengambilan sepenuhnya. Parameter itu menerima dictionary dan melakukan serialisasi untuk Anda, atau string JSON jika itu yang Anda pegang.

# 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,
    },
)

Memberikan keduanya diperbolehkan, dan dokumen inline yang menang, karena pengambilan hanya akan memperoleh ulang apa yang baru saja Anda berikan. Kedua jalur berbeda dalam satu hal yang penting ketika pekerjaan menumpuk: challenge inline yang sudah kedaluwarsa langsung ditolak alih-alih di-hash tanpa guna, sedangkan endpoint memungkinkan pemecah CAPTCHA mengambil challenge baru jika yang pertama mati saat pekerjaan menunggu.

Algoritma apa saja yang dicakup pemecah CAPTCHA

Satu metode menangani kedua generasi. Skema legacy dicakup dengan SHA-1, SHA-256, SHA-384 dan SHA-512, dan proof-of-work v2 dengan PBKDF2 dan SHA iteratif. PBKDF2 adalah default yang direkomendasikan ALTCHA sendiri, jadi itulah sebagian besar situs yang aktif.

Argon2id dan scrypt adalah pengecualian. Keduanya ditolak alih-alih dicoba: challenge yang meminta salah satunya kembali dalam sekitar sepertiga detik sebagai ERROR_CAPTCHA_UNSOLVABLE dan tidak pernah dicoba ulang, karena fungsi memory-hard bukan sesuatu yang bisa diperbaiki dengan percobaan ulang.

Langkah 3: kirim token kembali tanpa disentuh, sebelum kedaluwarsa

Widget mengirim payload-nya di field form bernama altcha. Kirim string itu persis seperti saat ia datang.

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"],
})

Payload itu adalah base64 dari dokumen JSON yang field-nya dicakup oleh signature HMAC milik server, jadi setiap penyuntingan membuatnya tidak valid. Memanggil strip padanya, mendekode dan mengodekan ulang, atau membangun ulang dictionary dengan urutan key yang lain semuanya menghasilkan token yang ditolak situs. Sebagian integrasi membacanya dari field body JSON bukan dari field form, jadi periksa apa yang dikirim oleh submit halaman itu sendiri dan sesuaikan dengan itu.

Jika sebuah situs menolak token yang menurut log Anda berhasil dipecahkan, challenge yang kedaluwarsa lebih mungkin menjadi penyebabnya daripada token yang rusak. Jendela challenge itu singkat dan sebagian menutup dalam waktu kurang dari dua menit, dan challenge yang kedaluwarsa kembali sebagai kegagalan verifikasi biasa yang tampak persis seperti jawaban salah. Ambil, pecahkan dan kirim dalam satu unit kerja, dan jangan pernah menahan token sementara seseorang mengisi form.

Timeout polling milik klien sendiri bukan yang membatasi Anda di sini, karena jendela challenge menutup jauh sebelum salah satu dari keduanya habis. Tetap ada gunanya mengetahui mana yang berlaku, karena ALTCHA berada di sisi yang pendek dari pembagian itu. Ini pekerjaan CPU dan bukan sesi browser, jadi ia memakai timeout polling default dan bukan timeout reCAPTCHA yang lebih panjang.

Opsi constructorBawaanApa yang dicakupnya
defaultTimeout120 detikPolling ALTCHA dan CAPTCHA gambar
recaptchaTimeout300 detikPolling reCAPTCHA, Turnstile dan GeeTest
pollingIntervalMaksimum 5 detikPolling dimulai pada 0,25 detik dan melambat hingga nilai ini

Langkah 4: memecahkan satu batch tanpa membuat setiap challenge menjadi basi

Python adalah satu-satunya SDK yang klien async-nya merupakan implementasi terpisah: AsyncCapSkip di sini adalah asyncio yang sebenarnya. Pada paket Node.js dan .NET, nama itu hanyalah alias dari klien biasa, yang metodenya memang sudah asynchronous, dan PHP bersifat synchronous sepenuhnya.

Kendalanya bukan konkurensi, melainkan kesegaran. Mengambil seratus challenge lalu memecahkan semuanya adalah bentuk yang salah, karena yang paling awal sudah kedaluwarsa saat batch itu masih berjalan. Ambil dan pecahkan di dalam task yang sama, satu task per halaman, dan biarkan gather menangani fan-out-nya.

# 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())

Proof of work terikat CPU, jadi batas atasnya adalah jumlah core bukan jumlah koneksi terbuka, dan ada gunanya mengukur di mesin yang benar-benar Anda pakai daripada menebak. Pola umum untuk pemecahan massal, termasuk tipe yang menunggu sesi browser bukan hashing, ada di panduan memecahkan CAPTCHA secara paralel.

Contoh lengkap yang berfungsi

# 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")

Tipe lain memiliki bentuk yang sama dengan metode yang berbeda. Ada satu pemanggilan untuk reCAPTCHA v2, v3 dan Enterprise, satu untuk Turnstile, satu untuk GeeTest v3 dan satu untuk CAPTCHA gambar, dan daftar lengkapnya ada di halaman pemecah CAPTCHA Python.

Paket untuk Node.js, PHP dan .NET menyediakan nama metode yang sama. Setiap SDK CapSkip dijelaskan di halaman SDK.

Kesalahan umum dan artinya

Apa yang Anda lihatPenyebabPerbaiki
Kegagalan verifikasi biasa dari situs, pada token yang berhasil dipecahkan tanpa masalahChallenge kedaluwarsa sebelum form terkirimAmbil, pecahkan dan kirim di dalam satu fungsi
ERROR_CAPTCHA_UNSOLVABLE dalam ApiException setelah sepertiga detikChallenge meminta Argon2id atau scryptTidak ada yang perlu dicoba ulang. Keduanya ditolak dengan sengaja
ValidationException pada pemanggilanTidak ada parameter challenge yang diberikan, atau ada parameter yang tidak diterima ALTCHABerikan endpoint challenge atau dokumen challenge, dan buang sisanya
NetworkException sebelum hashing apa pun terjadiCapSkip tidak berjalan, atau host dan port-nya salahJalankan CapSkip, lalu periksa apakah ia harus berada di mode Local atau mode Server
KeyError pada key tokenHanya hasil ALTCHA yang membawa key ituPanggil metode altcha, atau baca key code, yang menyimpan string yang sama
Pemecahan pertama dalam satu batch gagal dan yang terakhir berhasilChallenge diambil di awal dan kedaluwarsa saat berada di antreanAmbil di dalam setiap task, bukan sebelum gather
Token yang selalu ditolak situsAda sesuatu yang memangkas atau mengodekan ulang payloadTeruskan string itu tanpa disentuh

FAQ

Apakah saya butuh Selenium atau Playwright untuk halaman ALTCHA?

Tidak untuk bagian ALTCHA-nya. Challenge itu adalah masalah hashing dan jawabannya adalah string yang Anda kirim di field form, jadi requests atau httpx sudah cukup dan pemecahannya selesai dalam hitungan milidetik. Anda tetap membutuhkan browser jika sisa halamannya memang memerlukannya, misalnya ketika cookie sesi disetel oleh JavaScript atau form dirender di sisi klien. Dalam kasus itu, pertahankan browser untuk navigasi dan panggil pemecah CAPTCHA secara langsung untuk mendapatkan token, daripada mencoba membuat widget-nya berjalan.

Bisakah skrip di platform hosting menjangkau pemecah CAPTCHA?

Bisa. Aktifkan mode Server di pengaturan koneksi agar CapSkip mendengarkan di alamat jaringan, bukan di loopback, lalu arahkan CAPSKIP_HOST ke alamat itu. Container Docker, VPS, pekerjaan terjadwal di platform terkelola dan CI runner semuanya terhubung dengan cara yang sama, melalui API HTTP yang sama. Jika rutenya melintasi internet, gunakan IP publik statis dan aturan firewall yang hanya mengizinkan alamat yang Anda harapkan. Pemecah CAPTCHA tetap berjalan di perangkat Anda dalam kedua kasus, jadi lisensi dan pemecahan tanpa batas tidak terpengaruh.

Mengapa ALTCHA jauh lebih cepat dipecahkan daripada reCAPTCHA?

Karena keduanya meminta hal yang berbeda. reCAPTCHA dan Turnstile menginginkan bukti bahwa ada browser dengan riwayat yang masuk akal, dan itu memerlukan sesi nyata dan waktu nyata. ALTCHA hanya menginginkan bukti bahwa sejumlah CPU telah dipakai, jadi pekerjaannya adalah loop hash dengan kondisi berhenti yang sudah diketahui. Itu juga sebabnya jawabannya bersifat deterministik dan bukan sebuah penilaian: ada satu angka yang memenuhi challenge, dan angka itu entah ditemukan atau challenge-nya rusak. Konsekuensinya, angka itu tidak berharga lagi satu atau dua menit kemudian.

Bisakah saya memakai ulang satu token di beberapa permintaan?

Tidak, dan alasannya layak dijelaskan secara gamblang. Payload itu ditandatangani terhadap satu challenge tertentu, challenge itu diterbitkan satu kali, dan server melacaknya, jadi pengiriman kedua dari token yang sama justru adalah replay yang ingin dicegah oleh desain ini. Pecahkan satu kali untuk setiap pengiriman. Itu terjangkau di sini dengan cara yang tidak mungkin pada layanan berbayar per pemecahan, karena pekerjaannya hanya beberapa milidetik CPU Anda sendiri dan bukan panggilan yang ditagih, jadi tidak ada alasan menyimpan cache untuk sesuatu yang bisa dihitung ulang dengan mudah.

Versi singkatnya

Baca endpoint challenge dari widget, berikan bersama URL halaman ke satu metode ALTCHA, dan kirim token ke field bernama altcha tanpa menyuntingnya. Jaga pengambilan, pemecahan dan pengiriman tetap bersama, karena sebuah challenge bisa mati dalam waktu kurang dari dua menit dan challenge yang kedaluwarsa dilaporkan sebagai kegagalan verifikasi biasa. Untuk satu batch, sebarkan pekerjaan dengan klien async dan ambil setiap challenge di dalam task-nya sendiri daripada mengumpulkannya lebih dulu. Harapkan ERROR_CAPTCHA_UNSOLVABLE hanya dari Argon2id dan scrypt.

Satu konsekuensi layak Anda masukkan ke dalam logika retry. Berjalan secara lokal, sebuah pemecah captcha melakukan hashing di mesin yang sudah Anda miliki, jadi pemecahan yang terbuang hanya memakan milidetik dan bukan kredit. Karena itu reaksi yang tepat terhadap challenge yang basi adalah mengambil yang baru dan mencoba lagi.