المقارنات

الجلسات الثابتة مقابل الجلسات الدورية: أفضل استراتيجية وكيل لاختبارات CAPTCHA

القاعدة العملية أوضح مما تبدو: كل تدفق يمتد لأكثر من طلب ويحمل رمز CAPTCHA يحتاج جلسة ثابتة تُبقي عنوان IP نفسه حتى إرسال النموذج، وكل قراءة مستقلة لصفحة واحدة تعمل أفضل مع التدوير.

الخطأ المتكرر ليس اختيار مزود وكيل ضعيف، بل تشغيل المشروع كله على وضع واحد ثم تفسير ارتفاع معدل CAPTCHA بأسباب أخرى.

الخلاصة في ثلاثة بنود

  • الجلسة الثابتة — عنوان واحد لنافذة محددة: للدخول والدفع وأي نموذج يحمل CAPTCHA.
  • الجلسة الدورية — عنوان جديد لكل طلب: للجمع بالجملة ومراقبة الأسعار.
  • الوضع الهجين — قاعدة توجيه في الكود تختار الوضع لكل طلب.

مصفوفة القرار: أي وضع لأي سير عمل؟

سير العمل الوضع السبب
تسجيل الدخول والاشتراك ثابتة الرمز مرتبط بالعنوان
إتمام الشراء والدفع ثابتة ملفات الجلسة تتبع العنوان
إرسال نموذج يتضمن CAPTCHA ثابتة ربط الرمز بالعنوان
جمع بيانات الصفحات بالجملة دورية يوزّع الحمل
مراقبة الأسعار دورية طلبات مستقلة

إن غاب سير عملك عن الجدول فاسأل: هل يحمل الطلب التالي حالة من سابقه — رمز أو ملف تعريف ارتباط؟ نعم تعني جلسة ثابتة، ولا تعني تدويراً.

كيف يختلف الوضعان على مستوى عنوان IP

STICKY SESSION:
  Request 1 ──▶ IP: 192.168.1.50 ──▶ site.com/login
  Request 2 ──▶ IP: 192.168.1.50 ──▶ site.com/dashboard
  Request 3 ──▶ IP: 192.168.1.50 ──▶ site.com/account
  (Same IP for all requests in the session window)

ROTATING SESSION:
  Request 1 ──▶ IP: 192.168.1.50 ──▶ site.com/page1
  Request 2 ──▶ IP: 10.0.0.77   ──▶ site.com/page2
  Request 3 ──▶ IP: 172.16.5.22 ──▶ site.com/page3
  (Different IP per request)

الفارق في المخطط بسيط، لكن أثره يظهر في طبقة التحقق: تقيّم خدمات مثل reCAPTCHA v2 وCloudflare Turnstile سياق الطلب كاملاً، وتغيّر العنوان داخل تدفق واحد يجعل الطلبات تبدو صادرة عن أجهزة مختلفة.

مقارنة مباشرة بين الوضعين

الأرقام التالية تستند إلى بيانات مرصودة وتقارير مستخدمين. قد تختلف النتائج بحسب بيئة التشغيل والحجم والتوقيت.

العامل الجلسة الثابتة الجلسة الدورية
عنوان IP لكل طلب ثابت من 1 إلى 30 دقيقة جديد لكل طلب
معدل CAPTCHA في التدفقات متعددة الخطوات منخفض — 5-10% مرتفع — 30-50%
معدل CAPTCHA في الصفحات المفردة متوسط — 10-20% منخفض — 5-10%
صلاحية الرمز بعد الحل أعلى — العنوان نفسه خطر عدم التطابق
الأنسب لـ المصادقة والدفع الجمع بالجملة والبحث

متى تفوز الجلسات الثابتة في تدفقات CAPTCHA؟

التدفقات متعددة الخطوات: الدخول وإتمام الشراء

