RQ जॉब में 180 सेकंड की सीमा से आगे कैप्चा कैसे हल करें

rq captcha - How to Solve CAPTCHAs in RQ Jobs Past the 180-Second Limit

RQ में, जो Redis पर बनी Python जॉब क्यू है, कैप्चा हल करने के लिए पूरा क्रम एक ही जॉब में रखें: पेज लाएँ, CapSkip से कैप्चा हल करें, फॉर्म पोस्ट करें। तब RQ कैप्चा जॉब में सिर्फ़ एक सेटिंग बदलनी पड़ती है, उसका टाइमआउट। जब तक आप कुछ और न कहें, RQ हर जॉब को 180 सेकंड देता है। CapSkip SDK किसी reCAPTCHA टोकन के लिए 300 सेकंड तक इंतज़ार करता है, इसलिए जो हल व्यस्त थ्रेड के पीछे क्यू में खड़ा होता है, वह पोलिंग के बीच में ही खत्म कर दिया जाता है। RQ एक JobTimeoutException दर्ज करता है, और CapSkip वह हल पूरा तो करता है, पर उसे लेने वाला कोई नहीं होता। यह गाइड जॉब, टाइमआउट, वर्कर, रीट्राई और यह कवर करती है कि वर्कर कहाँ चल सकता है, Windows समेत।

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

  • किसी Windows मशीन पर चल रहा CapSkip। सैंपल reCAPTCHA v2 हल करते हैं, और जॉब का यही ढाँचा उन सभी टाइप के लिए काम करता है जिन्हें CapSkip सपोर्ट करता है।
  • RQ 2.x, capskip पैकेज और requests के साथ Python 3.10 या उसके बाद का संस्करण। सैंपल RQ 2.12 पर चलाए गए थे।
  • Redis सर्वर, वर्ज़न 5 या उसके बाद का, जिस तक जॉब को क्यू में डालने वाला कोड और वर्कर, दोनों पहुँच सकें। RQ, Valkey 7.2 या उसके बाद का संस्करण भी स्वीकार करता है।
  • वर्कर के लिए एक मशीन। RQ का डिफ़ॉल्ट वर्कर एक ऐसी Unix कॉल पर निर्भर है जो Windows में नहीं है, इसलिए नीचे का एक सेक्शन Windows पर, WSL के तहत और किसी दूसरी मशीन पर मौजूद विकल्प कवर करता है।
  • सॉल्वर के लिए एक पता। Local मोड में CapSkip केवल उसी डिवाइस के लिए 127.0.0.1 पर जवाब देता है। Server मोड में वह आपके नेटवर्क पते या पब्लिक IP पर सुनता है, ताकि किसी दूसरी मशीन पर चल रहा वर्कर API के ज़रिए उसे कॉल कर सके। दोनों यहाँ सेट किए जाते हैं: कनेक्शन सेटिंग्स.
pip install rq capskip requests

चरण 1: जॉब को उसके अपने मॉड्यूल में लिखें

RQ किसी जॉब को एक function के import path और उसके arguments के रूप में सहेजता है, और वर्कर जॉब उठाते समय उस function को import करता है। जो function उसी script में परिभाषित है जो उसे क्यू में डालती है, वह __main__ में रहता है, जिसे वर्कर import नहीं कर सकता, इसलिए RQ क्यू में डालते समय ही ValueError के साथ उसे मना कर देता है। जॉब को उसके अपने मॉड्यूल में रखें:

# tasks.py: the worker imports jobs by module path, so keep them here
# pip install rq capskip requests
import os
from html.parser import HTMLParser

import requests
from capskip import CapSkip

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


