إذا كانت مهام الأتمتة لديك تعمل بسلاسة ثم بدأت فجأة تُعيد ERROR_ZERO_BALANCE مع كل طلب، فالسبب ليس خللًا في الكود بل ببساطة نفاد رصيد حساب CaptchaAI. الحساب لم يعد يملك رصيدًا كافيًا لمعالجة المهام، فيرفض الخادم أي طلب جديد حتى تُضيف رصيدًا. الحل الفوري هو إعادة شحن الرصيد من captchaai.com، لكن الهدف الأهم هو ألا تصل إلى هذه النقطة من الأساس: فحص استباقي للرصيد، وتنبيهات مبكرة، وتعامل رشيق مع النفاد يبقي بقية سير العمل واقفًا على قدميه.
تخيّل فريقًا في القاهرة أو الرياض يشغّل مهمة جمع بيانات ليلية طوال نهاية الأسبوع. ينفد الرصيد مساء الجمعة، وأي تحويل بنكي جديد لن يُعتمد قبل يوم أو يومَي عمل، فتتوقف الأتمتة بالكامل حتى صباح الأحد. هذا النوع من التوقف المكلف هو تحديدًا ما تمنعه الأنماط الواردة في هذا الدليل.
لماذا يظهر خطأ الرصيد الصفري
قبل معالجة الخطأ، من المفيد معرفة مصدره. في معظم الحالات يعود ERROR_ZERO_BALANCE إلى أحد أربعة أسباب، ولكل منها إجراء مختلف:
| السبب | معدل التكرار | الإجراء المقترح |
|---|---|---|
| نفاد رصيد الحساب | الأكثر شيوعًا | أضف رصيدًا من موقع captchaai.com |
| استهلاك أعلى من المتوقع | شائع | فعّل مراقبة الرصيد وحدود التنبيه |
| تسرّب مفتاح API عن طريق الخطأ | نادر | دوّر مفتاح الـ API وراجع سجل الاستخدام |
| انتهاء صلاحية طريقة الدفع | أحيانًا | حدّث بيانات الفوترة في لوحة التحكم |
تحديد السبب الصحيح يوفّر عليك دقائق من التخمين: نفاد فعلي للرصيد يُعالَج بالشحن، بينما استهلاك مفاجئ قد يشير إلى مفتاح مكشوف يستنزف رصيدك.
الفحص السريع لرصيد الحساب
أول خطوة تشخيصية هي قراءة الرصيد الحالي مباشرة من الـ API بدل الاعتماد على التخمين. تستخدم الدالة التالية الإجراء getbalance عبر نقطة النهاية res.php، وتُعيد الرصيد كرقم عشري بالدولار الأمريكي:
import requests
def check_balance(api_key):
"""Check current CaptchaAI balance."""
resp = requests.get(
"https://ocr.captchaai.com/res.php",
params={"key": api_key, "action": "getbalance", "json": 1},
timeout=10,
)
data = resp.json()
if data.get("status") == 1:
return float(data["request"])
raise RuntimeError(f"Balance check failed: {data.get('request')}")
balance = check_balance("YOUR_API_KEY")
print(f"Balance: ${balance:.4f}")
شغّل هذا الفحص يدويًا عند ظهور الخطأ لأول مرة؛ فإذا عاد الرصيد بقيمة صفر تأكدت من السبب فورًا، وإذا ظهر رصيد موجب رغم استمرار الخطأ فالغالب أنك أمام تأخّر في مزامنة الرصيد لا نفاد حقيقي.
التعامل مع الرصيد الصفري دون توقف الأتمتة
بدل أن ينهار السكربت عند نفاد الرصيد، من الأفضل أن يتوقف بشكل مُتحكَّم فيه ويرفع استثناءً واضحًا يمكنك التقاطه. الفئة BalanceAwareSolver تفحص الرصيد قبل الإرسال، وتُخزِّن النتيجة مؤقتًا لخمس دقائق لتقليل الطلبات، وتُميّز بين رصيد منخفض ورصيد صفري عبر استثناءين منفصلين:
import requests
import time
import logging
logger = logging.getLogger(__name__)
class BalanceAwareSolver:
"""Solver that handles zero balance without crashing."""
def __init__(self, api_key, min_balance=0.50):
self.api_key = api_key
self.min_balance = min_balance
self._last_balance_check = 0
self._cached_balance = None
def solve(self, params):
"""Solve CAPTCHA with balance pre-check."""
# Check balance every 5 minutes
if time.time() - self._last_balance_check > 300:
self._check_balance()
if self._cached_balance is not None and self._cached_balance < 0.01:
raise InsufficientBalanceError(
f"Balance too low: ${self._cached_balance:.4f}. "
"Add funds at https://captchaai.com"
)
try:
return self._submit_and_poll(params)
except ZeroBalanceError:
self._cached_balance = 0.0
logger.error("ERROR_ZERO_BALANCE — add funds at captchaai.com")
raise
def _check_balance(self):
"""Check and cache balance."""
try:
resp = requests.get(
"https://ocr.captchaai.com/res.php",
params={
"key": self.api_key,
"action": "getbalance",
"json": 1,
},
timeout=10,
)
data = resp.json()
if data.get("status") == 1:
self._cached_balance = float(data["request"])
self._last_balance_check = time.time()
if self._cached_balance < self.min_balance:
logger.warning(
f"Low balance: ${self._cached_balance:.4f} "
f"(threshold: ${self.min_balance:.2f})"
)
except Exception as e:
logger.debug(f"Balance check failed: {e}")
def _submit_and_poll(self, params):
"""Submit task and poll for result."""
data = {"key": self.api_key, "json": 1, **params}
resp = requests.post(
"https://ocr.captchaai.com/in.php", data=data, timeout=30,
)
result = resp.json()
if result.get("status") != 1:
error = result.get("request", "")
if error == "ERROR_ZERO_BALANCE":
raise ZeroBalanceError("Account balance is zero")
raise RuntimeError(f"Submit failed: {error}")
task_id = result["request"]
time.sleep(10)
for _ in range(24):
resp = requests.get(
"https://ocr.captchaai.com/res.php",
params={
"key": self.api_key, "action": "get",
"id": task_id, "json": 1,
},
timeout=15,
)
data = resp.json()
if data.get("status") == 1:
return data["request"]
if data["request"] != "CAPCHA_NOT_READY":
raise RuntimeError(data["request"])
time.sleep(5)
raise TimeoutError("Solve timeout")
class ZeroBalanceError(Exception):
"""Raised when account has no balance."""
pass
class InsufficientBalanceError(Exception):
"""Raised when balance is below minimum threshold."""
pass
الفكرة الجوهرية هنا هي الفصل بين حالتَي «رصيد منخفض» و«رصيد صفري»: الأولى تحذير مبكر يتيح لك التصرف، والثانية توقف صريح يمكن للكود الأعلى منه أن يقرّر كيف يتعامل معه.
مراقبة الرصيد وإرسال تنبيهات مبكرة
الفحص اليدوي يفيد وقت الأزمة، لكن الحماية الحقيقية تأتي من مراقبة دورية تعمل في الخلفية. الفئة BalanceMonitor تُشغّل خيط معالجة (Thread) مستقلًّا يستطلع الرصيد على فترات، ويُطلق تحذيرًا عند نزوله تحت حدّ معيّن، وإنذارًا حرجًا عند وصوله إلى الصفر. استبدل الدالة _send_alert بقناة التنبيه التي تناسبك: بريد إلكتروني، أو Webhook إلى Slack:
import smtplib
from email.message import EmailMessage
import threading
import time
import logging
logger = logging.getLogger(__name__)
class BalanceMonitor:
"""Monitor balance and send alerts when low."""
def __init__(self, api_key, alert_threshold=1.00, check_interval=600):
self.api_key = api_key
self.alert_threshold = alert_threshold
self.check_interval = check_interval
self._alert_sent = False
self._running = False
def start(self):
"""Start background monitoring."""
self._running = True
thread = threading.Thread(target=self._monitor_loop, daemon=True)
thread.start()
logger.info("Balance monitor started")
def stop(self):
"""Stop monitoring."""
self._running = False
def _monitor_loop(self):
"""Check balance periodically."""
while self._running:
try:
balance = self._get_balance()
logger.info(f"Balance: ${balance:.4f}")
if balance <= 0:
self._send_alert("CRITICAL: CaptchaAI Zero Balance",
f"Balance is ${balance:.4f}. Solving will fail.")
elif balance < self.alert_threshold and not self._alert_sent:
self._send_alert("WARNING: CaptchaAI Low Balance",
f"Balance: ${balance:.4f} (threshold: ${self.alert_threshold:.2f})")
self._alert_sent = True
elif balance >= self.alert_threshold:
self._alert_sent = False # Reset alert flag
except Exception as e:
logger.error(f"Monitor error: {e}")
time.sleep(self.check_interval)
def _get_balance(self):
"""Check account balance."""
resp = requests.get(
"https://ocr.captchaai.com/res.php",
params={"key": self.api_key, "action": "getbalance", "json": 1},
timeout=10,
)
data = resp.json()
if data.get("status") == 1:
return float(data["request"])
raise RuntimeError(data.get("request"))
def _send_alert(self, subject, body):
"""Send email alert. Replace with your notification method."""
logger.critical(f"{subject}: {body}")
# Implement email, Slack webhook, or other notification here
# Usage
monitor = BalanceMonitor("YOUR_API_KEY", alert_threshold=2.00)
monitor.start()
نصيحة عملية للسوق العربي: اضبط حدّ التنبيه (alert_threshold) على قيمة تكفي استهلاك يوم أو يومَي عمل كاملين، لأن التحويلات البنكية قد لا تُعتمد قبل ذلك، وتحديدًا حول عطلة نهاية الأسبوع. حدّ منخفض جدًّا يعني أن التنبيه يصلك متأخرًا بعد أن يكون الرصيد قد اقترب فعلًا من الصفر.
تقدير التكلفة قبل تشغيل الدُفعات الكبيرة
قبل إطلاق دُفعة ضخمة، من الحكمة أن تتأكد أن رصيدك يغطّيها بدل أن تكتشف نفاده في المنتصف. الدالة التالية تقارن الرصيد الحالي بتكلفة تقديرية للدُفعة. القيم في COST_PER_SOLVE تقديرية لأغراض التخطيط فقط، والفوترة الفعلية تتبع خطتك في CaptchaAI:
# Approximate costs per CAPTCHA type
COST_PER_SOLVE = {
"recaptcha_v2": 0.003,
"recaptcha_v3": 0.004,
"turnstile": 0.002,
"geetest": 0.003,
"image": 0.001,
"bls": 0.002,
}
def estimate_cost(captcha_type, quantity):
"""Estimate cost for a batch of solves."""
rate = COST_PER_SOLVE.get(captcha_type, 0.003)
total = rate * quantity
return total
def check_budget(api_key, captcha_type, planned_solves):
"""Check if balance covers planned solves."""
balance = check_balance(api_key)
estimated = estimate_cost(captcha_type, planned_solves)
if balance >= estimated:
print(f"Budget OK: ${balance:.4f} covers ~{int(balance / COST_PER_SOLVE[captcha_type])} solves")
return True
else:
shortfall = estimated - balance
print(f"Need ${shortfall:.4f} more for {planned_solves} {captcha_type} solves")
return False
# Check before a large batch
check_budget("YOUR_API_KEY", "recaptcha_v2", 5000)
اجعل هذا الفحص جزءًا من خطوة ما قبل التشغيل في خط الأتمتة لديك، بحيث ترفض المهمة الانطلاق أصلًا إذا كان الرصيد لا يكفي، بدل أن تتعثّر بعد آلاف الطلبات.
التدهور الرشيق عند نفاد الرصيد
حتى مع المراقبة، قد يصل الرصيد إلى الصفر في منتصف مهمة حرجة. هنا يأتي دور التدهور الرشيق: بدل أن ينهار البرنامج، يتصرّف وفق سياسة تحدّدها أنت. الفئة GracefulSolver تبني على BalanceAwareSolver وتمنحك ثلاثة خيارات — تخطّي العنصر (skip)، أو وضعه في قائمة انتظار (queue)، أو رفع استثناء يوقف الأتمتة (raise):
class GracefulSolver:
"""Fall back to manual or skip when balance is zero."""
def __init__(self, api_key, on_zero_balance="skip"):
self.api_key = api_key
self.on_zero_balance = on_zero_balance # "skip", "queue", "raise"
self._pending_queue = []
self.solver = BalanceAwareSolver(api_key)
def solve_or_degrade(self, params, item_id=None):
"""Try to solve, degrade gracefully on zero balance."""
try:
return self.solver.solve(params)
except (ZeroBalanceError, InsufficientBalanceError):
return self._handle_zero(params, item_id)
def _handle_zero(self, params, item_id):
"""Handle zero balance based on configured strategy."""
if self.on_zero_balance == "skip":
logger.warning(f"Skipping CAPTCHA for item {item_id} — no balance")
return None
elif self.on_zero_balance == "queue":
self._pending_queue.append({"params": params, "item_id": item_id})
logger.info(f"Queued item {item_id} — {len(self._pending_queue)} pending")
return None
else: # "raise"
raise ZeroBalanceError("No balance — stopping automation")
def retry_pending(self):
"""Retry queued items after balance is refilled."""
if not self._pending_queue:
return []
results = []
remaining = []
for item in self._pending_queue:
try:
token = self.solver.solve(item["params"])
results.append({"item_id": item["item_id"], "token": token})
except (ZeroBalanceError, InsufficientBalanceError):
remaining.append(item)
break # Stop retrying — still no balance
self._pending_queue = remaining + self._pending_queue[len(results) + len(remaining):]
return results
استراتيجية queue مفيدة تحديدًا في سيناريو نهاية الأسبوع الذي بدأنا به: العناصر المتعثّرة لا تضيع، بل تنتظر في الطابور، وبمجرد أن تعيد شحن الرصيد تستدعي retry_pending لإكمالها من حيث توقفت.
الخطط الشهرية القائمة على الـ Threads بديلًا عن مراقبة الرصيد
مراقبة رصيد متناقص حلٌّ عملي، لكنه ليس الوحيد. تتيح CaptchaAI خططًا شهرية تُحاسَب على عدد الـ Threads المتزامنة لا على كل عملية حل، فتُجدّد اشتراكك في موعد ثابت بدل متابعة رصيد قد ينفد في أسوأ لحظة. تبدأ الخطة BASIC من 15$ شهريًا بخمسة Threads، وترتفع عبر STANDARD (30$، 15 Thread) وADVANCE (90$، 50 Thread) وصولًا إلى فئات VIP الأعلى مثل VIP-3 (7,500$، 5,000 Thread). وكل خطة تشمل عددًا غير محدود من الحلول لكل Thread طوال الشهر، ما يجعل التكلفة الشهرية ثابتة ومتوقّعة — وهي ميزة مهمة للفرق التي تريد ميزانية واضحة تُراجَع في captchaai.com بدل مفاجآت نفاد الرصيد.
جدول تشخيص الأعطال الشائعة
عندما يستمر الخطأ رغم المعالجة، استعن بالجدول التالي لربط العَرَض بسببه الأرجح وحلّه:
| العَرَض | السبب المحتمل | الحل |
|---|---|---|
| ظهور ERROR_ZERO_BALANCE على كل طلب | الحساب فارغ تمامًا | أضف رصيدًا من موقع captchaai.com |
| انخفاض الرصيد بسرعة غير متوقعة | مفتاح API مكشوف أو كود غير فعّال | دوّر المفتاح وراجع سجلات الاستخدام |
| رصيد موجب لكن الخطأ مستمر | تأخّر في التخزين المؤقت أو المزامنة | انتظر دقيقة واحدة ثم أعد المحاولة |
| تعذّر إضافة رصيد | مشكلة في طريقة الدفع | حدّث طريقة الدفع في لوحة التحكم |
الأسئلة الشائعة
هل يوقف ERROR_ZERO_BALANCE المهام قيد التنفيذ بالفعل؟
لا يؤثر الخطأ على المهام التي أُرسلت وبدأت معالجتها بالفعل؛ فهو يمنع فقط قبول طلبات جديدة. لهذا يفيد نمط قائمة الانتظار في حفظ العناصر الجديدة حتى تعيد الشحن.
كيف أفرّق بين نفاد الرصيد الفعلي وتأخّر تحديثه؟
شغّل دالة فحص الرصيد مباشرة: إذا أعادت صفرًا فالنفاد حقيقي، أما إذا أظهرت رصيدًا موجبًا مع استمرار الخطأ فالسبب غالبًا تأخّر مزامنة مؤقت يزول خلال دقيقة تقريبًا.
هل تُحتسب المحاولات الفاشلة على رصيدي؟
لا يُخصم من رصيدك مقابل المحاولات التي تفشل ولا تُرجع رمزًا؛ الخصم يقابل الحلول الناجحة التي تُعيد رمزًا أو إجابة فقط.
ما القيمة المناسبة لحدّ التنبيه بالرصيد؟
اختر حدًّا يغطّي استهلاك يوم أو يومَي عمل كاملين على الأقل، حتى يصلك التنبيه ويكتمل أي تحويل بنكي قبل أن يلامس الرصيد الصفر فعليًّا.
أدلة ذات صلة
لا تدع رصيدك يصل إلى الصفر — اشحن حساب CaptchaAI الآن.