يُتحقق من الرمز مقابل عنوان IP الذي صدر عنه الطلب؛ فإذا تغيّر العنوان بين الحل والإرسال قد يُرفض الرمز وتدفع تكلفة حل جديد دون أن يكتمل المسار. المثال التالي يثبّت الجلسة على عنوان واحد طوال تدفق الدخول:

import requests
import time

CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"

# Sticky session: same IP for the entire login flow
STICKY_PROXY = {
    "http": "http://user-session-abc123:[email protected]:5000",
    "https": "http://user-session-abc123:[email protected]:5000",
}

session = requests.Session()
session.proxies = STICKY_PROXY
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
})


def login_with_captcha(url, sitekey, username, password):
    """Full login flow — MUST use same IP throughout."""
    # Step 1: Load login page (IP: 192.168.1.50)
    session.get(url)

    # Step 2: Solve CAPTCHA (solved against IP: 192.168.1.50)
    token = solve_recaptcha(sitekey, url)

    # Step 3: Submit login (MUST be IP: 192.168.1.50)
    resp = session.post(url, data={
        "username": username,
        "password": password,
        "g-recaptcha-response": token,
    })

    return resp.status_code == 200


def solve_recaptcha(sitekey, pageurl):
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    })
    task_id = resp.json()["request"]

    for _ in range(60):
        time.sleep(5)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        data = result.json()
        if data["request"] != "CAPCHA_NOT_READY":
            return data["request"]

    raise TimeoutError("CAPTCHA solve timeout")

كائن session يحمل الوكيل والترويسات معاً؛ إنشاء جلسة requests جديدة في منتصف المسار يعيدك إلى نقطة البداية حتى لو بقي الوكيل نفسه.

لماذا يهمّ ثبات العنوان بعد الحل

المخطط التالي يلخّص ما يراه الخادم في الحالتين، وهو الفرق بين رمز مقبول ورمز مرفوض:

Sticky session:

  1. Browser loads page    → IP: 5.5.5.5
  2. CAPTCHA solved        → Token bound to session
  3. Form submitted        → IP: 5.5.5.5 ✅ Token accepted

Rotating session:

  1. Browser loads page    → IP: 5.5.5.5
  2. CAPTCHA solved        → Token bound to session
  3. Form submitted        → IP: 9.9.9.9 ❌ Token may be rejected

متى تكون الجلسات الدورية هي الخيار الأصح؟

جمع بيانات الصفحات بالجملة

كل صفحة مستقلة ولا تحمل حالة من سابقتها، وتوزيع الطلبات على مجموعة عناوين أوسع يخفض عدد الطلبات لكل عنوان فيقل احتمال ظهور تحدٍّ إضافي:

import concurrent.futures

ROTATING_PROXY = {
    "http": "http://user:[email protected]:5000",
    "https": "http://user:[email protected]:5000",
}


def scrape_page(url):
    """Each request gets a fresh IP automatically."""
    resp = requests.get(
        url,
        proxies=ROTATING_PROXY,
        headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"},
        timeout=30,
    )
    if resp.status_code == 200:
        return url, resp.text
    return url, None


urls = [f"https://example.com/products?page={i}" for i in range(1, 501)]

with concurrent.futures.ThreadPoolExecutor(max_workers=10) as pool:
    results = list(pool.map(scrape_page, urls))
    success = sum(1 for _, html in results if html)
    print(f"Scraped: {success}/{len(urls)}")

استخراج نتائج محركات البحث

تتابع محركات البحث حجم الاستعلامات لكل عنوان IP، والتدوير يُبقي كل عنوان تحت حدود المعدل:

def scrape_search(query, pages=10):
    results = []
    for page in range(pages):
        # Each request → new IP
        resp = requests.get(
            "https://search-engine.example.com/search",
            params={"q": query, "start": page * 10},
            proxies=ROTATING_PROXY,
            timeout=20,
        )
        results.append(resp.text)
        time.sleep(2)
    return results

الوضع الهجين: قاعدة توجيه واحدة

بدل اختيار وضع واحد للمشروع كله، اجعل الكود يقرر لكل طلب على حدة:

