Cara Memecahkan Capy Puzzle di Python, dari Key hingga Pengiriman Form

solve capy puzzle in python - How to Solve Capy Puzzle in Python, From Key to Form Post

Untuk memecahkan Capy Puzzle di Python, baca key PUZZLE_ milik situs dari halaman, panggil solver.capy() dari paket capskip dengan key tersebut dan URL halaman, lalu kirim tiga nilai yang dikembalikannya di field form capy_captchakey, capy_challengekey dan capy_answer, bersamaan dan secepatnya. Ambil halaman dan kirim form melalui session requests yang sama, agar cookie situs ikut terkirim bersama jawabannya. Bagian yang sering mengejutkan orang adalah bentuk hasilnya. Sebagian besar tipe CAPTCHA mengembalikan satu token; Capy mengembalikan tiga nilai yang hanya berfungsi sebagai satu set, dan salah satunya cepat kedaluwarsa. CapSkip menambahkan Capy Puzzle pada versi 1.4.0. Panduan ini membahas key, pemanggilan, jeda dua detik yang memang disengaja, pengiriman, percobaan ulang, dan menjalankan banyak pemecahan sekaligus.

Apa yang Anda butuhkan

  • CapSkip 1.4.0 atau lebih baru yang berjalan di komputer Windows. Dukungan Capy hadir pada rilis tersebut, bersama CaptchaFox dan Friendly Captcha.
  • Python 3.10 atau lebih baru dan paket capskip versi 1.3.0 atau lebih baru, rilis pertama yang memiliki metode capy(). Contoh kodenya juga memakai requests, dan bagian tentang pemecahan paralel memakai httpx.
  • Dua nilai dari halaman target: key Capy, yang diawali PUZZLE_, dan URL halaman tempat widget berjalan. Langkah 1 menunjukkan letak key tersebut, dan tempat yang sama memberi tahu Anda apakah Anda memerlukan nilai ketiga yang opsional.
  • 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, dan salah satu bagian di bawah membahas kapan Anda perlu beralih.
# Quoted, so cmd.exe does not read >= as a redirect
pip install "capskip>=1.3.0" requests httpx

Langkah 1: temukan key PUZZLE_ dan host Capy

Semua yang Anda butuhkan diambil dari halaman target, dan key-nya bersifat publik serta sama untuk setiap pengunjung. Situs menyimpannya di dua tempat. Parameter k pada URL script widget ada di HTML yang diunduh oleh requests. Setelah widget berjalan di browser, key itu juga ada di input tersembunyi capy_captchakey yang ditulis widget ke dalam form, dan di situlah DevTools menampilkannya. Satu regular expression untuk awalan PUZZLE_ menemukannya di kedua tempat itu.

import re

import requests

PAGE_URL = "https://example.com/login"
session = requests.Session()
html = session.get(PAGE_URL, timeout=30).text

# The widget script's k= parameter. The capy_captchakey input only
# exists once the widget has run in a browser.
key = re.search(r"PUZZLE_[A-Za-z0-9_-]+", html)

# The widget script's own host; None means the default one.
host = re.search(r"(https://[^\"'\s<>]+?)/puzzle/get_js/", html)
api_server = host.group(1) if host else None
print(key and key.group(0), api_server)

Selagi Anda melihat tag script itu, catat host-nya. Semua bagian URL script sebelum /puzzle/get_js/ adalah Capy API yang menaungi key tersebut, dan CapSkip menyebutnya api_server. Nilai default-nya https://jp.api.capy.me, tempat layanan aktifnya berjalan, jadi Anda hanya memerlukannya ketika sebuah halaman memuat widget dari tempat lain. Satu jebakan berasal dari dokumentasi pemecah CAPTCHA lain: beberapa di antaranya masih menampilkan api.capy.me tanpa awalan regional, dan host itu sudah tidak bisa di-resolve lagi. Jika contoh lama menyetelnya, hapus opsi tersebut.

Pengambilan halaman sengaja dilakukan melalui requests.Session. Form yang Anda kirim di Langkah 3 sering bergantung pada cookie sesi yang disetel halaman, dan objek session mengirimkannya kembali tanpa kode tambahan apa pun.

Langkah 2: pemanggilan capy()

Untuk memecahkan Capy Puzzle di Python, Anda cukup memakai satu metode. Metode ini menerima key dan URL halaman, ditambah argumen keyword opsional, dan untuk halaman di host default, 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.capy("PUZZLE_YOUR_KEY", "https://example.com/login")

