Windows पर SQLite के साथ Huey टास्क में कैप्चा कैसे हल करें

Huey में कैप्चा हल करने के लिए, क्यू को अपने tasks module के बगल में एक SqliteHuey फ़ाइल में रखें, CapSkip को ऐसे टास्क के अंदर कॉल करें जिसमें रीट्राई हों, और कंज़्यूमर को थ्रेड वर्कर के साथ शुरू करें। Windows पर पूरा स्टैक बस इतना है: एक SQLite फ़ाइल, कोई Redis सर्वर नहीं, और उसी PC पर सॉल्वर। इस Huey कैप्चा सेटअप में चार जाल हैं, और यह गाइड हर एक को कवर करती है। कंज़्यूमर एक exe है, huey_consumer.py नहीं। थ्रेड वर्कर पर Huey का timeout ऑप्शन कुछ नहीं करता, इसलिए एक अटका हुआ हल किसी वर्कर को हमेशा के लिए रोके रखता है। डिफ़ॉल्ट सेटिंग्स के साथ, नतीजा पढ़ने पर पहली फेल हुई कोशिश रिपोर्ट होती है, जबकि Huey अभी भी रीट्राई कर रहा होता है। और CancelExecution अपने पहले argument के रूप में retry लेता है, इसलिए रीट्राई रोकने का सीधा-सा तरीका उल्टा हमेशा रीट्राई करता रह सकता है।
आपको क्या चाहिए
- किसी Windows मशीन पर चल रहा CapSkip, जिसमें reCAPTCHA सॉल्वर चालू हो।
- Python 3.10 या उसके बाद का वर्ज़न, जो CapSkip SDK का न्यूनतम वर्ज़न है। Huey 3.4.0 अपना कोई न्यूनतम वर्ज़न घोषित नहीं करता। नीचे का सब कुछ Python 3.13.7 और 3.14.0 पर, huey 3.4.0 और capskip 1.3.0 के साथ चलाया गया।
- Redis की ज़रूरत नहीं। SqliteHuey क्यू, शेड्यूल, locks और नतीजों को एक ही SQLite फ़ाइल में रखता है।
- सॉल्वर के लिए एक पता। Local मोड में CapSkip केवल उसी डिवाइस के लिए 127.0.0.1 पर जवाब देता है। Server मोड में वह आपके नेटवर्क पते या पब्लिक IP पर सुनता है, ताकि किसी दूसरी मशीन पर चल रहा कंज़्यूमर API के ज़रिए उसे कॉल कर सके। दोनों यहाँ सेट किए जाते हैं: कनेक्शन सेटिंग्स.
चरण 1: Huey और CapSkip SDK इंस्टॉल करें
अपने प्रोजेक्ट फ़ोल्डर में एक virtual environment बनाएँ और तीन पैकेज इंस्टॉल करें। requests पैकेज का इस्तेमाल पूरा उदाहरण login पेज लाने और पोस्ट करने के लिए करता है, और आगे आने वाला timeout फ़िक्स भी इसे इस्तेमाल करता है।
# Windows, in PowerShell or cmd: a virtual environment in your project folder python -m venv .venv .venv\Scripts\python -m pip install huey capskip requests
चरण 2: क्यू और सॉल्वर क्लाइंट बनाएँ
Huey को जो कुछ चाहिए, वह सब tasks.py में रहता है। कंज़्यूमर टास्क ढूँढने के लिए इसे import करता है, और क्यू में काम डालने वाली हर script भी इसे import करती है।
# tasks.py
import os
from pathlib import Path
from capskip import CapSkip
from huey import SqliteHuey
# The whole queue is one SQLite file. Keep it next to this module, so the
# consumer and every script that imports tasks use the same file, whatever
# folder they are started from.
huey = SqliteHuey(
"captcha",
filename=str(Path(__file__).with_name("huey.db")),
store_intermediate_errors=False, # get() waits for the last retry
)
# Local mode: CapSkip on this PC. Server mode: set CAPSKIP_HOST (and
# CAPSKIP_API_KEY if key validation is on) to reach it on another machine.
solver = CapSkip(
apiKey=os.environ.get("CAPSKIP_API_KEY", "capskip"),
host=os.environ.get("CAPSKIP_HOST", "127.0.0.1"),
port=int(os.environ.get("CAPSKIP_PORT", "8080")),
)ऊपर की तरह, डेटाबेस फ़ाइल का नाम पूरे path के साथ दें। डिफ़ॉल्ट फ़ाइल नाम huey.db है, उसी फ़ोल्डर में जहाँ से प्रोसेस शुरू हुआ था। तब किसी दूसरे फ़ोल्डर से शुरू हुई script अपनी एक खाली huey.db बना लेती है, अपना टास्क उसी में क्यू करती है, और ऐसे नतीजे का इंतज़ार करती है जो कभी नहीं आता। फ़ाइल को tasks.py के बगल में तय कर देने से हर प्रोसेस को एक ही क्यू मिलती है। जब तक कंज़्यूमर चलता है, दो सहायक फ़ाइलें, huey.db-wal और huey.db-shm, उसके बगल में रहती हैं। ये SQLite के write-ahead log का हिस्सा हैं, सामान्य हैं, और किसी hard stop के बाद भी बची रह सकती हैं।
SQLite ने बिना किसी error के यह लोड संभाला। बारह वर्कर और तीन scripts, जिन्होंने मिलकर 600 टास्क क्यू में डाले, उन्हें डेटाबेस lock होने की कोई error नहीं मिली। हर प्रोसेस के अंदर Huey एक lock के पीछे एक ही कनेक्शन साझा करता है, और अलग-अलग प्रोसेस के बीच SQLite फ़ाइल के लिए 5 सेकंड तक इंतज़ार करता है। इस फ़ाइल के बारे में एक बात जान लें: टास्क के arguments और नतीजे इसमें सादे bytes के रूप में pickle होकर जाते हैं। argument के रूप में पास किया गया password टेबल में पढ़ा जा सकता था, इसलिए secrets को टास्क arguments में नहीं, बल्कि एनवायरनमेंट में या tasks.py में रखें।
चरण 3: Huey कैप्चा टास्क लिखें, और तय करें कि किसे रीट्राई करना है
Huey टास्क जो भी exception उठाता है, उससे एक रीट्राई खर्च हो जाती है। CapSkip की कुछ नाकामियों के लिए यह सही है और बाकी के लिए बर्बादी, इसलिए टास्क उन्हें छाँटता है।
from capskip import ApiException, ValidationException
from huey import CancelExecution
# Any exception uses one of the two retries, 15 s apart: NetworkException
# when CapSkip is not running, TimeoutException, an unsolvable task.
@huey.task(retries=2, retry_delay=15)
def solve_recaptcha(sitekey, page_url):
try:
return solver.recaptcha(sitekey=sitekey, url=page_url)["code"]
except (ApiException, ValidationException) as exc:
if "ERROR_CAPTCHA_UNSOLVABLE" in str(exc):
raise # this attempt failed; a fresh one may not
# ERROR_GOOGLEKEY, ERROR_PAGEURL, ERROR_BAD_PARAMETERS and
# ERROR_KEY_DOES_NOT_EXIST fail the same way on every attempt.
# CancelExecution's first argument is retry: False ends the task now.
raise CancelExecution(False, f"{type(exc).__name__}: {exc}") from excतीन नाकामियाँ दोबारा कोशिश के लायक हैं: NetworkException, जब CapSkip अभी चल नहीं रहा, TimeoutException, और ERROR_CAPTCHA_UNSOLVABLE, जिसके ज़रिए CapSkip ऐसे हल की रिपोर्ट करता है जो इस बार सफल नहीं हुआ। कंज़्यूमर error को उसके traceback के साथ log करता है, फिर एक लाइन कि वह टास्क को बची हुई रीट्राई की संख्या के साथ फिर से क्यू में डाल रहा है। 15 सेकंड के retry_delay के साथ, हमारे रन में अगली कोशिश नाकामी के 16.1 सेकंड बाद शुरू हुई।
गलत बना sitekey, http या https के बिना page URL, या गलत API key (key validation चालू होने पर), किसी भी हल के शुरू होने से पहले ही ERROR_GOOGLEKEY, ERROR_PAGEURL या ERROR_KEY_DOES_NOT_EXIST के साथ ठुकरा दिए जाते हैं। खाली sitekey या page URL पर ERROR_BAD_PARAMETERS मिलता है। ये हर बार एक ही तरह फेल होते हैं, इसलिए रीट्राई करना बस समय बर्बाद करता है। Huey का CancelExecution किसी टास्क को बिना रीट्राई के तभी खत्म करता है जब retry, False हो। बिना argument के उठाने पर, जब तक टास्क के पास रीट्राई बची हैं, वह रीट्राई करता रहता है। इसका signature भी पढ़ें: इसका पहला positional argument retry है, संदेश नहीं। अगर इसे सिर्फ़ एक संदेश के साथ CancelExecution लिखा जाए, तो वह संदेश retry की वैल्यू बन जाता है और true गिना जाता है। तब log कहता है कि टास्क को रीट्राई किया जाएगा, और टास्क बार-बार चलता रहता है, जब तक आप कंज़्यूमर को रोक न दें। संदेश को retry=False के साथ पास करने पर TypeError आता है, क्योंकि तब retry को दो वैल्यू मिल जाती हैं। जैसा कोड करता है, False को पहले पास करें। तब कंज़्यूमर एक WARNING log करता है कि टास्क ने CancelExecution उठाया और उसे रीट्राई नहीं किया जाएगा।
इस छँटाई की एक सीमा है: जिस sitekey को Google खुद ठुकरा देता है, वह भी आप तक ERROR_CAPTCHA_UNSOLVABLE के रूप में ही पहुँचता है, क्योंकि CapSkip हर फेल हुए हल की रिपोर्ट इसी तरह करता है। ऐसे मामले में फेल होने से पहले तीन कोशिशें खर्च होती हैं। अगर कोई पेज हर बार फेल होता है, तो सबसे पहले उसका sitekey जाँचें।
चरण 4: Windows पर कंज़्यूमर शुरू करें
कंज़्यूमर को उस फ़ोल्डर से चलाएँ जिसमें tasks.py है। जब आप exe को उसके path से कॉल करते हैं, तो virtual environment को activate करने की ज़रूरत नहीं होती।
# In the folder that holds tasks.py, in PowerShell or cmd .venv\Scripts\huey_consumer tasks.huey -w 4
पुरानी गाइड, और कंज़्यूमर का अपना usage hint भी, huey_consumer.py बताते हैं। Huey 3 सिर्फ़ huey_consumer.exe इंस्टॉल करता है, इसलिए वह नाम PowerShell और cmd, दोनों में इस संदेश के साथ फेल होता है कि उसे पहचाना नहीं गया। ऊपर वाली कमांड दोनों में काम करती है, और .venv\Scripts\python -m huey.bin.huey_consumer tasks.huey भी। किसी दूसरे फ़ोल्डर से शुरू करने पर कंज़्यूमर Error importing tasks.huey और ModuleNotFoundError: No module named tasks के साथ रुक जाता है, क्योंकि वह अपने search path में सिर्फ़ मौजूदा फ़ोल्डर जोड़ता है।
Windows पर थ्रेड वर्कर ही असली विकल्प हैं। -k process के साथ कंज़्यूमर तुरंत एक error के साथ exit हो जाता है, जो कहती है कि huey cannot be run in process-mode on Windows, क्योंकि प्रोसेस वर्कर को fork() चाहिए, जो Windows में नहीं है। Greenlet वर्कर के लिए gevent इंस्टॉल होना चाहिए। वैसे भी इस काम के लिए थ्रेड ही ठीक हैं, क्योंकि वर्कर किसी हल का लगभग पूरा समय CapSkip के इंतज़ार में बिताता है।
हर वर्कर अपनी अलग रिक्वेस्ट भेजता है, इसलिए वर्कर की संख्या ही यह भी तय करती है कि CapSkip को एक साथ कितने हल मिलते हैं। 12 वर्कर और क्यू में 12 टास्क होने पर, सभी 12 रिक्वेस्ट 30 मिलीसेकंड के अंदर CapSkip तक पहुँच गईं। CapSkip का reCAPTCHA सेक्शन डिफ़ॉल्ट रूप से एक समय में 10 हल चलाता है, जो Max. Threads से तय होता है, और बाकी को क्यू में रखता है। कुछ logins के लिए चार वर्कर ठीक हैं। क्यू लंबी हो तो -w को उस सीमा की ओर बढ़ाएँ।
चरण 5: हल को क्यू में डालें और नतीजा एक बार पढ़ें
टास्क को कॉल करने से वह चलता नहीं है। यह टास्क को क्यू में लिखता है और एक Result handle लौटाता है, जिस पर आप इंतज़ार कर सकते हैं।
# enqueue.py, next to tasks.py: .venv\Scripts\python enqueue.py
from huey.exceptions import ResultTimeout, TaskException
from tasks import huey, solve_recaptcha
result = solve_recaptcha("YOUR_SITEKEY", "https://example.com/login")
try:
# Three attempts of up to about 5.5 minutes each, plus two 15 s delays.
token = result.get(blocking=True, timeout=1100)
except TaskException as exc:
print("solve failed:", exc)
except ResultTimeout:
print("no result yet: is the consumer running?")
else:
print("token:", token[:30], "...")
# Reading the result deleted it from huey.db. This handle keeps its
# copy, but a new handle for the same task id finds nothing.
print("read again:", huey.result(result.id)) # None1100 सेकंड का इंतज़ार सबसे बुरी स्थिति को कवर करता है: तीन कोशिशें, जिनमें से हर एक SDK की सीमा तक चलती है, और साथ में दो रीट्राई delay। फेल हुआ टास्क TaskException उठाता है, जिसका संदेश आख़िरी error होता है और जिसके metadata में बची हुई रीट्राई और traceback होते हैं। अगर समय पर कोई जवाब नहीं आता, तो आपको ResultTimeout मिलता है, जिसका आमतौर पर मतलब है कि कंज़्यूमर चल नहीं रहा या किसी दूसरी डेटाबेस फ़ाइल का इस्तेमाल कर रहा है।
चरण 2 वाली store_intermediate_errors लाइन यहाँ मायने रखती है। Huey के डिफ़ॉल्ट के साथ, हर फेल हुई कोशिश नतीजे के रूप में सहेजी जाती है। हमारे टेस्ट में, get() ने पहली नाकामी के बाद ही TaskException उठा दिया, जबकि Huey रीट्राई चला रहा था। रीट्राई का नतीजा handle पर reset() कॉल करने के बाद ही दिखा। इसे बंद करने पर get() आख़िरी कोशिश का इंतज़ार करता है।
नतीजा एक ही बार पढ़ा जा सकता है। पढ़ते ही वह फ़ाइल से मिट जाता है, जैसे CapSkip अपने जवाबों के साथ करता है। जिस handle ने उसे पढ़ा, उसके पास उसकी कॉपी रहती है, लेकिन उसके बाद उसी task id के साथ huey.result(), None लौटाता है। अगर आपके कोड के दो हिस्सों को वैल्यू चाहिए, तो get() को preserve=True पास करें। जो टास्क None लौटाता है, वह कुछ भी सहेजता ही नहीं, इसलिए उस पर इंतज़ार ResultTimeout पर खत्म होता है।
अटके हुए हल को अपने timeout की ज़रूरत क्यों है
Huey 3 किसी टास्क पर timeout ऑप्शन स्वीकार करता है, लेकिन थ्रेड वर्कर पर वह कुछ नहीं करता। किसी थ्रेड को बाहर से बाधित नहीं किया जा सकता, इसलिए Huey इसे तभी जाँचता है जब टास्क खुद task.check_timeout() कॉल करे। timeout=2 वाला एक टास्क, जो पाँच सेकंड sleep में रहा, सामान्य रूप से पूरा हुआ। प्रोसेस वर्कर, जिनमें timeout लागू किया जा सकता था, Windows पर मना कर दिए जाते हैं।
यह इसलिए मायने रखता है क्योंकि CapSkip SDK अपनी रिक्वेस्ट पर कोई HTTP timeout सेट नहीं करता। अगर CapSkip कनेक्शन स्वीकार कर ले और कभी जवाब न दे, तो कॉल हमेशा इंतज़ार करती रहती है। हमारे टेस्ट में दो वर्कर बिना किसी log लाइन के इसी हालत में पड़े रहे, और उनके पीछे क्यू में खड़े टास्क कभी शुरू नहीं हुए। सॉल्वर के ठीक होने के 45 सेकंड बाद भी वे अटके हुए थे। इसका फ़िक्स है SDK की HTTP कॉल को timeout देना। इसे tasks.py में, module स्तर पर रखें, ताकि यह किसी भी हल से पहले चले।
import functools
import types
import requests
import capskip.api
# capskip 1.3.0 calls requests.post/get with no timeout, and Huey cannot stop
# a thread worker that is stuck in one. Give every SDK call 5 s to connect
# and 30 s to answer. Module level in tasks.py, so it runs before any solve.
capskip.api.requests = types.SimpleNamespace(
RequestException=requests.RequestException,
post=functools.partial(requests.post, timeout=(5, 30)),
get=functools.partial(requests.get, timeout=(5, 30)),
)इसके साथ, अटके हुए submit ने 30.0 सेकंड बाद NetworkException उठाया, और टास्क रीट्राई हुआ। अटकी हुई स्टेटस जाँच ज़्यादा देर चलती है, क्योंकि SDK फेल हुए poll को अभी तैयार नहीं मानता है और अपने 300 सेकंड के recaptchaTimeout तक polling जारी रखता है। वह कोशिश करीब 333 सेकंड बाद TimeoutException के साथ खत्म हुई, और रीट्राई ने हल कर दिया। दोनों ही सूरत में वर्कर फिर से खाली हो जाता है। यह फ़िक्स capskip.api के अंदर requests reference को बदल देता है, जो SDK का एक अंदरूनी हिस्सा है, इसलिए capskip अपग्रेड करने पर इसे फिर से जाँचें।
ऐसा शेड्यूल्ड हल जो खुद से overlap न हो
periodic टास्क किसी हल को timer पर दोहरा सकता है, उदाहरण के लिए login को ताज़ा रखने के लिए। नीचे का पूरा उदाहरण असली login करता है। periodic टास्क कोई arguments नहीं लेते, इसलिए sitekey और URL, function के अंदर ही रहते हैं।
from huey import crontab
# Every 15 minutes. The lock goes under periodic_task: when a run is due
# while the previous one is still solving, another worker skips it instead
# of starting a second solve for the same login.
@huey.periodic_task(crontab(minute="*/15"))
@huey.lock_task("login")
def refresh_login():
result = solver.recaptcha(sitekey="YOUR_SITEKEY", url="https://example.com/login")
print("new token:", result["code"][:30], "...")कंज़्यूमर अपने periodic टास्क को शुरू होते समय एक बार जाँचता है, फिर उसी शुरुआत से गिनकर हर 60 सेकंड पर। इसलिए जिस रन का समय मौजूदा मिनट में है, वह तुरंत शुरू हो जाता है। अगर कोई हल interval से ज़्यादा समय लेता है, तब भी Huey अगला रन क्यू में डाल देता है। कई वर्कर होने पर कोई खाली वर्कर उसे तब शुरू कर देता, जब पहला रन अभी हल ही कर रहा हो। lock इसे रोकता है: नया रन एक WARNING log करता है कि lock हासिल न हो पाने की वजह से उसे नहीं चलाया गया, और वह स्किप हो जाता है। एक वर्कर के साथ कुछ भी overlap नहीं होता, लेकिन देर वाले रन क्यू में जमा होते जाते हैं और फिर एक के बाद एक चलते हैं। बहुत देर तक इंतज़ार कर चुके रन हटाने के लिए periodic_task decorator में सेकंड में एक expires argument जोड़ें, जैसे expires=600।
locks डेटाबेस फ़ाइल में रहते हैं, इसलिए वे crash के बाद भी बचे रहते हैं। hard stop के बाद पीछे छूटा lock बाद के हर रन को स्किप करवा देता है। decorator locks साफ़ करने के लिए कंज़्यूमर को -f के साथ शुरू करें, और वह log करता है कि उसे पुराने पड़े (stale) locks मिले। Huey 3.4 ने lock_task में एक ttl ऑप्शन भी जोड़ा, लेकिन SqliteHuey उसे सपोर्ट नहीं करता और lock लेते समय NotImplementedError उठाता है।
Huey कैप्चा टास्क की पूरी फ़ाइल
यह वर्ज़न login पेज लाता है, sitekey और CSRF token पढ़ता है, पोस्ट से ठीक पहले कैप्चा हल करता है और फॉर्म को Referer header के साथ सबमिट करता है। यह login को माँग पर log_in के रूप में और शेड्यूल पर scheduled_login के रूप में देता है। दोनों एक ही lock साझा करते हैं, इसलिए वे एक ही अकाउंट के लिए कभी एक साथ हल नहीं करते। URL और credentials बदलें, फिर कंज़्यूमर को -f के साथ शुरू करें।
# tasks.py: pip install huey capskip requests
# Start: .venv\Scripts\huey_consumer tasks.huey -w 4 -f
import functools
import logging
import os
import re
import types
from pathlib import Path
import requests
import capskip.api
from capskip import ApiException, CapSkip, ValidationException
from huey import CancelExecution, SqliteHuey, crontab
LOGIN_URL = "https://example.com/login"
USERNAME, PASSWORD = "YOUR_USERNAME", "YOUR_PASSWORD"
huey = SqliteHuey(
"captcha",
filename=str(Path(__file__).with_name("huey.db")), # same file from any folder
store_intermediate_errors=False, # get() waits for the last retry
)
log = logging.getLogger("huey.captcha") # printed by the consumer
# The SDK's HTTP calls have no timeout; give them one so a stuck CapSkip
# cannot hold a worker thread forever.
capskip.api.requests = types.SimpleNamespace(
RequestException=requests.RequestException,
post=functools.partial(requests.post, timeout=(5, 30)),
get=functools.partial(requests.get, timeout=(5, 30)),
)
solver = CapSkip(
apiKey=os.environ.get("CAPSKIP_API_KEY", "capskip"),
host=os.environ.get("CAPSKIP_HOST", "127.0.0.1"),
port=int(os.environ.get("CAPSKIP_PORT", "8080")),
)
def solve(sitekey, page_url):
try:
return solver.recaptcha(sitekey=sitekey, url=page_url)["code"]
except (ApiException, ValidationException) as exc:
if "ERROR_CAPTCHA_UNSOLVABLE" in str(exc):
raise # worth another attempt
# A refused sitekey, page URL or API key fails the same way every time.
log.error("not retrying: %s: %s", type(exc).__name__, exc)
raise CancelExecution(False, f"{type(exc).__name__}: {exc}") from exc
def field(html, pattern):
match = re.search(pattern, html)
if not match:
raise ValueError(f"not found on the login page: {pattern}")
return match.group(1)
def login():
with requests.Session() as session:
page = session.get(LOGIN_URL, timeout=30)
sitekey = field(page.text, r'data-sitekey="([^"]+)"')
csrf = field(page.text, r'name="csrfmiddlewaretoken" value="([^"]+)"')
token = solve(sitekey, LOGIN_URL) # solve right before the post
reply = session.post(LOGIN_URL, timeout=30, headers={"Referer": LOGIN_URL}, data={
"csrfmiddlewaretoken": csrf,
"username": USERNAME,
"password": PASSWORD,
"g-recaptcha-response": token,
})
reply.raise_for_status() # a refused login fails the attempt
log.info("logged in (HTTP %s)", reply.status_code)
return reply.status_code
# Both tasks take the same lock, so an on-demand login never runs while a
# scheduled one is solving, and the other way round.
# On demand: from tasks import log_in; log_in().get(blocking=True, timeout=1100)
@huey.task(retries=2, retry_delay=15) # a locked attempt uses a retry
@huey.lock_task("login")
def log_in():
return login()
# On a schedule; a run that comes due while the lock is held is skipped.
@huey.periodic_task(crontab(minute="*/15"))
@huey.lock_task("login")
def scheduled_login():
login()हल उसी कोशिश के अंदर होता है जिसमें पोस्ट होती है, इसलिए हर रीट्राई हमेशा नया पेज लाती है और फिर से हल करती है। फेल हुई कोशिश से कोई token कभी आगे नहीं ले जाया जाता, और यह मायने रखता है क्योंकि Google किसी reCAPTCHA token को सिर्फ़ दो मिनट तक वैध रहने देता है। ठुकराया गया login, जो 403 जैसी कोई HTTP error लौटाता है, raise_for_status() से कोशिश को फेल कर देता है, और उसे दो बार रीट्राई किया जाता है, हर बार नए पेज और नए हल के साथ। CapSkip प्रति-हल शुल्क नहीं लेता, इसलिए इसकी कीमत सिर्फ़ समय है। कई साइटें गलत password पर 200 और फिर से वही फॉर्म लौटाती हैं, इसलिए अपनी साइट के लिए एक जाँच जोड़ें, जैसे पोस्ट के बाद का URL। माँग पर चला log_in अगर पाता है कि lock शेड्यूल्ड रन के पास है, तो वह उसी WARNING के साथ स्किप हो जाता है, और उस कोशिश में एक रीट्राई खर्च होती है। 15 सेकंड के अंतर पर दो रीट्राई उसे कुल मिलाकर करीब 30 सेकंड का इंतज़ार देती हैं। अगर शेड्यूल्ड हल इससे ज़्यादा समय लेता है, तो तीनों कोशिशें स्किप हो जाती हैं और get() एक TaskException उठाता है, जिसके संदेश में TaskLockedException होता है। अगर आपके हल आमतौर पर इससे ज़्यादा समय लेते हैं, तो log_in पर retry_delay बढ़ाएँ।
किसी दूसरी script से माँग पर login करने के लिए, tasks से log_in को import करें, उसे कॉल करें, और चरण 5 की तरह get(blocking=True, timeout=1100) से नतीजे का इंतज़ार करें। लौटने वाली वैल्यू, पोस्ट के बाद का आख़िरी HTTP स्टेटस है। टास्क की log लाइनें कंज़्यूमर की विंडो में Huey की अपनी log लाइनों के बगल में दिखती हैं।
कंज़्यूमर को साफ़ तरीके से रोकना
कंज़्यूमर की विंडो में एक बार Ctrl+C दबाएँ। Huey नए टास्क लेना बंद कर देता है, चल रहे टास्क का इंतज़ार करता है और exit कर जाता है। हमारे रन में, हल के बीच में रोका गया कंज़्यूमर 18 सेकंड बाद exit हुआ, जैसे ही वह हल पूरा हुआ। खाली बैठा (idle) कंज़्यूमर एक सेकंड के दसवें हिस्से से भी कम में exit हुआ। दूसरा Ctrl+C वर्ज़न के हिसाब से अलग बर्ताव करता है: Python 3.14 तुरंत exit कर जाता है, जबकि 3.13 तब भी चल रहे टास्क का इंतज़ार करता है, इसलिए ऊपर वाले timeout के बिना अटके हुए हल को सिर्फ़ kill करके ही रोका जा सकता था।
साफ़ तरीके से रुकने (graceful stop) से तेज़ कोई भी तरीका उस टास्क को खो देता है जो चल रहा था। इसमें 3.14 पर दूसरा Ctrl+C, Ctrl+Break, और -t ऑप्शन शामिल हैं, जो साफ़ रुकने के इंतज़ार की सीमा तय करता है: -t 5 के साथ कंज़्यूमर, Ctrl+C के करीब 5.1 सेकंड बाद exit हुआ। खोया हुआ टास्क पहले ही क्यू से निकल चुका था, इसलिए वह दोबारा नहीं चलता, और उसका lock पीछे छूट जाता है। इसीलिए पूरा उदाहरण -f के साथ शुरू होता है।
CapSkip को किसी दूसरी मशीन पर चलाना
कंज़्यूमर और सॉल्वर का एक ही PC पर होना ज़रूरी नहीं। कनेक्शन सेटिंग्स में CapSkip को Server मोड पर कर दें, तो वह आपके नेटवर्क पते या पब्लिक IP पर सुनता है। आपकी tasks.py पहले से ही पता एनवायरनमेंट से पढ़ती है, इसलिए कंज़्यूमर शुरू करने से पहले वेरिएबल सेट कर दें।
# PowerShell, before starting the consumer: CapSkip runs in Server mode # on another Windows machine on your network $env:CAPSKIP_HOST = "192.168.1.50" $env:CAPSKIP_API_KEY = "YOUR_API_KEY" # $env:CAPSKIP_PORT = "8080" only if you changed the port .venv\Scripts\huey_consumer tasks.huey -w 4 -f
अगर रास्ता इंटरनेट से होकर जाता है तो स्टैटिक पब्लिक IP इस्तेमाल करें, और API key validation चालू करें, CAPSKIP_API_KEY में भी वही key रखें। Server मोड शुरू होते ही CapSkip अपना पोर्ट हर पते के लिए खोल देता है, इसलिए उसे सिर्फ़ अपेक्षित मशीनों तक सीमित रखने के लिए बाकी पतों के लिए Windows Firewall में एक block नियम जोड़ें। तब कंज़्यूमर किसी भी ऐसी मशीन पर चल सकता है जो पोर्ट तक पहुँचती हो, और सॉल्वर अब भी आपकी अपनी Windows मशीन ही है, जिसमें हल बिना मीटर वाले हैं।
Huey में कैप्चा की आम errors
| आप जो देखते हैं | कारण | फिक्स |
|---|---|---|
| huey_consumer.py पहचाना नहीं जाता | Huey 3 सिर्फ़ huey_consumer.exe इंस्टॉल करता है | कमांड .venv\Scripts\huey_consumer चलाएँ |
| huey cannot be run in process-mode on Windows | प्रोसेस वर्कर को fork() चाहिए | डिफ़ॉल्ट थ्रेड वर्कर इस्तेमाल करें |
| ModuleNotFoundError: No module named tasks | कंज़्यूमर, tasks.py वाले फ़ोल्डर के बाहर से शुरू हुआ | उसे उसी फ़ोल्डर से शुरू करें |
| कंज़्यूमर चलने के बावजूद ResultTimeout | script और कंज़्यूमर अलग-अलग huey.db फ़ाइलें इस्तेमाल करते हैं | SqliteHuey को फ़ाइल का पूरा path दें |
| get() नाकामी बताता है, फिर टास्क सफल हो जाता है | store_intermediate_errors चालू है, इसलिए हर फेल हुई कोशिश सहेजी जाती है | store_intermediate_errors=False सेट करें |
| जिस टास्क को रुकना था, वह रीट्राई करता रहता है | CancelExecution को संदेश, retry argument के रूप में मिला | CancelExecution(False, message) उठाएँ |
| वर्कर टास्क उठाना बंद कर देते हैं और कुछ log नहीं करते | कोई हल बिना timeout वाली HTTP कॉल में अटका है | SDK की रिक्वेस्ट को timeout दें |
| हर शेड्यूल्ड रन स्किप हो जाता है | kill किए गए कंज़्यूमर का पीछे छूटा (stale) lock | कंज़्यूमर को -f के साथ रीस्टार्ट करें |
FAQ
क्या मैं SqliteHuey की जगह RedisHuey इस्तेमाल कर सकता हूँ?
हाँ। इस गाइड के टास्क, रीट्राई और locks उसी तरह काम करते हैं। redis पैकेज भी इंस्टॉल करें, फिर SqliteHuey की जगह RedisHuey से क्यू बनाएँ। हालाँकि उसे Redis सर्वर चाहिए, और Windows के साथ कोई Redis सर्वर नहीं आता। जिस PC पर CapSkip पहले से चल रहा है, उस पर SQLite फ़ाइल आपको दूसरी सर्विस चलाने से बचाती है। कई मशीनों पर फैली क्यू के लिए Redis बेहतर विकल्प है, जैसा कि यहाँ दिखाया गया है: Celery टास्क में कैप्चा हल करने की गाइड.
idle रहने के बाद पहला टास्क देर से क्यों शुरू होता है?
खाली बैठा (idle) कंज़्यूमर डेटाबेस को धीरे-धीरे कम बार जाँचता है, डिफ़ॉल्ट रूप से हर 10 सेकंड तक। हमारे रन में, चार वर्कर के साथ, idle अवधि के बाद पहले टास्क ने 3 से 7 सेकंड इंतज़ार किया। उस इंतज़ार को एक सेकंड तक सीमित करने के लिए कंज़्यूमर को -m 1 के साथ शुरू करें; तब यह एक सेकंड से कम रहा।
क्या यह Django प्रोजेक्ट में काम करता है?
हाँ, huey.contrib.djhuey के ज़रिए। HUEY सेटिंग में huey_class को huey.SqliteHuey पर सेट करें और एक filename दें, और कंज़्यूमर को manage.py run_huey से शुरू करें। एक डिफ़ॉल्ट लोगों को चौंकाता है: DEBUG चालू होने पर djhuey टास्क को रिक्वेस्ट के अंदर ही तुरंत चला देता है, इसलिए हल तब तक पेज को रोके रखता है जब तक CapSkip जवाब न दे। असली क्यू को टेस्ट करने के लिए HUEY सेटिंग में immediate को False पर सेट करें।
क्या कंज़्यूमर CapSkip से अलग किसी मशीन पर चल सकता है?
हाँ। कनेक्शन सेटिंग्स में CapSkip को Server मोड पर कर दें, ताकि वह loopback के बजाय किसी नेटवर्क पते पर सुने, और कंज़्यूमर शुरू होने से पहले CAPSKIP_HOST को उसी पते पर सेट करें। तब टास्क उसे उसी HTTP API के ज़रिए किसी भी ऐसी मशीन से कॉल करते हैं जो पोर्ट तक पहुँच सकती है। जिन पतों को उस तक नहीं पहुँचना चाहिए, उनके लिए Windows Firewall में एक block नियम जोड़ें। सॉल्वर अब भी आपके अपने हार्डवेयर पर चलता है, और कोई भी हल किसी third-party सर्विस से होकर नहीं जाता।
संक्षेप में
Windows पर Huey कैप्चा टास्क के लिए, SqliteHuey फ़ाइल को tasks.py के बगल में तय करें, store_intermediate_errors बंद करें, और CapSkip की सिर्फ़ उन्हीं नाकामियों को रीट्राई करें जिन्हें नई कोशिश ठीक कर सकती है, और बाकी को CancelExecution(False, message) से खत्म करें। .venv\Scripts\huey_consumer को थ्रेड वर्कर के साथ उस फ़ोल्डर से शुरू करें जिसमें tasks.py है, SDK की HTTP कॉल को timeout दें, यह मानकर चलें कि हर नतीजा सिर्फ़ एक बार पढ़ा जा सकता है, और शेड्यूल्ड हलों पर lock लगाएँ। यहाँ इस्तेमाल हुआ कंज़्यूमर का हर ऑप्शन Huey कंज़्यूमर डॉक्यूमेंटेशन में दर्ज है।
- कैप्चा के वे सभी टाइप जिन्हें Python पैकेज संभालता है: Python कैप्चा सॉल्वर पेज.
- checkbox वाला reCAPTCHA कैसे काम करता है और सॉल्वर क्या-क्या कवर करता है: reCAPTCHA v2 सॉल्वर पेज.
- खुद हल करने वाली कॉल, उसके हर ऑप्शन के साथ: Python में reCAPTCHA v2 हल करने की गाइड.
एक फ़ाइल में क्यू और उसी PC पर सॉल्वर, पूरे काम को आपके अपने नियंत्रण वाले हार्डवेयर पर रखते हैं। लोकल कैप्चा बायपास का असली फ़ायदा यही है: हर रीट्राई मुफ़्त है, इसलिए टास्क बेझिझक दोबारा कोशिश कर सकता है।