class FormPage(HTMLParser):
    """Collects the reCAPTCHA sitekey and the hidden fields of its form."""

    def __init__(self):
        super().__init__()
        self.sitekey, self.hidden, self._form = None, {}, None

    def handle_starttag(self, tag, attrs):
        a = dict(attrs)
        if tag == "form":
            self._form = {}
        if a.get("data-sitekey"):
            self.sitekey = a["data-sitekey"]
            if self._form is not None:
                self.hidden = self._form
        hidden = (a.get("type") or "").lower() == "hidden"
        if tag == "input" and hidden and a.get("name") and self._form is not None:
            self._form[a["name"]] = a.get("value") or ""

    def handle_endtag(self, tag):
        if tag == "form":
            self._form = None


def sign_up(page_url, username):
    # One session per job, so the page's cookies go back with the form.
    session = requests.Session()
    page = FormPage()
    page.feed(session.get(page_url, timeout=30).text)

    # Solve inside the job, right before the post: tokens expire.
    token = solver.recaptcha(page.sitekey, page_url)["code"]

    resp = session.post(page_url, data={
        **page.hidden,
        "username": username,
        "g-recaptcha-response": token,
    }, headers={"Referer": page_url}, timeout=30)
    resp.raise_for_status()
    return resp.status_code

हर जॉब अपना requests.Session खोलती है, इसलिए पेज जो session cookie सेट करता है, वह फॉर्म के साथ वापस जाती है। parser उस फॉर्म के hidden फ़ील्ड रखता है जिसमें widget है, जिनमें वह CSRF टोकन भी शामिल है जिससे वह cookie जुड़ी है, और पेज पर कहीं और मौजूद search या newsletter फॉर्म को अनदेखा करता है। सैंपल वापस पेज URL पर ही पोस्ट करता है; अगर फॉर्म का action कहीं और इशारा करता है, तो वहीं पोस्ट करें। Referer header इसलिए है क्योंकि requests न Referer भेजता है, न Origin, और कुछ frameworks, जिनमें Django भी है, ऐसी HTTPS फॉर्म पोस्ट ठुकरा देते हैं जिसमें इनमें से कोई भी न हो।

raise_for_status किसी HTTP error को, जैसे फेल हुई CSRF जाँच से आया 403, चुपचाप मिली सफलता के बजाय फेल हुई जॉब में बदल देता है, और रीट्राई चालू होने पर यह मायने रखता है। जो साइट सामान्य 200 पेज के साथ टोकन ठुकराती है, वह फिर भी सफलता ही गिनी जाती है, इसलिए response में वह चीज़ भी जाँचें जो आपकी साइट सफलता पर दिखाती है।

सॉल्वर क्लाइंट मॉड्यूल import होते समय बनता है। RQ के डिफ़ॉल्ट वर्कर में यह हर जॉब के नए work horse में होता है, और SimpleWorker में हर वर्कर के लिए एक बार। दोनों ठीक हैं, क्योंकि क्लाइंट कॉल के बीच कोई कनेक्शन खुला नहीं रखता। SDK एनवायरनमेंट वेरिएबल खुद नहीं पढ़ता, इसीलिए कोड CAPSKIP_HOST, CAPSKIP_PORT और CAPSKIP_API_KEY को पढ़ता है और उन्हें constructor को पास करता है। किसी दूसरे वर्कर को किसी दूसरी CapSkip मशीन की ओर मोड़ने के लिए उसका एनवायरनमेंट बदलें, कोड नहीं।

चरण 2: हल के हिसाब से टाइमआउट देकर क्यू में डालें

यही वह सेटिंग है जो तय करती है कि RQ कैप्चा जॉब किसी धीमे हल में टिक पाएगी या नहीं। हर बार क्यू में डालते समय job_timeout पास करें, या Queue object को एक default_timeout दें। वह डिफ़ॉल्ट Python object में रहता है, Redis में नहीं, इसलिए क्यू में डालने वाली हर script को अपना Queue एक ही तरह बनाना होगा:

# enqueue.py
from redis import Redis
from rq import Queue

from tasks import sign_up

# RQ's default is 180 seconds; a reCAPTCHA solve may take 300.
queue = Queue("captcha", connection=Redis(), default_timeout=420)

