حالات الاستخدام

التعامل مع اختبار CAPTCHA لمقارنة أسعار الصيدليات

تحمي معظم بوابات الصيدليات صفحات أسعار الأدوية باختبارات CAPTCHA، وأكثرها شيوعاً reCAPTCHA v2 على نماذج البحث. للحصول على السعر برمجياً، يمرّ كل طلب بأربع خطوات ثابتة:

  1. حمّل صفحة البحث واستخرج مفتاح الموقع.
  2. أرسل الاختبار إلى CaptchaAI عبر نقطة النهاية in.php.
  3. استطلع النتيجة كل بضع ثوانٍ حتى تجهز.
  4. أعد إرسال البحث ومعه الرمز المحلول.

يبني هذا الدليل على هذا النمط أداةً تجمع بيانات التسعير من عدة مصادر ضمن سير عمل واحد قابل للتكرار.

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

أين تصادف اختبارات CAPTCHA على بوابات الأدوية

قبل كتابة أي كود، من المفيد رسم خريطة للمواضع التي تظهر فيها الاختبارات ونوعها والمحفّز الذي يُطلقها:

نوع الصفحة اختبار CAPTCHA الشائع ما الذي يُطلقه
نموذج البحث عن الدواء reCAPTCHA v2 كل عملية بحث
صفحة نتائج الأسعار Cloudflare Turnstile الاشتباه في وصول آلي
محدِّد الصيدلية الأقرب reCAPTCHA v2 الاستعلامات حسب الموقع
البحث عن الكوبونات صورة تحقق قبل إظهار رموز الخصم
قائمة أدوية التأمين reCAPTCHA v2 بوابات تسجيل الدخول والبحث

وجميع هذه الأنواع مدعومة في CaptchaAI عبر واجهة واحدة، فلا تحتاج مساراً منفصلاً لكل مزوّد:

  • reCAPTCHA v2 — نماذج البحث ومحدِّد الصيدلية وقوائم التأمين.
  • Cloudflare Turnstile — صفحات نتائج الأسعار.
  • صور التحقق — بوابات الكوبونات والخصومات.

الأساس: حلّ reCAPTCHA v2 ثم إرسال البحث

تبدأ الأداة من أبسط حالة: نموذج بحث محمي بـ reCAPTCHA v2. الدالة أدناه ترسل مفتاح الموقع إلى نقطة النهاية in.php، ثم تستطلع res.php كل ثلاث ثوانٍ حتى تعود الاستجابة جاهزة، وأخيراً تُرفق الرمز مع بيانات البحث وتُعيد إرساله.

import requests
import time

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

def solve_recaptcha(site_key, page_url):
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": "YOUR_API_KEY",
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "json": 1
    })
    task_id = resp.json()["request"]

    for _ in range(60):
        time.sleep(3)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": "YOUR_API_KEY",
            "action": "get",
            "id": task_id,
            "json": 1
        })
        data = result.json()
        if data["status"] == 1:
            return data["request"]
    raise TimeoutError("Solve timed out")

def search_drug_prices(drug_name, zipcode):
    search_url = "https://pharmacy.example.com/search"

    # Load the search page to get the site key
    page = session.get(search_url)

    # Extract reCAPTCHA site key
    import re
    match = re.search(r'data-sitekey="([^"]+)"', page.text)
    site_key = match.group(1)

    # Solve the CAPTCHA
    token = solve_recaptcha(site_key, search_url)

    # Submit the search with token
    results = session.post(search_url, data={
        "drug": drug_name,
        "zip": zipcode,
        "g-recaptcha-response": token
    })

    return parse_prices(results.text)

توسيع الأداة لتشمل عدة صيدليات

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

PHARMACY_SOURCES = [
    {
        "name": "PharmacyA",
        "url": "https://pharmacya.example.com/pricing",
        "captcha_type": "recaptcha_v2"
    },
    {
        "name": "PharmacyB",
        "url": "https://pharmacyb.example.com/drugs",
        "captcha_type": "turnstile"
    },
    {
        "name": "PharmacyC",
        "url": "https://pharmacyc.example.com/search",
        "captcha_type": "image"
    }
]

