Cara Memperbaiki ERROR_UPLOAD Saat Mengirim CAPTCHA Gambar

error_upload - How to Fix ERROR_UPLOAD When Sending an Image CAPTCHA

ERROR_UPLOAD berarti tidak ada data gambar yang bisa dipakai yang sampai ke solver. Permintaannya sendiri baik-baik saja dan API key-nya juga baik-baik saja, tetapi bagian yang seharusnya membawa gambar tersebut tiba dalam keadaan kosong, atau tidak tiba sama sekali. Ini salah satu dari empat kode yang mencakup semua hal yang bisa salah dalam perjalanan masuk, dan keempatnya mudah tertukar karena semuanya terlihat sama dari sisi Anda. Artikel ini memisahkan keempatnya, memberikan batas yang sebenarnya, dan menunjukkan kode unggah yang tidak memicu satu pun di antaranya.

Apa yang Anda butuhkan

  • CapSkip yang berjalan, baik dalam Mode Local pada alamat loopback maupun dalam Mode Server pada mesin yang bisa dijangkau kode Anda. Keduanya dijelaskan di pengaturan koneksi, dan pilihan tersebut tidak mengubah apa pun tentang error di bawah ini.
  • Python 3.10 atau yang lebih baru dengan SDK yang sudah terpasang, atau curl jika Anda lebih suka mengakses endpoint secara langsung.
  • Satu gambar CAPTCHA asli yang disimpan ke disk. Screenshot dari seluruh halaman adalah kasus uji yang keliru dan membuat Anda mengejar batas ukuran alih-alih bug yang sebenarnya.

Arti setiap kode error gambar

Ini adalah kode-kode yang dikembalikan API untuk pengiriman gambar, langsung dari dokumentasi API CapSkip. Baca dulu kolom arti, karena yang membedakan setiap kode adalah di mana kegagalan itu terjadi, bukan seberapa parah kegagalannya.

KodeApa artinyaLetak masalah
ERROR_UPLOADTidak ada data gambar yang diberikan, atau unggahan gagalIsi permintaan. Tidak ada yang bisa dipakai yang sampai
ERROR_INVALID_IMAGEFormat gambar tidak valid, atau data gambar rusakByte-nya sampai tetapi tidak bisa didekode sebagai gambar
ERROR_INVALID_BASE64Encoding base64 tidak validString-nya tidak pernah berhasil diubah kembali menjadi byte
ERROR_TOO_BIG_CAPTCHA_FILESIZELebih dari 600 kB, atau lebih dari 1000px pada salah satu dimensiGambarnya asli dan valid, hanya saja terlalu besar
ERROR_BAD_PARAMETERSParameter wajib hilang atau tidak validField formulir di sekitar gambar

Ada kegagalan kelima yang bahkan tidak pernah sampai ke API. Berikan SDK sebuah path yang tidak ada, dan ia akan memunculkan ValidationException yang menyebutkan nama file tersebut, tanpa pernah mengirim permintaan. Perbedaan ini layak dipahami sejak awal: exception Python berarti mesin Anda sendiri yang menghentikannya, dan kode yang diawali ERROR berarti solver yang menghentikannya.

Langkah 1: kirim gambar dalam bentuk yang diterima API

SDK menerima tiga bentuk input dan mengubah semuanya menjadi pengiriman yang sama. Path lokal, URL jarak jauh, atau data URI yang membawa gambar secara inline.

# pip install capskip
from capskip import CapSkip

solver = CapSkip(host="127.0.0.1", port=8080)

# All three of these are accepted by the same method.
result = solver.normal("captcha.png")
result = solver.normal("https://example.com/captcha.jpg")
result = solver.normal("data:image/png;base64,iVBORw0KGgo...")

print(result["code"])   # the recognized text

Gunakan path absolut, bukan path relatif. Path relatif diselesaikan berdasarkan working directory proses, yang jarang sama dengan direktori tempat Anda menulis kode, dan inilah alasan paling umum mengapa skrip yang berjalan lancar di editor Anda gagal saat dijalankan lewat scheduler atau layanan.

Pada API HTTP mentah ada dua cara membawa gambar, dan memilih field yang salah adalah penyebab paling umum munculnya ERROR_UPLOAD. Multipart mengirim file itu sendiri, dan base64 mengirimnya sebagai string.

# no install needed, curl only
# method=post carries the file as multipart/form-data
curl -X POST "http://127.0.0.1:8080/in.php" \
  -F "key=capskip" \
  -F "method=post" \
  -F "[email protected]"

# method=base64 carries the same image as a string
curl -X POST "http://127.0.0.1:8080/in.php" \
  -d "key=capskip" \
  -d "method=base64" \
  --data-urlencode "body=BASE64_STRING_HERE"

Perhatikan nama field-nya. Dengan metode multipart, gambar masuk ke field bernama file, dan dengan metode base64, gambar masuk ke field bernama body. Mengirim file ke field body, atau menghilangkan tanda @ yang memberi tahu curl untuk membaca file alih-alih mengirim namanya sebagai teks literal, keduanya menghasilkan unggahan tanpa gambar di dalamnya.