job = queue.enqueue(sign_up, "https://example.com/signup", "YOUR_USERNAME")
print(job.id)

यह संख्या सबसे बुरी स्थिति को जोड़कर निकलती है। SDK किसी reCAPTCHA हल को 300 सेकंड तक पोल करता है, जो उसका recaptchaTimeout है, फिर TimeoutException उठाता है। पेज लाना और पोस्ट, दोनों requests को timeout=30 पास करते हैं, जो पूरी रिक्वेस्ट को नहीं, बल्कि कनेक्शन और डेटा के हर इंतज़ार को सीमित करता है। सब मिलाकर यह लगभग 360 सेकंड बनता है, और 420 किसी धीमे पेज के लिए एक मिनट की गुंजाइश छोड़ता है।

CapSkip अपनी अलग घड़ी भी चलाता है। उसकी reCAPTCHA सेटिंग्स में कोई टास्क उसके 10 थ्रेड में से किसी एक के लिए 250 सेकंड इंतज़ार कर सकता है, फिर उसके पास challenge लोड करने के लिए 250 सेकंड तक होते हैं और उसे हल करने के लिए 250 सेकंड और। जो टास्क इनमें से किसी भी एक सीमा को पार कर जाता है, उसे CapSkip एक ApiException के साथ फेल कर देता है। जो टास्क थ्रेड के लिए कुछ देर इंतज़ार करता है और फिर धीरे हल होता है, वह पहले SDK की 300 सेकंड की सीमा पार कर सकता है, और तब नतीजा TimeoutException होता है। हालाँकि SDK, CapSkip को की जाने वाली अपनी HTTP कॉल पर कोई timeout सेट नहीं करता। अगर CapSkip किसी रिक्वेस्ट के बीच में जवाब देना बंद कर दे, तो RQ का डिफ़ॉल्ट वर्कर फिर भी job_timeout पर जॉब खत्म कर देता है; नीचे बताया गया SimpleWorker ऐसा नहीं कर सकता।

अब देखें कि डिफ़ॉल्ट के साथ क्या होता है। 180 सेकंड पर RQ जॉब के भीतर JobTimeoutException उठाता है, जॉब उस समय जहाँ भी हो, और कैप्चा जॉब के लिए यह लगभग हमेशा SDK का पोल लूप होता है। जॉब failed job registry में पहुँच जाती है, और उसकी error होती है Task exceeded maximum timeout value (180 seconds)। CapSkip को कुछ नहीं बताया जाता। वह चलता रहता है, एक ऐसा टोकन बनाता है जिसे कोई नहीं लेता, और उसने जो थ्रेड इस्तेमाल किया, वह बेकार चला गया। हमने 200 सेकंड लेने वाले एक हल पर ठीक यही दोहराकर देखा।

हल के चारों ओर Exception को catch न करें

JobTimeoutException, Exception की एक सामान्य subclass है, जो आपके कोड के भीतर उठाई जाती है। हल के चारों ओर लगा एक व्यापक except Exception उसे पकड़ लेता है, जॉब सामान्य रूप से लौट आती है, और RQ उसे finished दर्ज कर देता है, और टाइमआउट का कहीं कोई निशान नहीं रहता। हमारे टेस्ट में, इस तरह लिखी गई एक जॉब की सीमा हल के बीच में ही खत्म हो गई और वर्कर ने Job OK लॉग किया। इसके बजाय SDK की अपनी base class को catch करें:

import logging

from capskip import CapSkipError

log = logging.getLogger(__name__)

try:
    token = solver.recaptcha(page.sitekey, page_url)["code"]
except CapSkipError as exc:
    # The SDK's errors only. RQ's JobTimeoutException is not one of
    # them, so a job that ran out of time still fails as it should.
    log.warning("solve failed for %s: %s", page_url, exc)
    raise

