इमेज कैप्चा भेजते समय ERROR_UPLOAD कैसे ठीक करें

error_upload - How to Fix ERROR_UPLOAD When Sending an Image CAPTCHA

ERROR_UPLOAD का मतलब है कि सॉल्वर तक कोई इस्तेमाल लायक इमेज डेटा नहीं पहुंचा। रिक्वेस्ट खुद ठीक थी और API key भी ठीक थी, लेकिन जिस हिस्से में तस्वीर होनी चाहिए थी वह खाली पहुंचा, या कभी पहुंचा ही नहीं। यह उन चार कोड्स में से एक है जो अंदर आने के रास्ते में हो सकने वाली हर गड़बड़ी को कवर करते हैं, और इन्हें आपस में मिलाना आसान है क्योंकि आपकी तरफ से चारों बिल्कुल एक जैसे दिखते हैं। यह पोस्ट इन्हें अलग-अलग करती है, असली सीमाएं बताती है, और ऐसा अपलोड कोड दिखाती है जो इनमें से किसी में भी नहीं फंसता।

आपको क्या चाहिए

  • CapSkip चल रहा होना चाहिए, या तो Local mode में loopback एड्रेस पर या Server mode में किसी ऐसी मशीन पर जहां आपका कोड पहुंच सके। दोनों का विवरण कनेक्शन सेटिंग्स में मिलता है, और नीचे दी गई त्रुटियों के बारे में यह चुनाव कुछ भी नहीं बदलता।
  • Python 3.10 या उससे नया वर्जन जिसमें SDK इंस्टॉल हो, या अगर आप सीधे endpoint से बात करना चाहें तो curl।
  • डिस्क पर सेव की गई एक असली कैप्चा इमेज। पूरे पेज का स्क्रीनशॉट गलत टेस्ट केस है और आपको बग की बजाय साइज़ लिमिट के पीछे भगा देता है।

हर इमेज एरर कोड का मतलब क्या है

ये वे कोड हैं जो API इमेज सबमिशन के लिए लौटाता है, सीधे CapSkip API डॉक्यूमेंटेशन से। पहले अर्थ वाला कॉलम पढ़ें, क्योंकि इन्हें अलग करने वाली चीज़ यह है कि गड़बड़ी कहां हुई, न कि वह कितनी गंभीर थी।

कोडइसका क्या मतलब हैगड़बड़ी कहां है
ERROR_UPLOADकोई इमेज डेटा नहीं दिया गया, या अपलोड विफल रहारिक्वेस्ट बॉडी। इस्तेमाल लायक कुछ भी नहीं पहुंचा
ERROR_INVALID_IMAGEअमान्य इमेज फॉर्मेट, या करप्ट इमेज डेटाबाइट्स तो पहुंचे लेकिन इमेज के रूप में डिकोड नहीं होते
ERROR_INVALID_BASE64अमान्य base64 एन्कोडिंगस्ट्रिंग कभी वापस बाइट्स में नहीं बदल पाई
ERROR_TOO_BIG_CAPTCHA_FILESIZE600 kB से ज़्यादा, या किसी एक डायमेंशन में 1000px से ज़्यादाइमेज असली और वैध है, बस बहुत बड़ी है
ERROR_BAD_PARAMETERSआवश्यक पैरामीटर गायब या अमान्य हैंइमेज के आस-पास के फॉर्म फील्ड्स

एक पांचवीं गड़बड़ी भी है जो API तक पहुंचती ही नहीं। SDK को ऐसा पाथ दें जो मौजूद ही नहीं है, तो वह बिना कोई रिक्वेस्ट भेजे फाइल का नाम बताते हुए एक ValidationException उठाता है। यह फर्क शुरू में ही समझ लेना ज़रूरी है: एक Python एक्सेप्शन का मतलब है कि आपकी अपनी मशीन ने इसे रोका, और ERROR से शुरू होने वाला कोड का मतलब है कि सॉल्वर ने इसे रोका।

