RQ İşlerinde 180 Saniyelik Sınırın Ötesinde CAPTCHA Nasıl Çözülür

Redis üzerine kurulu Python iş kuyruğu RQ’da CAPTCHA çözmek için tüm sırayı tek bir işe koyun: sayfayı çekin, CAPTCHA’yı CapSkip ile çözün, formu gönderin. Bu durumda bir RQ CAPTCHA işinde değiştirilmesi gereken tek bir ayar kalır: zaman aşımı. RQ, siz aksini söylemedikçe her işe 180 saniye verir. CapSkip SDK’sı bir reCAPTCHA token’ı için 300 saniyeye kadar bekler; bu yüzden meşgul thread’lerin arkasında sıraya giren bir çözüm, yoklamanın ortasında öldürülür. RQ bir JobTimeoutException kaydeder, CapSkip ise çözümü artık onu bekleyen kimse yokken tamamlar. Bu rehber işi, zaman aşımını, worker’ları, yeniden denemeleri ve Windows dahil worker’ın nerede çalışabileceğini ele alıyor.
Neye ihtiyacınız var
- Bir Windows makinesinde çalışan CapSkip. Örnekler reCAPTCHA v2 çözer; aynı iş yapısı CapSkip’in desteklediği her tür için çalışır.
- RQ 2.x, capskip paketi ve requests ile birlikte Python 3.10 veya üzeri. Örnekler RQ 2.12 üzerinde çalıştırıldı.
- İşleri kuyruğa ekleyen kodun da worker’ların da ulaşabildiği, 5 veya üzeri sürümde bir Redis sunucusu. RQ, Valkey 7.2 veya üzerini de kabul eder.
- Worker’lar için bir makine. RQ’nun varsayılan worker’ı Windows’ta bulunmayan bir Unix çağrısına dayanır; bu yüzden aşağıdaki bir bölüm Windows’taki, WSL altındaki ve başka bir makinedeki seçenekleri ele alıyor.
- Çözücü için bir adres. Local modunda CapSkip 127.0.0.1 üzerinden yalnızca o cihaza yanıt verir. Server modunda ise ağ adresinizi veya genel IP’nizi dinler, böylece başka bir makinedeki bir worker onu API üzerinden çağırabilir. İkisi de şurada ayarlanır: bağlantı ayarları.
pip install rq capskip requests
1. Adım: işi kendi modülüne yazın
RQ bir işi, bir fonksiyonun import yolu ve argümanları olarak saklar; worker da işi aldığında o fonksiyonu import eder. Onu kuyruğa ekleyen betikte tanımlanmış bir fonksiyon __main__ içinde yaşar ve worker onu import edemez; bu yüzden RQ böyle bir işi daha kuyruğa ekleme anında bir ValueError ile reddeder. İşi kendine ait bir modüle koyun:
# 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_codeHer iş kendi requests.Session nesnesini açar, böylece sayfanın ayarladığı oturum çerezi formla birlikte geri gider. Ayrıştırıcı, widget’ı içeren formun gizli alanlarını tutar (bunların arasında o çerezin ait olduğu CSRF token’ı da vardır) ve sayfanın başka bir yerindeki arama ya da bülten formunu yok sayar. Örnek, gönderimi sayfa URL’sine yapar; formun action değeri başka bir yeri gösteriyorsa oraya gönderin. Referer başlığının orada olmasının nedeni, requests’in ne Referer ne de Origin göndermesidir; aralarında Django’nun da bulunduğu bazı framework’ler, ikisi de olmayan bir HTTPS form gönderimini reddeder.
raise_for_status, başarısız bir CSRF kontrolünden gelen 403 gibi bir HTTP hatasını sessiz bir başarı yerine başarısız bir işe dönüştürür; yeniden denemeler açık olduğunda bu önemlidir. Token’ı normal bir 200 sayfasıyla reddeden bir site yine de başarı sayılır; bu yüzden yanıtta sitenizin başarı durumunda gösterdiği şeyi de kontrol edin.
Çözücü istemcisi, modül import edildiğinde oluşturulur. RQ’nun varsayılan worker’ında bu, her işin yeni work horse sürecinde olur; SimpleWorker ile ise worker başına bir kez. İkisi de sorun değildir, çünkü istemci çağrılar arasında açık bir bağlantı tutmaz. SDK ortam değişkenlerini kendiliğinden okumaz; kodun CAPSKIP_HOST, CAPSKIP_PORT ve CAPSKIP_API_KEY değerlerini okuyup constructor’a vermesinin nedeni budur. Farklı bir worker’ı farklı bir CapSkip makinesine yönlendirmek için kodunu değil, ortamını değiştirin.
2. Adım: çözüme uyan bir zaman aşımıyla kuyruğa ekleyin
Bir RQ CAPTCHA işinin yavaş bir çözümü atlatıp atlatmayacağına karar veren ayar budur. Kuyruğa her eklemede job_timeout verin ya da Queue nesnesine bir default_timeout tanımlayın. Bu varsayılan değer Redis’te değil Python nesnesinde yaşar; bu yüzden kuyruğa iş ekleyen her betik kendi Queue nesnesini aynı şekilde oluşturmalıdır:
# 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)Bu sayı en kötü durumun toplanmasından gelir. SDK bir reCAPTCHA çözümünü, recaptchaTimeout değeri olan 300 saniyeye kadar yoklar, ardından TimeoutException fırlatır. Sayfa çekimi ve gönderim, requests’e ayrı ayrı timeout=30 verir; bu da isteğin tamamını değil, bağlantıyı ve veri için yapılan her beklemeyi sınırlar. Toplam yaklaşık 360 saniye eder ve 420, yavaş bir sayfa için bir dakikalık pay bırakır.
CapSkip’in kendi saati de vardır. reCAPTCHA ayarlarında bir görev, 10 thread’inden biri için 250 saniye bekleyebilir, ardından challenge’ı yüklemek için 250 saniyeye kadar, çözmek için de 250 saniye daha süresi olur. Bu sürelerden herhangi biri dolan bir görevi CapSkip bir ApiException ile başarısız sayar. Bir thread için bir süre bekleyip ardından yavaş çözülen bir görev ise önce SDK’nın 300 saniyesini aşabilir; bu da TimeoutException ile sonuçlanır. Ancak SDK, CapSkip’e yaptığı kendi HTTP çağrılarında hiçbir zaman aşımı ayarlamaz. CapSkip bir isteğin ortasında yanıt vermeyi bırakırsa RQ’nun varsayılan worker’ı işi job_timeout dolduğunda yine de sonlandırır; aşağıda ele alınan SimpleWorker ise bunu yapamaz.
Varsayılan değerle ise şu olur. RQ 180. saniyede, iş o anda hangi noktada olursa olsun, işin içinde JobTimeoutException fırlatır; bir CAPTCHA işi için bu nokta neredeyse her zaman SDK’nın yoklama döngüsüdür. İş, hata olarak Task exceeded maximum timeout value (180 seconds) mesajıyla başarısız işler kaydına düşer. CapSkip’e haber verilmez. Çalışmaya devam eder, kimsenin almadığı bir token üretir ve kullandığı thread boşa harcanmış olur. Tam olarak bunu, 200 saniye süren bir çözümle yeniden ürettik.
Çözümün etrafında Exception yakalamayın
JobTimeoutException, kodunuzun içine fırlatılan sıradan bir Exception alt sınıfıdır. Çözümün etrafındaki geniş kapsamlı bir except Exception onu yakalar, iş normal şekilde döner ve RQ onu, zaman aşımından hiçbir yerde iz kalmadan, tamamlanmış olarak kaydeder. Bizim testimizde bu şekilde yazılmış bir iş, çözümün ortasında süresini doldurdu ve worker Job OK logladı. Bunun yerine SDK’nın kendi temel sınıfını yakalayın:
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)
raise3. Adım: CapSkip’in thread sayısı kadar worker çalıştırın
Bir RQ worker’ı aynı anda tek bir iş çalıştırır; dolayısıyla RQ CAPTCHA işlerinde worker sayısı, aynı anda işlemde olan çözüm sayısıdır. CapSkip varsayılan olarak aynı anda 10 reCAPTCHA çözer (Max. Threads ayarı) ve sonraki her görevi boş bir thread için bekletir. Bu sayının üzerindeki worker’lar daha fazla iş bitirmez. Onların görevleri bunun yerine CapSkip içinde sıraya girer ve bu bekleme her işin zaman aşımından yer. Thread başına bir worker doğru boyuttur:
# Ten workers for CapSkip's ten reCAPTCHA threads rq worker-pool captcha -n 10
worker-pool worker’ları başlatır ve ölenleri yeniden başlatır. Başlattığı her worker’da scheduler açıktır ve bunlardan biri kuyruk için scheduler’ı çalıştırır; bir sonraki adımdaki yeniden denemeler buna bağlıdır. CapSkip’te Max. Threads değerini yükseltirseniz havuzu da buna göre büyütün ve aynı CapSkip’i çağıran her makinedeki her worker’ı hesaba katın.
4. Adım: yeniden denemeler ve neden bir scheduler’a ihtiyaç duydukları
RQ varsayılan olarak hiçbir şeyi yeniden denemez. Başarısız bir iş, başarısız işler kaydına gider ve orada kalır. RQ’nun yeniden denemesini istiyorsanız kuyruğa eklerken bir Retry verin:
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]),
)Aralıklı bir yeniden deneme kuyruğa geri konmaz. RQ onu zamanlar ve onu kuyruğa yalnızca scheduler’ı çalıştıran bir worker geri taşır. worker-pool her zaman bir scheduler çalıştırır. Düz rq worker ile başlatılan tekil bir worker ise çalıştırmaz; bu durumda yeniden denenen her iş, hiçbir hata vermeden sonsuza kadar zamanlanmış işler kaydında bekler. Bunun tam olarak yaşandığını gördük ve scheduler’ı açık bir worker başladığında aynı iş saniyeler içinde çalıştı. Tekil worker’ları şöyle başlatın:
rq worker captcha --with-scheduler
Bir yeniden deneme işin tamamını yeniden çalıştırır: yeni bir sayfa, yeni bir çözüm ve yeni bir gönderim. İstediğiniz de budur, çünkü bir reCAPTCHA token’ı yalnızca bir kez kabul edilir, yani kaldığı yerden devam ettirilecek bir şey yoktur. İşin gönderimle bitmesi gerekmesinin nedeni de budur. Başarılı bir gönderimden sonra başarısız olabilecek her şey, yeniden denemenin ikinci kez gönderim yapmasına yol açar.
Çözümü ve gönderimi aynı işte tutun
İşi bölmek cazip gelir. Bir iş çözer ve token’ı döndürür; ikinci bir iş ya da ilkini kuyruğa ekleyen kod onu daha sonra gönderir. Bunu yapmayın. Bir reCAPTCHA token’ının süresi, verildikten yaklaşık iki dakika sonra dolar ve RQ bir sonraki işin ne zaman başlayacağı konusunda hiçbir söz vermez. Yük altında o iş, kuyruktaki diğer her şeyin arkasında bekler. RQ ayrıca bir işin dönüş değerini varsayılan olarak yalnızca 500 saniye saklar. Çözümü işin içinde, gönderimden hemen önce yapmak, token’ın tüm ömrünü tek bir fonksiyon çağrısının içinde tutar. Bir reCAPTCHA token’ı ne kadar süre geçerli kalır başlıklı yazı, süre dolumu kurallarını ayrıntılı olarak ele alıyor.
RQ worker’ı nerede çalışabilir: Windows, WSL ya da başka bir makine
RQ’nun varsayılan worker’ı her iş için yeni bir süreç fork eder. Windows’ta os.fork yoktur, bu yüzden orada worker ilk işinde bir AttributeError ile durur. RQ’nun dokümantasyonu worker’ların fork’a ihtiyaç duyduğunu söyler ve Windows kullanıcılarını WSL’ye yönlendirir; yine de worker sınıflarını anlatan sayfası Windows için SpawnWorker’ı önerir. RQ 2.12’de SpawnWorker da başarısız olur, çünkü her işi Windows’ta yine bulunmayan os.wait4 ile bekler. Geriye üç yol kalıyor.
CapSkip’in çalıştığı bilgisayarın kendisinde SimpleWorker kullanın. Her işi bir alt süreçte değil, worker sürecinin kendi içinde çalıştırır. Windows’ta RQ 2.12 ile işlerimizi ve scheduler’ı çalıştırdı; worker-pool da bunlardan birkaçını yan yana başlattı. Bunu, RQ projesinin resmî olarak desteklediği bir şey olarak değil, burada test edilmiş bir şey olarak görün. job_timeout’u bir zamanlayıcıyla uygular, ancak bu zamanlayıcı yalnızca Python ifadeleri arasında tetiklenir. 8 saniyelik bir job_timeout altında CapSkip’e yapılan bir çağrıyı 40 saniye takılı bıraktığımızda iş 8. saniyede değil, 40. saniyede başarısız oldu. Hiç dönmeyen bir çağrı ise siz o worker’ı yeniden başlatana kadar onu meşgul tutar. Worker aynı makinede olduğu için CapSkip Local modunda kalır. Redis’in resmî bir Windows derlemesi yoktur, ancak WSL altında çalışan bir Redis, Windows programlarına 127.0.0.1 üzerinden yanıt verir; bu kurulumu biz de böyle test ettik:
# On Windows: no fork, so run jobs inside the worker process rq worker-pool captcha -n 10 -w rq.worker.SimpleWorker
Aynı bilgisayardaki WSL 2 altında worker’ı başka bir makine gibi düşünün. WSL 2’nin varsayılan NAT ağ modunda Linux içindeki 127.0.0.1, Windows değil Linux VM’dir; bu yüzden oradaki bir worker, Local modundaki CapSkip’e ulaşamaz. Kontrol ettik, bağlantı başarısız oluyor. CapSkip’i Server moduna alın ve CAPSKIP_HOST değerini, Linux’un gördüğü şekliyle Windows host’unun adresine yönlendirin. Microsoft’un WSL ağ iletişimi rehberi bu adresi nasıl bulacağınızı gösteriyor; ayrıca Windows 11 22H2 ve sonraki sürümlerde, Linux’un Windows sunucularına 127.0.0.1 üzerinden ulaşabildiği yansıtılmış (mirrored) ağ modunu da anlatıyor.
Bir Linux sunucusunda, bir konteyner sunucusunda ya da bir platformda Server modunu kullanın. CapSkip bu durumda ağ adresinizi veya genel IP’nizi dinler ve her worker aynı API üzerinden bağlanır. Rota internetten geçiyorsa statik bir genel IP kullanın ve API anahtarı doğrulamasını açın. CapSkip, Server modu başladığında portunu her adrese açar; portu yalnızca worker’larınıza açık tutmak için diğer adreslere yönelik bir Windows Firewall engelleme kuralı ekleyin. Onu kaç worker çağırırsa çağırsın, çözücü hâlâ sizin kendi Windows makinenizdir ve çözüm başına ücretlendirme hâlâ yoktur.
Tam çalışan örnek
İki dosya ve bir komut. tasks.py, 2. adımdaki dar kapsamlı istisna yönetimiyle birlikte işi tutar; enqueue.py zaman aşımını ve yeniden denemeleri ayarlar.
# 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
Havuzu tasks.py dosyasının bulunduğu klasörden çalıştırın, çünkü worker’lar onu oradan import eder. rq info, her kuyruğun bekleyen, yürütülen (executing), biten (finished) ve başarısız (failed) iş sayılarını ve worker’ları gösterir. Aralıklı yeniden denemelerin beklediği zamanlanmış işler kaydını saymaz. Başarısız bir iş, traceback’ini varsayılan olarak bir yıl saklar: işi Job.fetch ile çekin ve exc_info değerini okuyun.
Sık görülen hatalar ve anlamları
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
| JobTimeoutException: Task exceeded maximum timeout value (180 seconds) | İş, RQ’nun varsayılan zaman aşımıyla çalıştı ve çözüm bundan uzun sürdü | job_timeout değerini ya da kuyruğun default_timeout değerini 420 yapın |
| İş tamamlandı olarak işaretleniyor ama siteye hiçbir şey ulaşmadı | Geniş kapsamlı bir except Exception, RQ’nun JobTimeoutException’ını yakaladı | Çözümün etrafında Exception’ı değil, CapSkipError’ı yakalayın |
| Yeniden denenen işler bir daha hiç çalışmıyor | Yeniden denemenin bir aralığı var ve hiçbir worker scheduler’ı çalıştırmıyor. İşler, rq info’nun saymadığı zamanlanmış işler kaydında bekliyor | worker-pool kullanın ya da tekil worker’ları scheduler seçeneğiyle başlatın |
| ValueError: Functions from the __main__ module cannot be processed by workers | İş fonksiyonu, onu kuyruğa ekleyen betikte tanımlanmış | Fonksiyonu tasks.py gibi bir modüle taşıyın ve oradan import edin |
| Bir Windows worker’ı iş aldığında os.fork ya da os.wait4 için AttributeError | Varsayılan worker da SpawnWorker da yalnızca Unix’te bulunan çağrıları kullanıyor | Worker’ları rq.worker.SimpleWorker ile başlatın. O worker’ın aldığı iş, RQ’nun temizlik işlemi onu başarısız sayana kadar executing altında kalır |
| Site, gönderimi oturumun süresi dolmuş diye reddediyor | Sayfa ve gönderim farklı oturumlarla ya da Referer olmadan yapıldı | İş başına tek bir requests.Session kullanın ve sayfa URL’sini Referer olarak gönderin |
| WSL’den ya da başka bir makineden yapılan ilk çözümde bir NetworkException | Oradaki 127.0.0.1, CapSkip makinesi değil | CapSkip’i Server moduna alın ve CAPSKIP_HOST değerini onun adresi olarak ayarlayın |
| ERROR_CAPTCHA_UNSOLVABLE içeren bir ApiException | CapSkip görevi başarısız saydı; örneğin kendi bekleme ya da çözüm zaman aşımından sonra | İşi Retry ile yeniden çalıştırın ve worker sayısını Max. Threads değerinde ya da altında tutun |
| 300 saniye sonra TimeoutException | Bir görev bir thread için bekledi ve ardından yavaş çözüldü, böylece ikisi birlikte 300 saniyeyi aştı ya da CapSkip çözümün ortasında kapatıldı | Havuzu Max. Threads değerine göre boyutlandırın ve CapSkip’in hâlâ çalıştığını kontrol edin |
FAQ
RQ’nun iş zaman aşımı CapSkip’teki çözümü durdurur mu?
Hayır. Zaman aşımı, CapSkip’in üzerinde çalıştığı görevi değil, sizin Python kodunuzu sonlandırır. CapSkip görevi tamamlar ya da kendi saatine göre başarısız sayar ve sonuç hiç gelmeyecek bir yoklamayı bekler. Zaman aşımının çözüm süresinin altında değil üstünde olması gerekmesinin nedeni budur: çözümün ortasında öldürülen bir iş size hem işin kendisine hem de bir CapSkip thread’ine mal olur.
İş AsyncCapSkip kullanmalı mı?
Bir kazancı yok. RQ, async def ile yazılmış bir işi gerçekten de kendine ait bir event loop içinde çalıştırır. Yine de her worker aynı anda tek bir iş çalıştırır, dolayısıyla paralellik her iki durumda da worker sayısından gelir. Düz CapSkip istemcisi işi basit tutar. AsyncCapSkip, tek bir süreçten çok sayıda çözüm başlatan, uzun süre çalışan bir asyncio programında karşılığını verir.
Barındırılan bir platformdaki worker’lar CapSkip’e ulaşabilir mi?
Evet. Bağlantı ayarlarından CapSkip’i Server moduna alın; böylece loopback yerine bir ağ adresini dinler. CAPSKIP_HOST değişkenini worker’ların ortamında ayarlayın; iş kodu değişmez. Bir VPS’teki, bir konteyner platformundaki ya da yönetilen bir host’taki worker’ların hepsi aynı HTTP API üzerinden bağlanır. Statik bir genel IP kullanın ve worker olmayan her adres için bir Windows Firewall engelleme kuralı ekleyin. Çözücü sizin sahip olduğunuz donanımda kalır, dolayısıyla worker eklemek çözüm başına hiçbir maliyet eklemez.
Bunun Celery’de CAPTCHA çözmekten farkı ne?
İş aynıdır: çözücünün kendi süre sınırının üzerinde bir zaman limitiyle, tek bir görevde çözün ve gönderin. Çevresindeki mekanizma ise farklıdır. Celery’nin soft ve hard zaman limitleri ve kendine özgü tuzakları olan bir onaylama modeli vardır. RQ’da ise iş başına, varsayılanı 180 saniye olan tek bir zaman aşımı vardır; bu zaman aşımı işin içinde bir istisna olarak fırlatılır ve iş hâlâ çalışıyorsa varsayılan worker, işin sürecini 60 ila 90 saniye sonra öldürür. Aralıklı yeniden denemeler ayrıca RQ’nun scheduler’ına ihtiyaç duyar. Celery tarafı şurada ele alınıyor: Celery görevinde CAPTCHA çözme rehberi.
Kısa özet
Bir RQ CAPTCHA işi için sayfa çekimini, çözümü ve gönderimi, kendi modülündeki tek bir iş fonksiyonuna koyun. İşi 420 saniyelik bir job_timeout ile kuyruğa ekleyin ya da kuyruğa bu varsayılanı verin, çünkü RQ’nun kendi 180 saniyesi bir reCAPTCHA çözümünün sürebileceğinden kısadır. Çözümün etrafında asla Exception’ı değil, CapSkipError’ı yakalayın. worker-pool ile CapSkip’in thread sayısı kadar worker çalıştırın; worker-pool, aralıklı yeniden denemelerin ihtiyaç duyduğu scheduler’ı da çalıştırır. Windows’ta SimpleWorker kullanın; WSL’den ya da başka bir makineden bağlanıyorsanız CapSkip’i Server moduna alın.
- Python paketinin desteklediği tüm CAPTCHA türleri: Python CAPTCHA çözücü sayfası.
- reCAPTCHA v2 çözümünün kendisinin nasıl işlediği: reCAPTCHA v2 çözücü sayfası.
Gece gündüz çözüm yapan on worker, kullanım başına ücret alan bir servisin her bin çözüm için fatura kestiği yükün ta kendisidir. Kendi makinenizde çalışan bir captcha çözücü bu yükü çözüm başına fatura çıkarmadan kaldırır.