print(result["captchakey"])     # goes in capy_captchakey
print(result["challengekey"])   # goes in capy_challengekey
print(result["answer"])         # goes in capy_answer

Hasilnya adalah dict biasa. Baca ketiga key bernama tersebut. Key code berisi seluruh objek jawaban dari server, sebuah dict dengan keempat field-nya, yang berguna untuk logging, dan respKey adalah string kosong yang hanya ada demi kompatibilitas dengan layanan lain. Jawabannya berupa string panjang yang awalnya kira-kira seperti 0xax8ex0xax84x: itu adalah jalur seretan yang akan direkam widget saat potongan puzzle digeser, bukan sebuah koordinat.

Opsi yang diterima metode ini

Metode capy() membuang argumen keyword apa pun yang bernilai None sebelum permintaan dikirim, jadi Anda bisa memberikan host dari Langkah 1 di setiap pemanggilan dan membiarkan regex yang menentukan apakah host itu ikut dikirim.

result = solver.capy(
    key.group(0),
    PAGE_URL,
    # None (no get_js script on the page) is dropped, and CapSkip
    # then uses its default host.
    api_server=api_server,
    # Poll every half second; see the next section for why.
    polling_interval=0.5,
)

Selain api_server, capy() menerima proxy, proxytype dan useragent, ditambah timeout dan polling_interval per panggilan dalam detik. User agent, jika Anda menyetelnya, dikirim pada satu-satunya permintaan yang dibuat CapSkip untuk mengambil puzzle, dan Anda akan jarang membutuhkannya. Ada juga opsi version, tetapi hanya puzzle yang diterima. Keluarga Capy yang lain, avatar, adalah challenge berbeda di balik endpoint yang berbeda, jadi SDK menolaknya dengan ValidationException alih-alih mengembalikan jawaban yang akan ditolak situs. Keyword yang tidak dikenal, key atau URL halaman yang kosong, atau tipe proxy selain HTTP, HTTPS, SOCKS5 atau SOCKS5H memicu exception yang sama sebelum apa pun dikirim.

Mengapa pemecahan Capy memakan waktu sekitar dua detik

Deteksinya sendiri cepat. CapSkip mengambil gambar puzzle, menemukan lubangnya dengan sedikit perhitungan piksel, lalu menyusun jalur seretan, tanpa melibatkan browser maupun model. Setelah itu ia menunggu, dengan sengaja.

Capy mengukur waktu antara puzzle diambil dan jawaban diterima, dan menolak apa pun yang tiba lebih cepat daripada waktu yang dibutuhkan seseorang untuk menyeret potongannya. Pengujian CapSkip sendiri terhadap Capy menempatkan batas bawah itu di sekitar satu detik, dan penolakannya membawa pesan yang sama dengan jawaban yang salah, sehingga pemecahan yang benar tetapi dikirim terlalu cepat terlihat persis seperti pemecah yang rusak. Karena itu CapSkip menahan setiap hasil Capy sampai dua detik setelah ia mengambil puzzle. Penantian ini berupa sleep, jadi yang dikorbankan hanya latensi, bukan CPU.

Mengapa sebuah pemanggilan memakan waktu mendekati empat detik dengan pengaturan default: SDK melakukan polling segera setelah mengirim tugas ke CapSkip, lalu sekali lagi setelah seperempat detik, dan terus menggandakan jaraknya hingga pollingInterval, yaitu 5 detik secara default. Polling terjadi pada 0, 0.25, 0.75, 1.75 dan 3.75 detik, sehingga jawaban yang siap pada detik kedua baru diambil pada polling kelima. Dengan polling_interval=0.5 pada pemanggilan, atau pollingInterval=0.5 di konstruktor jika sebagian besar yang dipecahkan klien adalah Capy, pemanggilan kembali sedikit lebih dari dua detik setelah tugas dikirim, sekitar 2.3 detik dalam pengujian kami. Jangan menambahkan penundaan sendiri sebelum Anda mengirim form, dan jangan mencoba memangkas jedanya: jeda itulah yang membuat jawabannya lolos.

Langkah 3: kirim ketiga nilai dalam satu permintaan

Ketiga nilai itu masuk ke field yang akan ditulis sendiri oleh widget ke dalam form. Kirim ketiganya bersamaan, dalam permintaan yang sama dengan isi form lainnya, melalui session yang mengambil halaman tersebut.

