تراقب خط أنابيب حل CAPTCHA لحظة بلحظة عبر إرسال تنبيهاته إلى قناة Discord باستخدام Webhook: تحذير عند انخفاض الرصيد، إشعار فوري عند ارتفاع معدل الأخطاء، وملخّص يومي لمعدل النجاح والتكلفة. لا حاجة إلى بناء لوحة مراقبة منفصلة أو فتح لوحة التحكم يدوياً كل ساعة — يصل الإشعار إلى المكان الذي يعمل فيه فريقك أصلاً. في هذا الدليل تبني نظام تنبيهات كاملاً بـ Python وJavaScript يستطلع رصيد CaptchaAI ومعدل الأخطاء، ثم يدفع النتائج إلى Discord عبر تضمينات (embeds) ملوّنة.
يغطّي النظام أربعة أنواع من التنبيهات، كلٌّ منها يقابل دالّة في الكود أدناه:
- تنبيه الرصيد: يُطلق تحذيراً عند هبوط الرصيد تحت عتبة محددة (مثلاً $10)، وتنبيه خطأ حرج تحت $2.
- ارتفاع معدل الأخطاء: يراقب آخر خمس دقائق ويُشعر عند تجاوز نسبة الفشل 15%.
- تكدّس قائمة الانتظار: ينبّه عند تراكم المهام مع تقدير زمن التصريف.
- الملخص اليومي: تقرير مجدول بمعدل النجاح ومتوسط الكمون والتكلفة والرصيد وأعلى عمق لقائمة الانتظار.
لماذا تُرسل تنبيهات خط أنابيب CAPTCHA إلى Discord؟
عندما يعمل خط أنابيب حل CAPTCHA على أحجام كبيرة، فإن أكثر ما يؤلم ليس فشل طلب واحد، بل اكتشاف تعطّل الخط بعد فوات الأوان — نفاد الرصيد في منتصف الليل، أو ارتفاع مفاجئ في رمز خطأ مثل ERROR_CAPTCHA_UNSOLVABLE يوقف جمع البيانات دون أن ينتبه أحد.
تخيّل فريق بيانات في القاهرة أو الرياض يشغّل مهمة استخراج بيانات ليلية تعتمد على حل CAPTCHA. لو نفد الرصيد الساعة الثالثة فجراً، فالفرق بين خسارة الليلة كاملة وبين معالجة سريعة هو إشعار واحد يصل إلى هاتف المسؤول. Discord يوفّر هذا: إشعارات فورية على الجوّال وسطح المكتب، قنوات منفصلة لكل بيئة، وتضمينات غنية تعرض الرصيد ومعدل الخطأ ووقت الحل في رسالة واحدة واضحة.
مقارنةً ببناء واجهة مراقبة مخصّصة، يستغرق ربط Webhook دقائق، ولا يتطلب استضافة إضافية، ويستفيد من التطبيق الذي يفتحه المطوّرون طوال اليوم. استخدم Discord قناةً للرؤية الجماعية، مع الإبقاء على أداة نداء مخصّصة (on-call) للحالات الحرجة التي تتطلب استدعاءً فورياً.
إعداد Discord Webhook
- افتح إعدادات خادم Discord
- انتقل إلى Integrations → Webhooks
- انقر New Webhook وسمِّه "CaptchaAI Alerts"
- انسخ عنوان URL الخاص بالـ Webhook
- خزّنه في متغيّر البيئة
DISCORD_WEBHOOK_URL
خزّن مفتاح الـ API في متغيّر بيئة منفصل باسم CAPTCHAAI_API_KEY ولا تضعه في الكود مباشرةً؛ هذا يحمي بيانات الاعتماد ويسهّل تدوير المفاتيح لاحقاً دون تعديل السكربت.
Python — نظام تنبيهات CaptchaAI عبر Discord
يبني الكود التالي فئة DiscordCaptchaAlerts لصياغة التضمينات الملوّنة، وفئة PipelineMonitor تستطلع الرصيد كل خمس دقائق وتحسب معدل الأخطاء خلال آخر خمس دقائق، مع مهلة تهدئة (cooldown) تمنع إغراق القناة بالإشعارات المتكررة.
import os
import time
import requests
from datetime import datetime
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
DISCORD_WEBHOOK = os.environ["DISCORD_WEBHOOK_URL"]
session = requests.Session()
class DiscordCaptchaAlerts:
COLORS = {
"success": 0x2ECC71, # Green
"warning": 0xF39C12, # Orange
"error": 0xE74C3C, # Red
"info": 0x3498DB, # Blue
}
def __init__(self, webhook_url):
self.webhook_url = webhook_url
def send_embed(self, title, description, color_key="info", fields=None):
embed = {
"title": title,
"description": description,
"color": self.COLORS.get(color_key, self.COLORS["info"]),
"timestamp": datetime.utcnow().isoformat() + "Z",
"footer": {"text": "CaptchaAI Pipeline Monitor"}
}
if fields:
embed["fields"] = fields
payload = {"embeds": [embed]}
resp = requests.post(
self.webhook_url, json=payload, timeout=10
)
resp.raise_for_status()
def balance_alert(self, balance, threshold):
severity = "error" if balance < 2 else "warning"
self.send_embed(
title="💰 Balance Alert",
description=f"CaptchaAI balance is **${balance:.2f}**",
color_key=severity,
fields=[
{"name": "Threshold", "value": f"${threshold:.2f}", "inline": True},
{"name": "Severity", "value": severity.upper(), "inline": True},
{"name": "Action", "value": "Top up your balance at captchaai.com", "inline": False}
]
)
def error_spike(self, error_rate, error_count, total_count, top_errors):
error_list = "\n".join(
f"• `{code}`: {count}" for code, count in top_errors.items()
)
self.send_embed(
title="⚠️ Error Rate Spike",
description=f"Error rate: **{error_rate:.1%}** ({error_count}/{total_count})",
color_key="error",
fields=[
{"name": "Error Breakdown", "value": error_list or "No details", "inline": False},
{"name": "Window", "value": "Last 5 minutes", "inline": True}
]
)
def queue_alert(self, depth, workers_active):
self.send_embed(
title="📊 Queue Backup",
description=f"Queue depth: **{depth}** pending tasks",
color_key="warning",
fields=[
{"name": "Active Workers", "value": str(workers_active), "inline": True},
{"name": "Est. Drain Time", "value": f"{depth // max(workers_active, 1)} min", "inline": True}
]
)
def daily_summary(self, stats):
self.send_embed(
title="📈 Daily CAPTCHA Summary",
description=f"**{stats['total']}** tasks processed",
color_key="success" if stats["success_rate"] > 0.92 else "warning",
fields=[
{"name": "Success Rate", "value": f"{stats['success_rate']:.1%}", "inline": True},
{"name": "Avg Latency", "value": f"{stats['avg_latency']:.1f}s", "inline": True},
{"name": "Total Cost", "value": f"${stats['cost']:.2f}", "inline": True},
{"name": "Errors", "value": str(stats["errors"]), "inline": True},
{"name": "Balance", "value": f"${stats['balance']:.2f}", "inline": True},
{"name": "Peak Queue", "value": str(stats["peak_queue"]), "inline": True},
]
)
def solve_recovered(self, previous_rate, current_rate):
self.send_embed(
title="✅ Pipeline Recovered",
description=f"Solve rate recovered: {previous_rate:.1%} → {current_rate:.1%}",
color_key="success"
)
alerts = DiscordCaptchaAlerts(DISCORD_WEBHOOK)
class PipelineMonitor:
def __init__(self, check_interval=60):
self.check_interval = check_interval
self.results = [] # (timestamp, success, error_code)
self.last_balance_alert = 0
self.last_error_alert = 0
self.cooldown = 300 # 5 minutes between alerts
def record(self, success, error_code=None):
self.results.append((time.time(), success, error_code))
# Keep last 5 min
cutoff = time.time() - 300
self.results = [r for r in self.results if r[0] > cutoff]
def run_checks(self):
now = time.time()
# Balance check
if now - self.last_balance_alert > self.cooldown:
balance = self._check_balance()
if balance is not None and balance < 10:
alerts.balance_alert(balance, threshold=10)
self.last_balance_alert = now
# Error rate check
if now - self.last_error_alert > self.cooldown and len(self.results) > 10:
total = len(self.results)
errors = [r for r in self.results if not r[1]]
error_rate = len(errors) / total
if error_rate > 0.15:
error_breakdown = {}
for _, _, code in errors:
if code:
error_breakdown[code] = error_breakdown.get(code, 0) + 1
alerts.error_spike(error_rate, len(errors), total, error_breakdown)
self.last_error_alert = now
def _check_balance(self):
try:
resp = session.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "getbalance", "json": 1
})
data = resp.json()
if data.get("status") == 1:
return float(data["request"])
except Exception:
pass
return None
monitor = PipelineMonitor()
استدعِ monitor.record(success, error_code) بعد كل محاولة حل، وmonitor.run_checks() بشكل دوري داخل حلقة المراقبة؛ يتكفّل الباقي بحساب النسب وإرسال التنبيه عند الحاجة فقط.
JavaScript — عميل إرسال التنبيهات إلى Discord
إن كان خط أنابيبك يعمل على Node.js، فهذا المكافئ يستخدم Axios لإرسال التضمينات نفسها ويشغّل حلقة استطلاع للرصيد كل خمس دقائق عبر setInterval.
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY;
const DISCORD_WEBHOOK = process.env.DISCORD_WEBHOOK_URL;
const COLORS = {
success: 0x2ecc71,
warning: 0xf39c12,
error: 0xe74c3c,
info: 0x3498db,
};
async function sendDiscordEmbed(title, description, colorKey = "info", fields = []) {
await axios.post(DISCORD_WEBHOOK, {
embeds: [
{
title,
description,
color: COLORS[colorKey] || COLORS.info,
timestamp: new Date().toISOString(),
footer: { text: "CaptchaAI Pipeline Monitor" },
fields,
},
],
}, { timeout: 10000 });
}
async function alertBalance(balance, threshold = 10) {
const severity = balance < 2 ? "error" : "warning";
await sendDiscordEmbed(
"💰 Balance Alert",
`CaptchaAI balance is **$${balance.toFixed(2)}**`,
severity,
[
{ name: "Threshold", value: `$${threshold.toFixed(2)}`, inline: true },
{ name: "Severity", value: severity.toUpperCase(), inline: true },
]
);
}
async function alertErrorSpike(errorRate, details = {}) {
await sendDiscordEmbed(
"⚠️ Error Rate Spike",
`Error rate: **${(errorRate * 100).toFixed(1)}%**`,
"error",
[
{ name: "Total Tasks", value: String(details.total || 0), inline: true },
{ name: "Errors", value: String(details.errors || 0), inline: true },
]
);
}
async function sendDailySummary(stats) {
const color = stats.successRate > 0.92 ? "success" : "warning";
await sendDiscordEmbed(
"📈 Daily CAPTCHA Summary",
`**${stats.total}** tasks processed`,
color,
[
{ name: "Success Rate", value: `${(stats.successRate * 100).toFixed(1)}%`, inline: true },
{ name: "Avg Latency", value: `${stats.avgLatency.toFixed(1)}s`, inline: true },
{ name: "Balance", value: `$${stats.balance.toFixed(2)}`, inline: true },
]
);
}
// Balance monitoring loop
async function monitorBalance() {
try {
const resp = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "getbalance", json: 1 },
});
if (resp.data.status === 1) {
const balance = parseFloat(resp.data.request);
if (balance < 10) await alertBalance(balance);
}
} catch (err) {
console.error("Balance check failed:", err.message);
}
}
setInterval(monitorBalance, 300000); // Every 5 minutes
module.exports = { alertBalance, alertErrorSpike, sendDailySummary };
نماذج من رسائل التنبيه في Discord
الأرقام في الأمثلة التالية توضيحية فقط، وتختلف حسب نوع CAPTCHA وبيئة التشغيل والحجم؛ أجرِ قياساتك الخاصة قبل ضبط العتبات.
تحذير الرصيد:
💰 تنبيه الرصيد رصيد CaptchaAI هو $8.42 العتبة: $10.00 | الخطورة: WARNING
ارتفاع الأخطاء:
⚠️ ارتفاع معدل الأخطاء معدل الخطأ: 22.5% (45/200)
ERROR_CAPTCHA_UNSOLVABLE: 30TIMEOUT: 15
الملخص اليومي:
📈 ملخص CAPTCHA اليومي 12,450 مهمة تمت معالجتها نسبة النجاح: 95.2% | متوسط الكمون: 22.4 ثانية | الرصيد: $142.30
استكشاف الأخطاء ومعالجتها
| المشكلة | السبب المحتمل | الحل |
|---|---|---|
| استجابة 400 Bad Request | بنية التضمين (embed) غير صحيحة | تأكد أن جميع قيم الحقول نصية وأن مصفوفة fields بالتنسيق الصحيح |
| تحديد المعدل 429 Too Many Requests | عدد رسائل كبير في الدقيقة | أضف مهلة تهدئة بين التنبيهات، خمس دقائق كحدّ أدنى |
| اختفاء الـ Webhook | حذفه أحد الأعضاء من الخادم | أنشئ Webhook جديداً وحدّث متغيّر البيئة DISCORD_WEBHOOK_URL |
| التضمينات لا تظهر | مصفوفة embeds مفقودة |
غلّف كائن التضمين داخل {"embeds": [...]} |
الأسئلة الشائعة
كيف أتجنّب حظر معدل الطلبات (429) من Discord؟
يفرض Discord حدوداً على عدد الرسائل لكل Webhook في الدقيقة. اجمع التنبيهات المتشابهة في رسالة واحدة، وأضف مهلة تهدئة لا تقلّ عن خمس دقائق بين الإشعارات كما في متغيّر cooldown بالكود، وتجنّب إرسال إشعار منفصل لكل عملية حل على حدة.
ما الفرق بين Webhook وبوت Discord كامل؟
الـ Webhook مسار أحادي الاتجاه لإرسال الرسائل فقط، لا يحتاج إلى استضافة أو مصادقة معقّدة، ويكفي لمعظم تنبيهات المراقبة. أما البوت الكامل فيتيح تفاعلاً ثنائي الاتجاه (أوامر وأزرار) لكنه يتطلب خادماً دائم التشغيل. لتنبيهات خط الأنابيب، الـ Webhook أبسط وأكفأ.
هل يمكن ذكر مستخدم أو دور (@mention) في التنبيهات الحرجة؟
نعم. أضف الحقل "content": "<@USER_ID>" لذكر مستخدم، أو "content": "<@&ROLE_ID>" لذكر دور، إلى حمولة الطلب، بحيث يصل تنبيه نفاد الرصيد أو تعطّل الخط إلى المسؤول مباشرةً.
ما أنواع CAPTCHA التي يمكن مراقبة خط أنابيبها بهذه الطريقة؟
النظام محايد تجاه نوع CAPTCHA: يراقب أي خط أنابيب يستدعي CaptchaAI، سواء كان يحل reCAPTCHA v2/v3 أو Cloudflare Turnstile وChallenge أو GeeTest v3 أو الصور وgrid وBLS. التنبيهات مبنية على الرصيد ومعدل الأخطاء والكمون، وهي مقاييس مشتركة بين جميع الأنواع المدعومة.
الخطوات التالية
بعد ربط التنبيهات، وسّع خط أنابيبك بأدلة الحل الأساسية:
- ابدأ سريعاً مع CaptchaAI: حلّ أول اختبار CAPTCHA في خمس دقائق
- حلّ reCAPTCHA v2 عبر الـ API خطوة بخطوة
- حلّ Cloudflare Turnstile باستخدام الـ API
- حلّ GeeTest v3 باستخدام الـ API