class HybridProxyManager:
    """Sticky for multi-step flows, rotating for single requests."""

    def __init__(self, provider_host, username, password, port=5000):
        self.host = provider_host
        self.username = username
        self.password = password
        self.port = port

    def get_rotating_proxy(self):
        return {
            "http": f"http://{self.username}:{self.password}@{self.host}:{self.port}",
            "https": f"http://{self.username}:{self.password}@{self.host}:{self.port}",
        }

    def get_sticky_proxy(self, session_id, duration_min=10):
        sticky_user = f"{self.username}-session-{session_id}-ttl-{duration_min}"
        return {
            "http": f"http://{sticky_user}:{self.password}@{self.host}:{self.port}",
            "https": f"http://{sticky_user}:{self.password}@{self.host}:{self.port}",
        }


proxy_mgr = HybridProxyManager("proxy.example.com", "user", "pass")


def scrape_with_auto_strategy(url, needs_login=False):
    if needs_login:
        # Multi-step → sticky
        import uuid
        session_id = uuid.uuid4().hex[:8]
        proxy = proxy_mgr.get_sticky_proxy(session_id)
    else:
        # Single page → rotating
        proxy = proxy_mgr.get_rotating_proxy()

    return requests.get(url, proxies=proxy, timeout=30)

تخفض هذه البنية الرموز المرفوضة في مسارات الدخول، وتحتفظ بسعة التدوير لما يستفيد منها فعلاً.

التطبيق في Node.js

المنطق نفسه مع Axios: دالة واحدة تبني إعدادات الوكيل بحسب الوضع، ويستدعيها مسار الدخول ومسار الجمع بالجملة.

const axios = require("axios");

const CAPTCHAAI_KEY = "YOUR_API_KEY";
const PROXY_HOST = "proxy.example.com";
const PROXY_PORT = 5000;

function getProxy(mode, sessionId = null) {
  const user =
    mode === "sticky" ? `user-session-${sessionId}` : "user";

  return {
    proxy: {
      host: PROXY_HOST,
      port: PROXY_PORT,
      auth: { username: user, password: "pass" },
    },
  };
}

// Rotating: bulk scrape
async function scrapePages(urls) {
  const results = [];
  for (const url of urls) {
    const config = getProxy("rotating");
    const resp = await axios.get(url, { ...config, timeout: 30000 });
    results.push({ url, data: resp.data });
  }
  return results;
}

// Sticky: login flow
async function loginFlow(loginUrl, sitekey, credentials) {
  const sessionId = Date.now().toString(36);
  const config = getProxy("sticky", sessionId);

  // Step 1: Load page
  await axios.get(loginUrl, config);

  // Step 2: Solve CAPTCHA
  const submitResp = await axios.post(
    "https://ocr.captchaai.com/in.php",
    null,
    {
      params: {
        key: CAPTCHAAI_KEY,
        method: "userrecaptcha",
        googlekey: sitekey,
        pageurl: loginUrl,
        json: 1,
      },
    }
  );
  const taskId = submitResp.data.request;

  let token;
  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const res = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: CAPTCHAAI_KEY, action: "get", id: taskId, json: 1 },
    });
    if (res.data.request !== "CAPCHA_NOT_READY") {
      token = res.data.request;
      break;
    }
  }

  // Step 3: Submit with same IP
  return axios.post(
    loginUrl,
    {
      ...credentials,
      "g-recaptcha-response": token,
    },
    config
  );
}

ضبط مدة الجلسة الثابتة TTL

  • دقيقة واحدة — إرسال نموذج سريع؛ الخطر انتهاء المهلة داخل التدفق.
  • 5 دقائق — دخول قياسي وإجراء بعده؛ التوازن الأفضل عملياً.
  • 10 دقائق — تدفقات متعددة الصفحات؛ خطر حظر متوسط.
  • 30 دقيقة فأكثر — جلسات ممتدة؛ أعلى خطر حظر.