चरण 3: उतने ही वर्कर चलाएँ जितने CapSkip के पास थ्रेड हैं

RQ वर्कर एक समय में एक ही जॉब चलाता है, इसलिए RQ कैप्चा जॉब के लिए वर्कर की संख्या ही एक साथ चल रहे हलों की संख्या है। CapSkip डिफ़ॉल्ट रूप से एक साथ 10 reCAPTCHA हल करता है, जो उसकी Max. Threads सेटिंग है, और हर अतिरिक्त टास्क को खाली थ्रेड का इंतज़ार करवाता है। इस संख्या से ज़्यादा वर्कर ज़्यादा काम पूरा नहीं करते। इसके बजाय उनके टास्क CapSkip के भीतर क्यू में खड़े रहते हैं, और यह इंतज़ार हर जॉब के टाइमआउट को खा जाता है। हर थ्रेड के लिए एक वर्कर सही आकार है:

# Ten workers for CapSkip's ten reCAPTCHA threads
rq worker-pool captcha -n 10

worker-pool वर्कर शुरू करता है और जो भी वर्कर बंद हो जाए, उसे दोबारा शुरू करता है। वह जो भी वर्कर शुरू करता है, उसमें शेड्यूलर चालू होता है, और उनमें से एक वर्कर क्यू के लिए शेड्यूलर चलाता है, जिस पर अगले चरण की रीट्राई निर्भर हैं। अगर आप CapSkip में Max. Threads बढ़ाते हैं, तो पूल को भी उसी हिसाब से बढ़ाएँ, और उसी CapSkip को कॉल करने वाली हर मशीन का हर वर्कर गिनें।

चरण 4: रीट्राई, और उन्हें शेड्यूलर की ज़रूरत क्यों है

डिफ़ॉल्ट रूप से RQ कुछ भी रीट्राई नहीं करता। फेल हुई जॉब failed job registry में जाती है और वहीं पड़ी रहती है। RQ से दोबारा कोशिश करवाने के लिए, क्यू में डालते समय एक Retry पास करें:

from rq import Retry

job = queue.enqueue(
    sign_up, "https://example.com/signup", "YOUR_USERNAME",
    # Up to two more runs: 30 seconds, then 120 seconds after a failure.
    retry=Retry(max=2, interval=[30, 120]),
)

अंतराल वाली रीट्राई वापस क्यू पर नहीं डाली जाती। RQ उसे शेड्यूल करता है, और सिर्फ़ शेड्यूलर चलाने वाला वर्कर ही उसे कभी वापस ले जाता है। worker-pool हमेशा एक शेड्यूलर चलाता है। सादे rq worker से शुरू किया गया अकेला वर्कर ऐसा नहीं करता, और तब हर रीट्राई की गई जॉब बिना किसी error के हमेशा के लिए scheduled registry में इंतज़ार करती रहती है। हमने ठीक यही होते देखा, और शेड्यूलर वाला वर्कर शुरू होते ही वही जॉब कुछ ही सेकंड में चल गई। अकेले वर्कर ऐसे शुरू करें:

rq worker captcha --with-scheduler

रीट्राई पूरी जॉब को दोबारा चलाती है: नया पेज, नया हल और नई पोस्ट। आप यही चाहते हैं, क्योंकि reCAPTCHA टोकन एक ही बार स्वीकार होता है, इसलिए वहीं से आगे बढ़ाने लायक कुछ होता ही नहीं। इसी वजह से जॉब को पोस्ट पर ही खत्म होना चाहिए। कामयाब पोस्ट के बाद जो भी चीज़ फेल हो सकती है, वह रीट्राई से दूसरी बार पोस्ट करवा देती है।

हल और पोस्ट को एक ही जॉब में रखें