def compare_drug_price(drug_name, zipcode):
    results = []

    for source in PHARMACY_SOURCES:
        try:
            prices = fetch_prices(
                source["url"],
                source["captcha_type"],
                drug_name,
                zipcode
            )
            results.append({
                "source": source["name"],
                "prices": prices,
                "status": "success"
            })
        except Exception as e:
            results.append({
                "source": source["name"],
                "error": str(e),
                "status": "failed"
            })

    return sorted(results, key=lambda r: r.get("prices", {}).get("lowest", float("inf")))

التعامل مع مزوّدي CAPTCHA المختلفين

لا تعتمد كل البوابات المزوّد نفسه:

  • بعضها يستخدم reCAPTCHA v2.
  • بعضها Cloudflare Turnstile.
  • بعضها صور تحقق تُعرض قبل النتائج.

تختار الدالة التالية مسار الحل المناسب بحسب نوع الاختبار المكتشف على الصفحة، مع الحفاظ على واجهة موحّدة لكل المصادر:

def fetch_prices(url, captcha_type, drug_name, zipcode):
    page = session.get(url)

    if captcha_type == "recaptcha_v2":
        import re
        match = re.search(r'data-sitekey="([^"]+)"', page.text)
        token = solve_recaptcha(match.group(1), url)
        field_name = "g-recaptcha-response"

    elif captcha_type == "turnstile":
        import re
        match = re.search(r'data-sitekey="(0x[^"]+)"', page.text)
        token = solve_turnstile(match.group(1), url)
        field_name = "cf-turnstile-response"

    elif captcha_type == "image":
        img_data = extract_captcha_image(page.text)
        token = solve_image_captcha(img_data)
        field_name = "captcha"

    return session.post(url, data={
        "drug": drug_name,
        "zip": zipcode,
        field_name: token
    })

إدارة الجلسة لتقليل تكرار الاختبارات

تتطلب مقارنة الأسعار عمليات بحث متكررة، وكل اختبار إضافي يعني وقتاً وتكلفة. حافظ على جلسة واحدة تعيد استخدام ملفات تعريف الارتباط، وأعد الحل فقط حين تظهر صفحة اختبار فعلية بدل حلّه استباقياً مع كل طلب. تتتبّع الفئة أدناه عدد عمليات البحث منذ آخر اختبار لتقيس مدى استقرار الجلسة:

class PharmacySession:
    def __init__(self, base_url):
        self.session = requests.Session()
        self.base_url = base_url
        self.searches_since_captcha = 0

    def search(self, drug_name, zipcode):
        result = self.session.post(f"{self.base_url}/search", data={
            "drug": drug_name,
            "zip": zipcode
        })

        if self.is_captcha_page(result.text):
            token = self.solve_page_captcha(result.text)
            result = self.session.post(f"{self.base_url}/search", data={
                "drug": drug_name,
                "zip": zipcode,
                "g-recaptcha-response": token
            })
            self.searches_since_captcha = 0
        else:
            self.searches_since_captcha += 1

        return result

    def is_captcha_page(self, html):
        return "g-recaptcha" in html or "cf-turnstile" in html

    def solve_page_captcha(self, html):
        import re
        match = re.search(r'data-sitekey="([^"]+)"', html)
        return solve_recaptcha(match.group(1), self.base_url)

التنفيذ باستخدام JavaScript

إن كانت أداتك تعمل ضمن بيئة Node.js، فالمثال التالي يعيد المنطق نفسه: حلّ متوازٍ لكل مصدر عبر Promise.all، ثم تصفية العناصر الناجحة وترتيبها حسب السعر:

async function comparePharmacyPrices(drugName, zipCode, sources) {
  const results = await Promise.all(
    sources.map(async (source) => {
      try {
        const price = await fetchDrugPrice(source, drugName, zipCode);
        return { source: source.name, price, status: 'success' };
      } catch (error) {
        return { source: source.name, error: error.message, status: 'failed' };
      }
    })
  );

  return results
    .filter(r => r.status === 'success')
    .sort((a, b) => a.price - b.price);
}