# session is the one Step 1 used, so the page's cookies go back too.
resp = session.post(
    PAGE_URL,  # or wherever the form's action attribute points
    data={
        "username": "YOUR_USERNAME",
        "capy_captchakey": result["captchakey"],
        "capy_challengekey": result["challengekey"],
        "capy_answer": result["answer"],
    },
    timeout=30,
)
print(resp.status_code)

Kirim jawaban persis seperti yang dikembalikan. Backend situs memeriksanya terhadap puzzle yang diambil, jadi memotongnya, menyusunnya ulang, atau merapikannya dengan cara apa pun akan membuatnya tidak valid. Library requests melakukan percent-encoding pada body form, dan itu tidak masalah, karena server men-decode-nya sebelum memeriksa. Lalu kirim secepatnya. CapSkip membuat challenge key baru untuk setiap pemecahan dan puzzle terikat padanya, jadi key tersebut hanya sekali pakai dan berumur pendek, dan satu pemecahan hanya untuk satu pengiriman.

Tiru apa yang dikirim form aslinya. Sebagian besar halaman membawa field tersembunyi sendiri, seperti token anti-forgery, dan sebagian mengirim lewat script dengan body JSON, bukan form post. Kirim sekali secara manual dengan DevTools terbuka, salin permintaannya, lalu taruh ketiga nilai Capy di tempat halaman itu menaruhnya.

Langkah 4: percobaan ulang saat pemecahan gagal

Saat Anda memecahkan Capy Puzzle di Python dalam volume berapa pun, beberapa pemecahan akan gagal. Pemecahan yang gagal datang sebagai ApiException yang pesannya berisi ERROR_CAPTCHA_UNSOLVABLE, dan lewat res.php, endpoint yang di-polling SDK, satu kode itu mencakup dua situasi yang berbeda. Yang membedakan keduanya adalah seberapa sering terjadi.

Apa yang terjadiGejalanyaApa yang harus dilakukan
CapSkip tidak menemukan lubangnyaSesekali, dan percobaan berikutnya biasanya berhasilCoba ulang. Setiap percobaan memunculkan puzzle baru di atas foto yang berbeda
Capy API menolak key tersebutSetiap percobaan, untuk satu key itu, dan daftar tugas Capy di CapSkip menampilkan Invalid captcha keyPeriksa key dan api_server. CapSkip tidak pernah mencoba ulang key yang ditolak, karena key itu akan ditolak dengan cara yang sama

Pemecahan yang meleset jarang terjadi, jadi satu kali percobaan ulang sudah mencakup hampir semuanya. Setel Retries di bagian Capy pada pengaturan CapSkip, yang bernilai 0 secara default dan mengizinkan hingga tiga kali per tugas, atau coba ulang di kode Anda sendiri:

from capskip import ApiException


def solve_capy(key, url, attempts=3, **options):
    for attempt in range(1, attempts + 1):
        try:
            return solver.capy(key, url, **options)
        except ApiException as exc:
            # A missed hole reads as unsolvable, and the next try
            # draws a new puzzle. Anything else is final.
            if "UNSOLVABLE" not in str(exc) or attempt == attempts:
                raise

Metode capy() melakukan polling dengan defaultTimeout milik klien, 120 detik, karena pemecahan Capy hanyalah satu pengambilan dan sedikit aritmetika, bukan sesi browser. CapSkip juga menjalankan hitungan waktunya sendiri: di bagian Capy, sebuah tugas bisa menunggu hingga 250 detik (Wait Timeout) untuk mendapatkan salah satu dari 10 thread (Max. Threads), dan satu percobaan mendapat 60 detik (Row Timeout). Pemecahan normal muat di dalam semua batas itu berkali-kali lipat.

Memecahkan banyak puzzle Capy sekaligus

AsyncCapSkip adalah klien asyncio sungguhan di Python, bukan sekadar alias, jadi asyncio.gather menjalankan beberapa pemecahan secara berdampingan. Pasangkan setiap pemecahan dengan pengirimannya sendiri. Mengumpulkan seratus pemecahan lebih dulu lalu mengirim belakangan membuat challenge key yang paling awal menua selagi pemecahan terakhir selesai.

import asyncio

import httpx
from capskip import AsyncCapSkip

solver = AsyncCapSkip(host="127.0.0.1", port=8080, pollingInterval=0.5)
slots = asyncio.Semaphore(10)  # CapSkip's Capy Max. Threads