स्टेप 1: इमेज को उस रूप में भेजें जो API स्वीकार करता है

SDK तीन तरह के इनपुट लेता है और उन सबको एक ही सबमिशन में बदल देता है। एक लोकल पाथ, एक रिमोट URL, या इमेज को इनलाइन ले जाने वाला एक data URI।

# 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

रिलेटिव पाथ की बजाय एब्सोल्यूट पाथ इस्तेमाल करें। रिलेटिव पाथ प्रोसेस की working directory के हिसाब से resolve होता है, जो शायद ही कभी वह डायरेक्टरी होती है जहां आपने कोड लिखा था, और यही सबसे आम वजह है जिससे आपके एडिटर में चलने वाली स्क्रिप्ट किसी scheduler या service के तहत फेल हो जाती है।

raw HTTP API पर इमेज भेजने के दो तरीके हैं, और गलत फील्ड चुनना ही सबसे ज़्यादा ERROR_UPLOAD पैदा करता है। Multipart फाइल को खुद भेजता है, और base64 उसे एक स्ट्रिंग के रूप में भेजता है।

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

फील्ड नामों पर ध्यान दें। multipart तरीके में इमेज file नाम की फील्ड में जाती है, और base64 तरीके में यह body नाम की फील्ड में जाती है। फाइल को body फील्ड में भेजना, या curl को फाइल पढ़ने के लिए बताने वाला @ हटा देना, दोनों से ऐसा अपलोड बनता है जिसमें कोई इमेज होती ही नहीं।

स्टेप 2: ERROR_INVALID_BASE64 ठीक करें

base64 की गड़बड़ियां लगभग हमेशा लाइन रैपिंग की वजह से होती हैं। GNU coreutils डिफ़ॉल्ट रूप से अपने आउटपुट को 76 characters पर रैप कर देता है और वे newlines रिक्वेस्ट में भी बने रहते हैं, इसलिए शेल प्रॉम्प्ट पर एनकोड करते समय रैप चौड़ाई शून्य दें। एनकोडर इस मामले में एक जैसे नहीं हैं और कुछ तो रैप करते ही नहीं, यही वजह है कि प्रॉम्प्ट के बजाय कोड में एनकोड करना बेहतर है।

SDK और raw API के बीच स्विच करने वालों को एक और फर्क पकड़ में आता है। SDK पूरा data URI स्वीकार करता है, prefix सहित। raw endpoint पर body पैरामीटर सिर्फ़ base64 payload चाहता है, बिना किसी prefix के।

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

यह length जांच दिखने से कहीं ज़्यादा मायने रखती है। लगभग पचास characters से छोटी base64 स्ट्रिंग को इमेज डेटा की बजाय फाइल पाथ के रूप में पढ़ा जाता है, इसलिए एक truncated payload बैड base64 के रूप में फेल होता ही नहीं। यह मिसिंग फाइल के रूप में फेल होता है, जो आपको गलत जगह ढूंढने भेज देता है।

स्टेप 3: ERROR_TOO_BIG_CAPTCHA_FILESIZE ठीक करें

इसकी एक अस्पष्ट गाइडलाइन नहीं बल्कि प्रकाशित संख्याएं हैं। API 600 kB से बड़ी इमेज को रिजेक्ट करता है, और किसी भी डायमेंशन में 1000px से बड़ी इमेज को भी रिजेक्ट करता है। असली कैप्चा के लिए दोनों सीमाएं काफ़ी बड़ी हैं, इसलिए इनमें से किसी एक तक पहुंचने का आमतौर पर मतलब यही है कि widget की बजाय पूरे पेज का स्क्रीनशॉट भेजा गया।

कैप्चा तक क्रॉप करना बेहतर तरीका है, क्योंकि इससे एक्यूरेसी भी बेहतर होती है। जब आप भरोसे से क्रॉप नहीं कर सकते, तब डाउनस्केलिंग एक फॉलबैक है।

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

स्टेप 4: ERROR_INVALID_IMAGE ठीक करें