async function fetchDrugPrice(source, drugName, zipCode) {
  // Solve CAPTCHA for this source
  const token = await solveCaptcha(source.siteKey, source.url);

  const response = await fetch(source.url, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      drug: drugName,
      zip: zipCode,
      'g-recaptcha-response': token
    })
  });

  return parsePrice(await response.text());
}

ضبط معدل الطلبات

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

الاستراتيجية التطبيق
المباعدة بين الطلبات 5–10 ثوانٍ بين كل عملية بحث
تدوير الجلسات جلسة جديدة كل 20–30 استعلاماً
تنويع أنماط البحث تجنّب تكرار البحث عن الدواء نفسه بلا انقطاع
اعتماد وكلاء سكنية عناوين IP الخاصة بمراكز البيانات تُطلق اختبارات أكثر

استكشاف الأخطاء الشائعة

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

كم تكلّف تشغيل الأداة؟

تُسعّر CaptchaAI حسب عدد المعالجات المتزامنة، أي الـ threads، لا حسب كل عملية حل، وكل باقة تتيح عدداً غير محدود من عمليات الحل شهرياً ضمن حدود سرعتها. تختار الباقة بحسب عدد المصادر التي تجمع منها في اللحظة نفسها:

  • BASIC — 15 دولاراً شهرياً و5 threads متزامنة؛ مناسبة لأداة تجمع أسعار بضع صيدليات على التوازي.
  • STANDARD — 30 دولاراً شهرياً و15 thread؛ لتغطية أوسع أو جمع يومي أكثف.
  • ADVANCE — 90 دولاراً شهرياً و50 thread؛ لعشرات المصادر المتزامنة.

ولأن الفوترة ثابتة شهرياً وليست لكل عملية حل، تبقى تكلفة مقارنة الأسعار قابلة للتنبؤ حتى مع تقلّب حجم البحث. الأسعار بالدولار الأمريكي، ويمكن مراجعة الباقات المحدّثة على صفحة التسعير الرسمية.

أسئلة شائعة

ما أنواع اختبارات CAPTCHA التي تظهر على بوابات الصيدليات ويدعمها CaptchaAI؟

يدعم CaptchaAI الأنواع التي تصادفها عادةً على بوابات الصيدليات عبر واجهة واحدة:

  • reCAPTCHA v2 وv3 — نماذج البحث ومحدِّد الصيدلية.
  • Cloudflare Turnstile — صفحات نتائج الأسعار.
  • صور التحقق وGeeTest v3 — بوابات الكوبونات وبعض صفحات البحث.

في المقابل لا تدعم CaptchaAI حالياً hCaptcha أو FunCaptcha، فإن صادفت أحدهما على بوابة ما فستحتاج مساراً بديلاً.

كم تبلغ تكلفة تشغيل أداة مقارنة أسعار الأدوية؟

تعتمد التكلفة على عدد المصادر التي تجمع منها بالتوازي، لا على عدد الأدوية التي تبحث عنها. تبدأ باقة BASIC من 15 دولاراً شهرياً بخمسة threads متزامنة وحلّ غير محدود، وهي كافية لمشروع صغير، بينما ينتقل الحجم الأكبر إلى STANDARD بسعر 30 دولاراً أو ما فوقها، مع بقاء الفوترة شهرية ثابتة.

هل جمع أسعار الأدوية آلياً عبر حلّ CAPTCHA مسموح؟

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

كيف أقلّل عدد اختبارات CAPTCHA أثناء البحث المتكرر؟

اجمع بين أربع ممارسات تخفض معدل ظهور الاختبارات وتقلّل الرصيد المستهلك:

  • حافظ على جلسة واحدة تعيد استخدام ملفات تعريف الارتباط.
  • باعِد بين الطلبات 5–10 ثوانٍ.
  • دوّر الجلسة كل 20–30 استعلاماً.
  • استخدم وكلاء سكنية بدل عناوين مراكز البيانات.

الخطوات التالية

أدلة ذات صلة

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