async def solve_and_submit(key, url, form):
    # One client per job, so each form session keeps its own cookies.
    async with slots, httpx.AsyncClient(
            timeout=30, follow_redirects=True) as client:
        await client.get(url)
        result = await solver.capy(key, url)
        return await client.post(url, data={
            **form,
            "capy_captchakey": result["captchakey"],
            "capy_challengekey": result["challengekey"],
            "capy_answer": result["answer"],
        })


async def main(jobs):
    return await asyncio.gather(
        *(solve_and_submit(*job) for job in jobs), return_exceptions=True)

Semaphore ini disesuaikan dengan jumlah thread CapSkip, sehingga tidak ada tugas yang menunggu di antrean CapSkip sambil menahan sesi tetap terbuka. Semaphore ini berasal dari library standar Python dan didokumentasikan di bagian asyncio.Semaphore. Pada volume besar, tambahkan juga proxy. Setiap pemecahan mengambil puzzle baru dari Capy API, dan aliran permintaan seperti itu dari satu alamat persis pola yang ingin ditangkap oleh rate limiting. Konfigurasikan pool proxy di bagian Capy pada CapSkip, atau berikan dict proxy berisi type dan uri di setiap pemanggilan; proxy hanya menyentuh pengambilan puzzle, satu-satunya permintaan yang dibuat oleh pemecahan Capy. Pola asyncio lainnya 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 (ApiException, CapSkip, CapSkipError,
                     TimeoutException, ValidationException)

PAGE_URL = "https://example.com/login"

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")),
    # Capy answers after a two second hold; poll often enough to catch it.
    pollingInterval=0.5,
)
session = requests.Session()

html = session.get(PAGE_URL, timeout=30).text
key = re.search(r"PUZZLE_[A-Za-z0-9_-]+", html)
if not key:
    raise SystemExit("No PUZZLE_ key in the HTML; find it in DevTools.")
host = re.search(r"(https://[^\"'\s<>]+?)/puzzle/get_js/", html)

try:
    for attempt in range(1, 4):
        try:
            result = solver.capy(key.group(0), PAGE_URL,
                                 api_server=host.group(1) if host else None)
            break
        except ApiException as exc:
            # A missed hole reads as unsolvable; the next try draws a new puzzle.
            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; defaultTimeout is 120 seconds")
except CapSkipError as exc:
    # A third miss, a refused key, or CapSkip unreachable.
    raise SystemExit(f"solve failed: {exc!r}")

# All three together, straight away: the challenge key is single-use.
resp = session.post(
    PAGE_URL,  # or wherever the form's action attribute points
    data={
        "username": "YOUR_USERNAME",
        "capy_captchakey": result["captchakey"],
        "capy_challengekey": result["challengekey"],
        "capy_answer": result["answer"],
    },
    timeout=30,
)
print(resp.status_code)

Jika ketiga percobaan gagal, periksa key sebelum hal lain, karena key yang ditolak gagal dengan cara yang sama setiap kali, sedangkan pemecahan yang meleset hampir tidak pernah terjadi tiga kali berturut-turut. Ketika halaman membangun widget dari script yang di-bundle dan regex tidak menemukan apa pun, buka tab Network lalu salin key dan host dari permintaan milik widget itu sendiri. Endpoint mentah di balik metode ini didokumentasikan di bagian Capy pada referensi API.

Kesalahan umum dan artinya