القاعدة الأساسية: اضبط المدة على ضعف الزمن المتوقع للتدفق. مهلة أقصر تكسر المسار في منتصفه، وأطول من اللازم تُراكم نشاطاً على عنوان واحد.

سيناريو من السوق العربي: موسم الجمعة البيضاء

فريق تشغيل في متجر إلكتروني خليجي يستعد للموسم، وأمامه مهمتان في الأسبوع نفسه:

  • مراقبة الكتالوج والمخزون عبر آلاف الطلبات المستقلة على صفحات المنتجات العامة: التدوير هو الخيار، وتثبيت الجلسة هنا يكدّس آلاف الطلبات على عنوان واحد فيرفع احتمال وسمه سريعاً.
  • اختبار مسار الشراء ضمن اختبارات الجودة — دخول، ثم سلة، ثم دفع تجريبي خلف نموذج يحمل CAPTCHA: جلسة ثابتة بعشر دقائق تكفي.

ويبقى اعتبار محلي كثيراً ما يُنسى: عقد خروج قريبة من جمهور المتجر تقصّر زمن الاستجابة وتقلّل احتمال انتهاء مهلة الجلسة قبل الإرسال.

أخطاء شائعة وكيفية تشخيصها

العَرَض السبب الأرجح الإجراء
رفض الرمز بعد حل ناجح تغيّر العنوان قبل الإرسال انقل التدفق إلى جلسة ثابتة
ارتفاع معدل CAPTCHA على صفحات مفردة عنوان ثابت يطرق صفحات كثيرة حوّل الطلبات إلى التدوير
حظر عنوان داخل جلسة ثابتة طلبات كثيرة على عنوان موسوم قلّل TTL أو أضف فواصل زمنية

أسئلة شائعة

ما القيمة المناسبة لمدة TTL في تدفق يتضمن حل CAPTCHA؟

احسب زمن التدفق فعلياً — تحميل الصفحة، ثم الحل، ثم الإرسال — واضربه في اثنين؛ في تدفق دخول نموذجي تكفي 5 دقائق.

لماذا يُرفض الرمز رغم أن الخدمة أعادته بنجاح؟

غالباً لأن الرمز أُرسل من عنوان IP غير الذي حُلّ عليه، أو لأن صلاحيته انتهت قبل الإرسال. ثبّت الجلسة أولاً، ثم قلّص الفجوة بين استلام الرمز وإرساله.

هل يرفع التدوير فاتورة CaptchaAI؟

تعتمد الخطط على عدد الـ threads المتزامنة لا على عدد عمليات الحل، مع حل غير محدود لكل thread شهرياً: خطة BASIC بسعر $15 تتيح 5 threads، وSTANDARD بسعر $30 تتيح 15 thread. ما يغيّره وضع الجلسة هو حجم العمل لا سعر الوحدة.

هل تصلح وكلاء مراكز البيانات للجلسات الثابتة؟

تصلح للمسارات الداخلية واختبارات الجودة على أنظمتك، لكن نطاقاتها معروفة ومصنّفة، ما يرفع احتمال ظهور تحدٍّ إضافي. راجع تكامل Oxylabs لوكلاء مراكز البيانات وإعداد Smartproxy السكني ودليل Bright Data لمعرفة صيغة معرّف الجلسة عند كل مزود.

كيف أتأكد أن استراتيجية الجلسة هي سبب ارتفاع معدل CAPTCHA؟

شغّل التدفق نفسه مرتين بالمدخلات نفسها، مرة بجلسة ثابتة ومرة بالتدوير، وسجّل عدد الاختبارات لكل مئة طلب. إن تساوى التشغيلان فالسبب في مكان آخر: الترويسات أو إيقاع الإرسال.

أدلة ذات صلة

طابق استراتيجية الوكيل مع طبيعة كل تدفق، ثم احصل على مفتاح CaptchaAI وشغّل أول مسار كامل بجلسة ثابتة.

التعليقات غير مفعّلة لهذا المقال.