काम को बाँटना लुभावना लगता है। एक जॉब हल करके टोकन लौटाए, और दूसरी जॉब, या पहली को क्यू में डालने वाला कोड, उसे बाद में पोस्ट करे। ऐसा न करें। reCAPTCHA टोकन जारी होने के लगभग दो मिनट बाद एक्सपायर हो जाता है, और RQ कोई वादा नहीं करता कि अगली जॉब कब शुरू होगी। लोड के दौरान वह क्यू पर मौजूद बाकी सब के पीछे इंतज़ार करती है। RQ डिफ़ॉल्ट रूप से किसी जॉब की return value भी सिर्फ़ 500 सेकंड तक रखता है। जॉब के भीतर, पोस्ट से ठीक पहले हल करने से टोकन की पूरी उम्र एक ही function कॉल के भीतर रहती है। reCAPTCHA टोकन की वैधता अवधि पर लिखा लेख एक्सपायरी के नियमों को विस्तार से समझाता है।

RQ वर्कर कहाँ चल सकता है: Windows, WSL या कोई दूसरी मशीन

RQ का डिफ़ॉल्ट वर्कर हर जॉब के लिए fork करके एक नई प्रोसेस बनाता है। Windows में os.fork नहीं है, इसलिए वहाँ वर्कर अपनी पहली ही जॉब पर AttributeError के साथ रुक जाता है। RQ का दस्तावेज़ कहता है कि वर्कर को fork चाहिए और Windows यूज़र्स को WSL की ओर भेजता है, हालाँकि worker classes वाला उसका पेज Windows के लिए SpawnWorker सुझाता है। RQ 2.12 पर SpawnWorker भी फेल होता है, क्योंकि वह हर जॉब का इंतज़ार os.wait4 से करता है, और यह कॉल भी Windows में नहीं है। इससे तीन रास्ते बचते हैं।

खुद CapSkip वाले PC पर, SimpleWorker इस्तेमाल करें। यह हर जॉब को किसी चाइल्ड प्रोसेस के बजाय वर्कर प्रोसेस के भीतर ही चलाता है। RQ 2.12 के साथ Windows पर इसने हमारी जॉब और शेड्यूलर, दोनों चलाए, और worker-pool ने ऐसे कई वर्कर साथ-साथ शुरू किए। इसे upstream से सपोर्टेड नहीं, बल्कि यहाँ टेस्ट किया हुआ मानें। यह job_timeout को एक timer से लागू करता है, लेकिन timer सिर्फ़ Python statements के बीच चलता है। जब हमने 8 सेकंड के job_timeout के तहत CapSkip को की गई एक कॉल को 40 सेकंड तक अटकाया, तो जॉब 40 सेकंड पर फेल हुई, 8 पर नहीं। जो कॉल कभी लौटती ही नहीं, वह उस वर्कर को तब तक घेरे रखती है जब तक आप वर्कर को दोबारा शुरू न करें। CapSkip, Local मोड में ही रहता है, क्योंकि वर्कर उसी मशीन पर है। Redis का कोई आधिकारिक Windows build नहीं है, लेकिन WSL के तहत चल रहा Redis, Windows प्रोग्राम को 127.0.0.1 पर जवाब देता है, और हमने यह सेटअप इसी तरह टेस्ट किया:

# On Windows: no fork, so run jobs inside the worker process
rq worker-pool captcha -n 10 -w rq.worker.SimpleWorker

उसी PC पर WSL 2 के तहत, वर्कर को एक दूसरी मशीन मानें। WSL 2 की डिफ़ॉल्ट NAT networking में, Linux के भीतर 127.0.0.1 का मतलब Linux VM है, Windows नहीं, इसलिए वहाँ का वर्कर Local मोड वाले CapSkip तक नहीं पहुँच सकता। हमने जाँचा, और कनेक्शन फेल होता है। CapSkip को Server मोड पर कर दें और CAPSKIP_HOST को Windows होस्ट के उस पते पर सेट करें जो Linux को दिखता है। WSL networking पर Microsoft की गाइड बताती है कि वह पता कैसे ढूँढें, और Windows 11 22H2 और उसके बाद के वर्ज़न पर mirrored networking का भी वर्णन करती है, जिसमें Linux, Windows सर्वरों तक 127.0.0.1 पर पहुँच सकता है।