Langkah 2: perbaiki ERROR_INVALID_BASE64

Kegagalan base64 hampir selalu disebabkan oleh line wrapping. GNU coreutils membungkus outputnya pada 76 karakter secara default, dan newline tersebut ikut terbawa ke dalam permintaan, jadi berikan lebar wrapping nol saat Anda melakukan encoding di shell prompt. Setiap encoder berbeda soal ini dan sebagian tidak membungkus sama sekali, itulah alasan untuk melakukan encoding di dalam kode, bukan di prompt.

Ada satu perbedaan lagi yang sering membuat orang keliru saat berpindah antara SDK dan API mentah. SDK menerima data URI lengkap, termasuk prefix-nya. Parameter body pada endpoint mentah menginginkan payload base64 itu sendiri, tanpa prefix di depannya.

# pip install capskip
import base64

with open("captcha.png", "rb") as fh:
    raw = base64.b64encode(fh.read()).decode()

# One continuous string. No newlines, no spaces, no truncation.
assert "\n" not in raw and len(raw) > 50

# The SDK wants the prefix, the raw body parameter does not.
result = solver.normal("data:image/png;base64," + raw)

Pemeriksaan panjang ini lebih penting daripada kelihatannya. String base64 yang lebih pendek dari sekitar lima puluh karakter dibaca sebagai path file, bukan sebagai data gambar, sehingga payload yang terpotong sama sekali tidak gagal sebagai base64 yang buruk. Ia gagal sebagai file yang tidak ditemukan, yang membuat Anda mencari di tempat yang salah.

Langkah 3: perbaiki ERROR_TOO_BIG_CAPTCHA_FILESIZE

Kode ini punya angka yang sudah dipublikasikan, bukan sekadar panduan yang samar. API menolak gambar di atas 600 kB, dan menolak gambar di atas 1000px pada salah satu dimensinya. Kedua batas ini sudah cukup longgar untuk CAPTCHA yang sebenarnya, jadi jika Anda sampai melewatinya, itu biasanya berarti screenshot seluruh halaman yang terkirim, bukan widget-nya saja.

Melakukan crop tepat ke CAPTCHA adalah perbaikan yang lebih baik, karena sekaligus meningkatkan akurasi. Downscaling adalah solusi cadangan untuk saat Anda tidak bisa melakukan crop secara andal.

# pip install capskip pillow
from PIL import Image

img = Image.open("captcha.png")

# Bring the longest side under the documented 1000px ceiling.
if max(img.size) > 1000:
    img.thumbnail((1000, 1000))

# optimize=True usually clears the 600 kB limit on its own.
img.save("captcha-ready.png", optimize=True)

Langkah 4: perbaiki ERROR_INVALID_IMAGE

Kode ini berarti byte-nya sampai dengan utuh tetapi bukan gambar. Dalam praktiknya, ada satu penyebab yang paling dominan. Anda mengunduh CAPTCHA dengan HTTP client, server merespons dengan halaman error atau redirect, dan kode Anda menyimpan isi respons tersebut ke file yang berakhiran .png tanpa pernah memeriksa isinya. File-nya nyata, ukurannya masuk akal, dan empat byte pertamanya adalah HTML.

# no install needed, standard library only
SIGNATURES = (b"\x89PNG", b"\xff\xd8\xff", b"GIF8", b"RIFF")

with open("captcha.png", "rb") as fh:
    head = fh.read(4)

# An error page saved as .png starts with <!DO or <htm instead.
print(any(head.startswith(sig) for sig in SIGNATURES))

Jalankan pemeriksaan itu saat mengunduh, bukan saat memecahkan. Membaca empat byte tidak memakan biaya apa pun, dan itu mengubah error solver yang membingungkan menjadi error jaringan yang jelas, tepat di titik ketika error jaringan itu sebenarnya terjadi.

Contoh lengkap yang berfungsi

Menggabungkan keempat perbaikan ini menghasilkan sebuah fungsi yang memvalidasi sebelum mengirim, dan menjaga agar error yang dimunculkan mesin Anda tetap terpisah dari error yang dikembalikan solver.

# pip install capskip pillow
from PIL import Image
from capskip import CapSkip, ApiException, ValidationException

solver = CapSkip(host="127.0.0.1", port=8080, defaultTimeout=120)

def solve_image(path):
    """Return the CAPTCHA text, or None with a reason printed."""
    img = Image.open(path)          # raises if it is not an image
    if max(img.size) > 1000:
        img.thumbnail((1000, 1000))
        img.save(path, optimize=True)

    try:
        return solver.normal(path)["code"]
    except ValidationException as exc:
        print("never left this machine:", exc)
    except ApiException as exc:
        print("the solver rejected it:", exc)
    return None

Membuka gambar dengan Pillow terlebih dahulu menyatukan dua dari empat kode tersebut menjadi satu exception lokal, karena file yang tidak bisa dibuka di sini juga tidak akan pernah bisa didekode di sana. Yang sampai ke API setelahnya adalah gambar yang sudah dipastikan baik pada ukuran yang sudah dipastikan baik pula.