इस कोड का मतलब है कि बाइट्स पूरी तरह पहुंचे लेकिन वे इमेज नहीं हैं। व्यवहार में इसकी एक प्रमुख वजह होती है। आपने कैप्चा को किसी HTTP क्लाइंट से डाउनलोड किया, सर्वर ने एरर पेज या रीडायरेक्ट के साथ जवाब दिया, और आपके कोड ने बिना अंदर देखे रिस्पॉन्स बॉडी को .png में खत्म होने वाली फाइल में सेव कर दिया। फाइल असली है, साइज़ भी ठीक लगता है, और पहले चार बाइट्स 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))

यह जांच सॉल्व टाइम की बजाय डाउनलोड टाइम पर करें। चार बाइट पढ़ना मुफ़्त है, और यह एक उलझाने वाली सॉल्वर एरर को उसी जगह एक साफ़ नेटवर्क एरर में बदल देता है जहां नेटवर्क एरर असल में हुई थी।

पूरा चलने वाला उदाहरण

चारों फिक्स को एक साथ जोड़ने पर एक ऐसा फ़ंक्शन बनता है जो भेजने से पहले जांच करता है, और आपकी मशीन की उठाई गई एरर को सॉल्वर की लौटाई गई एरर से अलग रखता है।

# 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

पहले Pillow से इमेज खोलना चार में से दो कोड को एक लोकल एक्सेप्शन में समेट देता है, क्योंकि जो फाइल यहां नहीं खुल सकी वह वहां भी कभी डिकोड नहीं होती। इसके बाद जो API तक पहुंचता है वह एक जानी-पहचानी सही इमेज होती है, जानी-पहचानी सही साइज़ में।

एक चीज़ मत जोड़ें: प्रॉक्सी। प्रॉक्सी reCAPTCHA, Turnstile, GeeTest और CaptchaFox के लिए सपोर्टेड है, इमेज कैप्चा के लिए नहीं। एक प्रॉक्सी भेजना चुपचाप नज़रअंदाज़ नहीं होता बल्कि एक पैरामीटर एरर है, इसलिए यह कॉल को पूरी तरह फेल कर देता है।

सॉल्वर को उसकी जगह सर्वर पर चलाना

इमेज अपलोड ही वह इकलौता कैप्चा टाइप है जिसमें रिक्वेस्ट असली पेलोड ले जाती है, इसलिए यह जानना ज़रूरी है कि वह पेलोड कहां जा रहा है। CapSkip दो व्यवस्थाएं देता है:

मोडकिस पर सुनता हैकब इस्तेमाल करें
लोकल127.0.0.1, केवल उसी डिवाइस परआपकी स्क्रिप्ट और सॉल्वर एक ही मशीन पर चलते हैं
सर्वरआपका नेटवर्क पता या पब्लिक IPWorkers, कोई VPS या होस्टेड प्लेटफ़ॉर्म API के ज़रिए कॉल करते हैं

Server mode में आप SDK host को सॉल्वर मशीन पर पॉइंट करते हैं और आपके कोड में बाकी कुछ नहीं बदलता, इसलिए workers का एक pool एक ही instance शेयर कर सकता है। जब callers आपके अपने नेटवर्क के बाहर हों तो एक static public IP की सलाह दी जाती है। विवरण कनेक्शन सेटिंग्स में मिलता है, और Server mode फिर भी आपका ही हार्डवेयर है और फिर भी unmetered है: यह सिर्फ़ यह बदलता है कि सॉल्वर कहां चलता है, कभी यह नहीं कि उसका मालिक कौन है या यह बिल कैसे करता है।

FAQ

CapSkip कितनी बड़ी इमेज स्वीकार करता है?

600 kB, और किसी भी डायमेंशन में 1000px। इनमें से किसी एक को पार करने पर आपको आधा-अधूरा सॉल्व नहीं बल्कि ERROR_TOO_BIG_CAPTCHA_FILESIZE मिलता है। दोनों संख्याएं API reference पेज पर प्रकाशित हैं, और दोनों किसी भी असली कैप्चा इमेज से काफ़ी ऊपर हैं, इसलिए इन तक पहुंचने को इस संकेत के रूप में लें कि आप जितना भेजना चाहते थे उससे ज़्यादा पेज भेज रहे हैं।