Linux सर्वर, कंटेनर होस्ट या किसी प्लेटफ़ॉर्म पर, Server मोड इस्तेमाल करें। तब CapSkip आपके नेटवर्क पते या पब्लिक IP पर सुनता है, और हर वर्कर उसी API के ज़रिए जुड़ता है। जब रास्ता इंटरनेट से होकर जाए तो स्टैटिक पब्लिक IP इस्तेमाल करें और API key validation चालू करें। Server मोड शुरू होते ही CapSkip अपना पोर्ट हर पते के लिए खोल देता है, इसलिए उसे सिर्फ़ अपने वर्कर तक सीमित रखने के लिए बाकी पतों के लिए Windows Firewall में एक block नियम जोड़ें। सॉल्वर अब भी आपकी अपनी Windows मशीन है, और हल अब भी बिना मीटर वाले हैं, चाहे कितने भी वर्कर उसे कॉल करें।

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

दो फ़ाइलें और एक कमांड। tasks.py में जॉब है, चरण 2 वाली सीमित exception handling के साथ; enqueue.py टाइमआउट और रीट्राई सेट करती है।

# tasks.py
# pip install rq capskip requests
import logging
import os
from html.parser import HTMLParser

import requests
from capskip import CapSkip, CapSkipError

log = logging.getLogger(__name__)
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")),
)


class FormPage(HTMLParser):
    def __init__(self):
        super().__init__()
        self.sitekey, self.hidden, self._form = None, {}, None

    def handle_starttag(self, tag, attrs):
        a = dict(attrs)
        if tag == "form":
            self._form = {}
        if a.get("data-sitekey"):
            self.sitekey = a["data-sitekey"]
            if self._form is not None:
                self.hidden = self._form
        hidden = (a.get("type") or "").lower() == "hidden"
        if tag == "input" and hidden and a.get("name") and self._form is not None:
            self._form[a["name"]] = a.get("value") or ""

    def handle_endtag(self, tag):
        if tag == "form":
            self._form = None


def sign_up(page_url, username):
    session = requests.Session()
    page = FormPage()
    page.feed(session.get(page_url, timeout=30).text)
    if not page.sitekey:
        raise ValueError(f"no data-sitekey on {page_url}")

    try:
        token = solver.recaptcha(page.sitekey, page_url)["code"]
    except CapSkipError as exc:
        # RQ's JobTimeoutException is not a CapSkipError, so it passes.
        log.warning("solve failed for %s: %s", page_url, exc)
        raise

    resp = session.post(page_url, data={
        **page.hidden,
        "username": username,
        "g-recaptcha-response": token,
    }, headers={"Referer": page_url}, timeout=30)
    resp.raise_for_status()
    return resp.status_code
# enqueue.py
from redis import Redis
from rq import Queue, Retry

from tasks import sign_up

queue = Queue("captcha", connection=Redis(), default_timeout=420)

for user in ["YOUR_USERNAME_1", "YOUR_USERNAME_2"]:
    job = queue.enqueue(
        sign_up, "https://example.com/signup", user,
        retry=Retry(max=2, interval=[30, 120]),
    )
    print(job.id)
# Linux or WSL; on Windows add -w rq.worker.SimpleWorker
rq worker-pool captcha -n 10

पूल को उसी फ़ोल्डर से चलाएँ जिसमें tasks.py है, क्योंकि वर्कर उसे वहीं से import करते हैं। rq info हर क्यू की waiting, executing, finished और failed गिनती दिखाता है, और वर्कर भी। यह scheduled registry को नहीं गिनता, जहाँ अंतराल वाली रीट्राई इंतज़ार करती हैं। फेल हुई जॉब डिफ़ॉल्ट रूप से अपना traceback एक साल तक रखती है: Job.fetch से जॉब लाएँ और उसका exc_info पढ़ें।