Satu hal yang jangan ditambahkan: proxy. Proxy didukung untuk reCAPTCHA, Turnstile, GeeTest, dan CaptchaFox, tetapi tidak untuk CAPTCHA gambar. Mengirimkannya akan menghasilkan error parameter, bukan diabaikan diam-diam, sehingga langsung menggagalkan panggilan tersebut.

Menjalankan pemecah di server saja

Unggahan gambar adalah satu-satunya tipe CAPTCHA di mana permintaan membawa payload sungguhan, jadi penting untuk tahu ke mana payload itu pergi. CapSkip menawarkan dua susunan:

ModeMendengarkan diGunakan saat
Lokal127.0.0.1, hanya perangkat ituSkrip Anda dan solver berjalan pada satu mesin
ServerAlamat jaringan atau IP publik AndaWorkers, VPS, atau platform hosted yang memanggil lewat API

Dalam Mode Server, Anda mengarahkan host SDK ke mesin solver dan tidak ada bagian lain dari kode Anda yang berubah, sehingga sekumpulan worker bisa berbagi satu instance. IP publik statis disarankan ketika pemanggil berada di luar jaringan Anda sendiri. Detailnya ada di pengaturan koneksi, dan Mode Server tetap berjalan di perangkat keras Anda sendiri dan tetap tanpa biaya per pemakaian: yang berpindah hanya lokasi tempat solver berjalan, bukan siapa pemiliknya atau bagaimana penagihannya.

FAQ

Berapa ukuran gambar maksimum yang diterima CapSkip?

600 kB, dan 1000px pada salah satu dimensi. Lewati salah satunya saja, dan Anda akan mendapatkan ERROR_TOO_BIG_CAPTCHA_FILESIZE, bukan pemecahan sebagian. Kedua angka ini dipublikasikan di halaman referensi API, dan keduanya jauh di atas ukuran gambar CAPTCHA yang sebenarnya, jadi anggap saja jika Anda sampai melewatinya sebagai tanda bahwa Anda mengirim lebih banyak bagian halaman daripada yang seharusnya.

Mengapa gambar yang sama berhasil secara lokal tetapi gagal di server saya?

Biasanya path-nya, bukan gambarnya. Path relatif diselesaikan berdasarkan working directory tempat proses tersebut dijalankan, dan layanan atau scheduled task jarang dimulai dari tempat yang Anda kira. Gunakan path absolut, lalu periksa apakah file tersebut bisa dibaca oleh akun yang menjalankan proses itu. Jika solvernya sendiri berada di mesin lain, pastikan host dan port-nya mengarah ke sana, bukan ke loopback.

Bisakah saya menggunakan proxy saat memecahkan CAPTCHA gambar?

Tidak. Dukungan proxy mencakup reCAPTCHA, Turnstile, GeeTest, dan CaptchaFox, yaitu tipe-tipe di mana solver memuat halamannya sendiri. CAPTCHA gambar adalah byte yang sudah Anda miliki, jadi tidak ada yang perlu dilakukan proxy, dan parameternya akan ditolak, bukan diabaikan.

Berapa lama waktu yang dibutuhkan untuk memecahkan CAPTCHA gambar?

Jauh di bawah satu detik dalam operasi normal. Timeout polling untuk pekerjaan gambar secara default adalah 120 detik, yang berfungsi sebagai jaring pengaman, bukan sebagai ekspektasi, dan SDK mulai melakukan polling pada seperempat detik lalu memperlambatnya secara bertahap dari sana. Jika Anda menunggu dalam hitungan detik, bukan milidetik, pertanyaan yang lebih menarik adalah apa yang sedang dilakukan solver, bukan apakah timeout Anda sudah cukup panjang.

Versi paling singkatnya

Cari tahu dulu sisi mana yang gagal sebelum mengubah apa pun. Exception Python berarti gambar tidak pernah meninggalkan mesin Anda, dan kode yang diawali ERROR berarti gambar tersebut sampai tetapi ditolak. Lalu cocokkan kodenya: tidak ada yang sampai adalah ERROR_UPLOAD, sampai tetapi tidak bisa didekode adalah ERROR_INVALID_IMAGE, string yang tidak bisa didekode adalah ERROR_INVALID_BASE64, dan terlalu besar berarti melewati 600 kB atau melewati 1000px. Validasi byte-nya saat mengunduh, dan sebagian besar masalah ini akan berhenti terjadi. Pemecahan yang gagal setelah unggahan yang bersih adalah masalah lain, yang dibahas di panduan ERROR_CAPTCHA_UNSOLVABLE. Untuk parameternya sendiri, halaman pemecah CAPTCHA gambar adalah referensinya, dan detail khusus Python ada di halaman pemecah CAPTCHA Python. Dari sisi ekonomi juga membantu di sini: kapasitas pemecah captcha tanpa batas pada perangkat keras milik Anda sendiri berarti percobaan ulang setelah unggahan yang gagal tidak memakan biaya apa pun selain percobaan itu sendiri.