Apa yang Anda lihatPenyebabPerbaiki
Situs menolak pengiriman padahal capy() mengembalikan ketiga nilaiJawaban diubah, atau hanya satu atau dua nilai yang sampai ke formKirim result["answer"] apa adanya, bersama dua nilai lainnya, dalam satu permintaan
Situs menolak pengiriman dan menyatakan sesi telah kedaluwarsaHalaman diambil dengan requests.get() dan form dikirim dengan permintaan baru, sehingga cookie halaman tidak pernah ikut terkirim kembaliAmbil halaman dan kirim form melalui satu requests.Session
Pengiriman yang berhasil sekali gagal pada percobaan keduaChallenge key hanya sekali pakai dan berumur pendekPecahkan ulang untuk setiap pengiriman, dan langsung kirim
ApiException pada setiap percobaan, untuk satu keyCapy API menolak key tersebut, atau api_server menunjuk ke host yang salahSalin ulang key, termasuk awalannya, dan periksa host pada tag script
ApiException sesekali yang berisi ERROR_CAPTCHA_UNSOLVABLECapSkip tidak dapat menemukan lubang pada puzzle ituCoba ulang; percobaan berikutnya memunculkan puzzle yang berbeda
Setiap pemecahan gagal setelah Anda menyalin contoh dari layanan lainContoh itu menyetel api_server ke api.capy.me, yang sudah tidak bisa di-resolveHapus opsi itu dan pakai host default
ValidationException sebelum apa pun terkirimKey atau URL halaman kosong, avatar sebagai version, tipe proxy selain HTTP, HTTPS, SOCKS5 atau SOCKS5H, atau keyword yang tidak diterima metode iniPastikan key bukan string kosong, lalu perbaiki atau buang argumen yang disebut dalam pesan
ApiException dengan ERROR_WRONG_USER_KEY atau ERROR_KEY_DOES_NOT_EXISTValidasi API key aktif di CapSkip, dan skrip mengirim key default atau tidak mengirim key sama sekaliSetel CAPSKIP_API_KEY ke key yang dikonfigurasi di CapSkip
TimeoutException di bawah beban paralel yang beratTugas yang mengantre lebih banyak daripada yang bisa diselesaikan 10 thread dalam 120 detik, atau CapSkip dimulai ulang di tengah pemecahanBatasi konkurensi dengan semaphore, atau naikkan defaultTimeout
NetworkException pada pemanggilan pertamaCapSkip tidak berjalan, atau host dan port-nya salahJalankan CapSkip, lalu periksa apakah ia harus berada di mode Local atau mode Server

FAQ

Mengapa capy() mengembalikan tiga nilai, bukan satu token?

Karena itulah yang dikirim form Capy. Tidak ada server yang menerbitkan token pada titik mana pun. Widget itu sendiri membuat challenge key, mengambil puzzle yang menjadi pasangannya, dan merekam seretan, lalu situs mengirim challenge key dan jawaban ke Capy dengan private key miliknya untuk diperiksa. CapSkip memerankan widget, jadi ia mengembalikan apa yang akan ditulis widget ke dalam form.

Apakah user agent python-requests membuat jawaban ditolak?

Tidak oleh Capy. Jawaban Capy tidak terikat pada browser, CapSkip tidak mengembalikan user agent untuknya, dan user agent opsional yang bisa Anda berikan hanya mengubah permintaan yang mengambil puzzle. Situsnya sendiri mungkin tetap menolak permintaan yang memperkenalkan diri sebagai python-requests, dengan alasannya sendiri. Jika begitu, setel User-Agent browser pada session sekali saja, maka setiap permintaan darinya, termasuk pengiriman form, membawa header itu.

Bisakah saya memakai jawabannya di sesi Selenium atau Playwright?

Bisa. Pecahkan dengan URL halaman yang sedang dibuka browser, lalu tulis ketiga nilai ke input tersembunyi capy_captchakey, capy_challengekey dan capy_answer milik form dengan skrip singkat, sambil menambahkan input yang belum dibuat oleh widget, lalu kirim form seperti yang biasa dilakukan halaman itu. Jangan menyeret potongan puzzle di browser juga, karena itu akan menghasilkan jawaban kedua yang berbeda. Jika browser hanya dipakai untuk melewati puzzle, jalur requests di atas lebih sederhana dan lebih cepat.

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, host container, runner CI, dan notebook terkelola 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. Alur yang sama untuk .NET dibahas di panduan Capy Puzzle untuk C#.

Versi singkatnya

Untuk memecahkan Capy Puzzle di Python, ambil halaman dengan session requests, tarik key PUZZLE_ dengan satu regex, dan catat host script widget kalau-kalau bukan host default. Panggil solver.capy() dengan key dan URL halaman yang sebenarnya, lalu biarkan ia memakan beberapa detiknya, sekitar 2.3 detik dengan polling_interval=0.5. Kirim captchakey, challengekey dan answer di ketiga field capy_, apa adanya, bersamaan dan seketika, melalui session yang sama. Coba ulang pemecahan yang sesekali meleset, tambahkan proxy seiring volume bertambah, dan beralihlah ke mode Server begitu skrip tidak lagi berada di mesin pemecah CAPTCHA.

Satu hal terakhir tentang percobaan ulang itu. Setiap percobaan memunculkan puzzle yang berbeda, jadi mencoba lagi adalah solusi yang tepat untuk pemecahan yang meleset, dan dengan pemecah captcha tanpa batas di mesin Anda sendiri, percobaan kedua hanya memakan beberapa detik, bukan satu pemecahan berbayar lagi.