एक ही इमेज लोकल पर काम क्यों करती है लेकिन मेरे सर्वर पर फेल हो जाती है?

आमतौर पर पाथ की वजह से, इमेज की वजह से नहीं। एक रिलेटिव पाथ उस working directory के हिसाब से resolve होता है जिसमें प्रोसेस शुरू हुई थी, और कोई service या scheduled task शायद ही कभी वहां शुरू होती है जहां आप सोचते हैं। एब्सोल्यूट पाथ इस्तेमाल करें, फिर जांचें कि जिस account के तहत प्रोसेस चलती है वह फाइल पढ़ सकता है। अगर सॉल्वर खुद किसी और मशीन पर है, तो पक्का करें कि host और port loopback की बजाय उसी की ओर पॉइंट करते हैं।

क्या मैं इमेज कैप्चा हल करते समय प्रॉक्सी इस्तेमाल कर सकता हूं?

नहीं। प्रॉक्सी सपोर्ट reCAPTCHA, Turnstile, GeeTest और CaptchaFox को कवर करता है, जो वे टाइप हैं जहां सॉल्वर खुद पेज लोड करता है। इमेज कैप्चा तो बाइट्स हैं जो पहले से आपके पास हैं, इसलिए प्रॉक्सी के करने के लिए कुछ है ही नहीं और यह पैरामीटर नज़रअंदाज़ होने की बजाय रिजेक्ट हो जाता है।

एक इमेज कैप्चा में कितना समय लगना चाहिए?

सामान्य स्थिति में एक सेकंड से काफ़ी कम। इमेज काम के लिए polling timeout डिफ़ॉल्ट रूप से 120 seconds है, जो एक उम्मीद की बजाय एक सुरक्षा जाल है, और SDK एक चौथाई सेकंड पर पोलिंग शुरू करता है और वहां से धीरे-धीरे बढ़ाता जाता है। अगर आप मिलीसेकंड की बजाय सेकंड इंतज़ार कर रहे हैं, तो दिलचस्प सवाल यह है कि सॉल्वर क्या कर रहा है, न कि आपका timeout काफ़ी लंबा है या नहीं।

सबसे छोटा जवाब

कुछ भी बदलने से पहले पता करें कि किस तरफ गड़बड़ी हुई। एक Python एक्सेप्शन का मतलब है कि इमेज कभी आपकी मशीन से बाहर नहीं गई, और ERROR से शुरू होने वाला कोड का मतलब है कि वह पहुंची और रिजेक्ट हुई। फिर कोड मिलाएं: कुछ भी न पहुंचना ERROR_UPLOAD है, पहुंचना लेकिन डिकोड न होना ERROR_INVALID_IMAGE है, स्ट्रिंग का डिकोड न होना ERROR_INVALID_BASE64 है, और बहुत बड़ा होने का मतलब है 600 kB से ज़्यादा या 1000px से ज़्यादा। डाउनलोड के समय बाइट्स की जांच करें और इनमें से ज़्यादातर होना बंद हो जाएंगी। साफ़ अपलोड के बाद फेल हुआ सॉल्व एक अलग समस्या है, जिसका ज़िक्र ERROR_CAPTCHA_UNSOLVABLE की गाइड में मिलता है। खुद पैरामीटर्स के लिए, इमेज कैप्चा सॉल्वर पेज ही रेफरेंस है, और Python से जुड़ी बारीकियां Python कैप्चा सॉल्वर पेज पर मिलती हैं। यहां अर्थशास्त्र भी मदद करता है: असीमित कैप्चा सॉल्वर की क्षमता का मतलब है कि आपके अपने हार्डवेयर पर एक खराब अपलोड के बाद रीट्राई में सिर्फ़ रीट्राई की ही लागत आती है।