आम errors और उनका मतलब

आप जो देखते हैंकारणफिक्स
JobTimeoutException: Task exceeded maximum timeout value (180 seconds)जॉब RQ के डिफ़ॉल्ट टाइमआउट पर चली, और हल में उससे ज़्यादा समय लगाjob_timeout या क्यू का default_timeout 420 पर सेट करें
जॉब finished दिखती है, लेकिन साइट तक कुछ नहीं पहुँचाएक व्यापक except Exception ने RQ का JobTimeoutException पकड़ लियाहल के चारों ओर Exception नहीं, CapSkipError को catch करें
रीट्राई की गई जॉब दोबारा कभी नहीं चलतींरीट्राई में अंतराल है और कोई भी वर्कर शेड्यूलर नहीं चलाता। जॉब scheduled registry में इंतज़ार करती हैं, जिसे rq info नहीं गिनताworker-pool इस्तेमाल करें, या अकेले वर्कर शेड्यूलर ऑप्शन के साथ शुरू करें
ValueError: Functions from the __main__ module cannot be processed by workersजॉब function उसी script में परिभाषित है जो उसे क्यू में डालती हैउसे tasks.py जैसे किसी मॉड्यूल में ले जाएँ और import करें
Windows वर्कर के जॉब उठाते ही os.fork या os.wait4 के लिए AttributeErrorडिफ़ॉल्ट वर्कर और SpawnWorker, दोनों सिर्फ़ Unix वाली कॉल इस्तेमाल करते हैंवर्कर rq.worker.SimpleWorker के साथ शुरू करें। उस वर्कर ने जो जॉब उठाई थी, वह तब तक executing में रहती है जब तक RQ का cleanup उसे फेल न कर दे
साइट पोस्ट को expire हो चुके session के रूप में ठुकरा देती हैपेज और पोस्ट अलग-अलग sessions पर गए, या बिना Referer केहर जॉब के लिए एक requests.Session इस्तेमाल करें और पेज URL को Referer के रूप में भेजें
WSL या किसी दूसरी मशीन से पहले ही हल पर NetworkExceptionवहाँ 127.0.0.1, CapSkip वाली मशीन नहीं हैCapSkip को Server मोड पर करें और CAPSKIP_HOST को उसके पते पर सेट करें
ERROR_CAPTCHA_UNSOLVABLE वाला ApiExceptionCapSkip ने टास्क फेल कर दिया, उदाहरण के लिए अपने wait या solve टाइमआउट के बादRetry को जॉब दोबारा चलाने दें, और वर्कर Max. Threads के बराबर या उससे कम रखें
300 सेकंड बाद TimeoutExceptionटास्क ने थ्रेड का इंतज़ार किया और फिर धीरे हल हुआ, इसलिए दोनों मिलाकर 300 सेकंड से ज़्यादा हो गए, या हल के बीच में CapSkip बंद कर दिया गयापूल का आकार Max. Threads के बराबर रखें और जाँचें कि CapSkip अब भी चल रहा है

FAQ

क्या RQ का जॉब टाइमआउट CapSkip में चल रहे हल को रोक देता है?

नहीं। टाइमआउट आपके Python कोड को खत्म करता है, उस टास्क को नहीं जिस पर CapSkip काम कर रहा है। CapSkip उसे पूरा करता है, या अपनी घड़ी के हिसाब से फेल करता है, और नतीजा ऐसे poll का इंतज़ार करता है जो कभी आता ही नहीं। इसीलिए टाइमआउट हल के समय से नीचे नहीं, ऊपर होना चाहिए: हल के बीच में खत्म की गई जॉब से आप जॉब भी गँवाते हैं और CapSkip का एक थ्रेड भी।

क्या जॉब को AsyncCapSkip इस्तेमाल करना चाहिए?

इसमें कोई फ़ायदा नहीं है। RQ, async def जॉब को चलाता तो है, अपने एक अलग event loop में। फिर भी हर वर्कर एक समय में एक ही जॉब चलाता है, इसलिए दोनों तरह से समानांतरता वर्कर की संख्या से ही आती है। सादा CapSkip क्लाइंट जॉब को सरल रखता है। AsyncCapSkip का फ़ायदा लंबे समय तक चलने वाले ऐसे asyncio प्रोग्राम में मिलता है जो एक ही प्रोसेस से कई हल चलाता है।

क्या किसी होस्टेड प्लेटफ़ॉर्म पर चल रहे वर्कर CapSkip तक पहुँच सकते हैं?

हाँ। कनेक्शन सेटिंग्स में CapSkip को Server मोड पर कर दें ताकि वह loopback के बजाय किसी नेटवर्क पते पर सुने। वर्कर के एनवायरनमेंट में CAPSKIP_HOST सेट करें; जॉब का कोड नहीं बदलता। VPS, कंटेनर प्लेटफ़ॉर्म या मैनेज्ड होस्ट पर चल रहे वर्कर, सब उसी HTTP API के ज़रिए जुड़ते हैं। स्टैटिक पब्लिक IP इस्तेमाल करें, और हर उस पते के लिए Windows Firewall में एक block नियम रखें जो वर्कर का नहीं है। सॉल्वर आपके अपने हार्डवेयर पर ही रहता है, इसलिए वर्कर जोड़ने से प्रति-हल कोई खर्च नहीं जुड़ता।

यह Celery में कैप्चा हल करने से कैसे अलग है?

काम वही है: एक ही टास्क में हल और पोस्ट, सॉल्वर की अपनी सीमा से ऊपर की समय सीमा के साथ। उसके आसपास का तंत्र अलग है। Celery में सॉफ़्ट और हार्ड समय सीमाएँ हैं, और स्वीकृति का एक मॉडल है जिसके अपने जाल हैं। RQ में हर जॉब का एक ही टाइमआउट होता है, डिफ़ॉल्ट रूप से 180 सेकंड, जो जॉब के भीतर एक exception के रूप में उठता है, और अगर जॉब तब भी चल रही हो, तो उसका डिफ़ॉल्ट वर्कर 60 से 90 सेकंड बाद जॉब की प्रोसेस को खत्म कर देता है। अंतराल वाली रीट्राई को RQ के शेड्यूलर की भी ज़रूरत होती है। Celery वाला पहलू यहाँ कवर किया गया है: Celery टास्क में कैप्चा हल करने की गाइड.

संक्षेप में

RQ कैप्चा जॉब के लिए, पेज लाना, हल और पोस्ट, तीनों को उसके अपने मॉड्यूल में एक ही जॉब function में रखें। उसे 420 सेकंड के job_timeout के साथ क्यू में डालें, या क्यू को यही डिफ़ॉल्ट दें, क्योंकि RQ के अपने 180 सेकंड उस समय से कम हैं जितना एक reCAPTCHA हल ले सकता है। हल के चारों ओर CapSkipError को catch करें, Exception को कभी नहीं। worker-pool से उतने ही वर्कर चलाएँ जितने CapSkip के पास थ्रेड हैं; यह वह शेड्यूलर भी चलाता है जिसकी अंतराल वाली रीट्राई को ज़रूरत होती है। Windows पर SimpleWorker इस्तेमाल करें; WSL या किसी दूसरी मशीन से, CapSkip को Server मोड पर कर दें।

चौबीसों घंटे हल करते दस वर्कर ठीक वैसा ही लोड पैदा करते हैं जिसका बिल कोई मीटर्ड सर्विस हर हज़ार हल के हिसाब से वसूलती है। आपकी अपनी मशीन पर चलने वाला कैप्चा सॉल्वर इसे बिना किसी प्रति-हल बिल के सँभाल लेता है।