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

تجريف البيانات المالية والتعامل مع CAPTCHA برمجياً

عندما يعترض اختبار reCAPTCHA أو Cloudflare Turnstile سكربت جمع البيانات المالية، لا يعني ذلك توقّف العملية. الحل أن تُدمج داخل السكربت آلية تعامل تلقائية تمرّ بأربع مراحل دون أي تدخل يدوي:

  • اكتشف مفتاح الموقع (sitekey) في صفحة الهدف.
  • أرسله إلى CaptchaAI واطلب حلّ الاختبار المطلوب.
  • استطلع النتيجة دورياً حتى يجهز الرمز.
  • أعد إرسال الطلب نفسه ومعه الرمز، فتستأنف عملية الجمع تلقائياً.

يطبّق هذا الدليل النمط عملياً على فاحصات الأسهم وملفات SEC EDGAR وبيانات السوق المحمية بـ Turnstile، بأمثلة Python جاهزة للتشغيل.


أين تظهر اختبارات CAPTCHA في المواقع المالية

يوضح الجدول التالي أين تصطدم عمليات الجمع بالتحقق ونوع كل اختبار على أبرز المنصات:

المصدر نوع الاختبار ما الذي يشغّله قيمة البيانات
SEC EDGAR reCAPTCHA v2 الطلبات كبيرة الحجم ملفات الشركات
Yahoo Finance reCAPTCHA v2 رصد عمليات الجمع أسعار الأسهم والسجل التاريخي
Bloomberg Cloudflare Turnstile أي وصول آلي بيانات السوق
Finviz reCAPTCHA v2 الدخول إلى فاحص الأسهم نتائج الفرز
TradingView Cloudflare Challenge تحديد معدل الطلبات الرسوم والمؤشرات
Morningstar reCAPTCHA v3 صفحات تصدير البيانات تحليلات الصناديق

سيناريو تطبيقي من السوق الإقليمي

تخيّل فريق بيانات في شركة إدارة أصول بالخليج يبني لوحة متابعة يومية تجمع أسعار الأسهم الأمريكية من فاحصات عامة وملفات SEC EDGAR لعملاء إقليميين يستثمرون في الأسواق العالمية. مع تشغيل السكربت خلال ساعات السوق الأمريكية، تبدأ المواقع بعرض reCAPTCHA وTurnstile بعد عشرات الطلبات. وبدل إيقاف الجمع أو التدخل اليدوي، يمرّر الفريق كل اختبار عبر CaptchaAI ويستأنف الطلب تلقائياً — فتبقى اللوحة محدّثة دون إشراف بشري متواصل.


قلّل ظهور الاختبارات بضبط إيقاع الطلبات

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

  • باعد بين الطلبات، ولا تفتح اتصالات متزامنة كثيرة على النطاق نفسه.
  • ثبّت هوية الجلسة — وكيل مستخدم واقعي وبروكسي سكني — طوال مدة الجمع.
  • اجمع خارج أوقات الذروة، وضمّن بريد جهة الاتصال في وكيل المستخدم على SEC EDGAR.
الإجراء التوصية
تأخير بين الطلبات 2–5 ثوانٍ بين الصفحات
الاتصالات المتزامنة 3–5 كحد أقصى لكل نطاق
نوع البروكسي سكني أو من مزوّد خدمة الإنترنت (ISP)
مدة الجلسة جلسات ثابتة من 5–10 دقائق
وكيل المستخدم واقعي وثابت طوال الجلسة
SEC EDGAR تضمين بريد جهة الاتصال في وكيل المستخدم (مطلوب)
ساعات السوق الجمع خارج أوقات الذروة قدر الإمكان

جمع نتائج فاحص الأسهم

النمط الأساسي واحد: أرسل مفتاح الموقع، استطلع النتيجة، ثم أعد إرسال الطلب ومعه الرمز في الحقل g-recaptcha-response. الدالة solve_captcha والصنف FinancialScraper أدناه يشكّلان الأساس الذي تعيد بقية الأمثلة استخدامه:

import requests
import time
from bs4 import BeautifulSoup
import re

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


def solve_captcha(method, sitekey, pageurl, **kwargs):
    data = {
        "key": CAPTCHAAI_KEY,
        "method": method,
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    }
    data.update(kwargs)

    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data=data)
    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,
        })
        r = result.json()
        if r["request"] != "CAPCHA_NOT_READY":
            return r["request"]

    raise TimeoutError("Solve timeout")


class FinancialScraper:
    def __init__(self, proxy=None):
        self.session = requests.Session()
        if proxy:
            self.session.proxies = {"http": proxy, "https": proxy}
        self.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",
            "Accept-Language": "en-US,en;q=0.9",
        })

    def scrape_screener(self, url):
        """Scrape stock screener, handling CAPTCHA if triggered."""
        resp = self.session.get(url, timeout=30)

        # Check for CAPTCHA
        sitekey_match = re.search(r'data-sitekey="([^"]+)"', resp.text)
        if sitekey_match:
            sitekey = sitekey_match.group(1)
            token = solve_captcha("userrecaptcha", sitekey, url)

            # Resubmit with token
            resp = self.session.post(url, data={
                "g-recaptcha-response": token,
            })

        return self._parse_stocks(resp.text)

    def _parse_stocks(self, html):
        soup = BeautifulSoup(html, "html.parser")
        stocks = []
        for row in soup.select("table.screener-table tr")[1:]:
            cols = row.select("td")
            if len(cols) >= 8:
                stocks.append({
                    "ticker": cols[1].get_text(strip=True),
                    "company": cols[2].get_text(strip=True),
                    "sector": cols[3].get_text(strip=True),
                    "price": cols[6].get_text(strip=True),
                    "change": cols[7].get_text(strip=True),
                })
        return stocks


# Usage
scraper = FinancialScraper(
    proxy="http://user:pass@residential.proxy.com:5000"
)
stocks = scraper.scrape_screener("https://screener.example.com/screener.ashx?v=111")
for stock in stocks[:5]:
    print(f"{stock['ticker']}: {stock['price']} ({stock['change']})")

استخراج ملفات SEC EDGAR

تفرض SEC EDGAR قيدين يجب مراعاتهما معاً في الكود:

  • حدّ على معدل الطلبات، مع عرض اختبار CAPTCHA عند الوصول كبير الحجم.
  • اشتراط وكيل مستخدم يحمل بريد جهة اتصال، وإلا رُفض الطلب بالرمز 403.

الصنف التالي يعالج الحالتين معاً:

import json


class SECFilingScraper:
    BASE_URL = "https://efts.sec.gov/LATEST"

    def __init__(self, user_agent_email, proxy=None):
        self.session = requests.Session()
        if proxy:
            self.session.proxies = {"http": proxy, "https": proxy}
        # SEC requires identifying User-Agent
        self.session.headers.update({
            "User-Agent": f"CompanyName admin@{user_agent_email}",
            "Accept": "application/json",
        })

    def search_filings(self, company, filing_type="10-K"):
        """Search EDGAR for specific filing types."""
        url = f"{self.BASE_URL}/search-index"
        params = {
            "q": company,
            "dateRange": "custom",
            "forms": filing_type,
        }

        resp = self.session.get(url, params=params, timeout=30)

        # Handle CAPTCHA if triggered
        if "captcha" in resp.text.lower() or resp.status_code == 403:
            sitekey = self._extract_sitekey(resp.text)
            if sitekey:
                token = solve_captcha("userrecaptcha", sitekey, url)
                resp = self.session.post(url, data={
                    **params,
                    "g-recaptcha-response": token,
                })

        return resp.json() if resp.status_code == 200 else {}

    def download_filing(self, filing_url):
        """Download individual filing document."""
        resp = self.session.get(filing_url, timeout=60)
        if resp.status_code == 200:
            return resp.text
        return None

    def _extract_sitekey(self, html):
        match = re.search(r'data-sitekey="([^"]+)"', html)
        return match.group(1) if match else None


# Usage
sec = SECFilingScraper(
    user_agent_email="example.com",
    proxy="http://user:pass@proxy.example.com:5000",
)
filings = sec.search_filings("Apple Inc", "10-K")

بيانات السوق المحمية بـ Cloudflare Turnstile

يبقى منطق أرسل/استطلع/استخدم الرمز كما هو، ولا يتغيّر سوى شيئين عند الانتقال إلى مواقع محمية بـ Turnstile:

  • اسم الطريقة يصبح turnstile بدل userrecaptcha.
  • حقل الرمز في إعادة الإرسال يصبح cf-turnstile-response بدل g-recaptcha-response.

يظهر ذلك في الدالة التالية:

def scrape_turnstile_market_data(url, sitekey):
    """Handle Cloudflare Turnstile on financial data sites."""
    token = solve_captcha("turnstile", sitekey, url)

    session = requests.Session()
    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",
    })

    resp = session.post(url, data={
        "cf-turnstile-response": token,
    }, timeout=30)

    return resp.json() if resp.status_code == 200 else None

لقطة يومية مجدولة لبيانات السوق

بعد أن يصبح التعامل مع الاختبار جزءاً من الصنف، يتحوّل الجمع اليومي إلى حلقة بسيطة تمرّ على الرموز وتحفظ النتائج في ملف CSV، مع تأخير قصير بين الطلبات:

import csv
from datetime import datetime


def daily_market_snapshot(tickers, output_dir="data"):
    """Collect daily stock data, handling CAPTCHAs automatically."""
    scraper = FinancialScraper(
        proxy="http://user:pass@residential.proxy.com:5000"
    )

    date_str = datetime.now().strftime("%Y-%m-%d")
    results = []

    for ticker in tickers:
        url = f"https://screener.example.com/quote.ashx?t={ticker}"
        try:
            data = scraper.scrape_screener(url)
            if data:
                results.extend(data)
            time.sleep(2)  # Rate limit
        except Exception as e:
            print(f"Error on {ticker}: {e}")

    # Save to CSV
    filepath = f"{output_dir}/market_{date_str}.csv"
    with open(filepath, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=["ticker", "company", "sector", "price", "change"])
        writer.writeheader()
        writer.writerows(results)

    print(f"Saved {len(results)} records to {filepath}")
    return results


# Run daily
tickers = ["AAPL", "GOOGL", "MSFT", "AMZN", "TSLA"]
daily_market_snapshot(tickers)

حلّ المشكلات الشائعة

المشكلة السبب الحل
خطأ 403 على SEC EDGAR وكيل المستخدم بلا بريد إلكتروني أضف ترويسة CompanyName email@domain
ظهور CAPTCHA في كل طلب تجاوز حد معدل الطلبات أضف تأخيراً 3–5 ثوانٍ بين الطلبات
أسعار قديمة غير محدّثة استجابة مخزّنة مؤقتاً أضف معامل استعلام لكسر التخزين المؤقت
فشل تحليل JSON إرجاع صفحة CAPTCHA بدل البيانات تحقق من وجود CAPTCHA قبل التحليل
حظر عنوان IP طلبات كثيرة من العنوان نفسه بدّل إلى بروكسي سكني دوّار

أسئلة شائعة

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

استخدم بروكسي سكنياً أو من مزوّد خدمة إنترنت (ISP) مع تدوير للعناوين وجلسات ثابتة قصيرة. تُكتشف بروكسيات مراكز البيانات بسرعة على المنصات المالية، ما يرفع تكرار ظهور CAPTCHA ويؤدي إلى حظر العناوين.

كيف أتعامل مع ظهور CAPTCHA أثناء جلسة جمع جارية؟

لا توقف السكربت: استخرج مفتاح الموقع من الصفحة، أرسله إلى CaptchaAI عبر الدالة solve_captcha، ثم أعد إرسال الطلب نفسه مضيفاً الرمز في g-recaptcha-response أو cf-turnstile-response. أما إذا تكرر الاختبار في كل طلب، فالسبب غالباً تجاوز حد المعدل — عندها زد التأخير بين الطلبات.

هل يتعامل CaptchaAI مع reCAPTCHA v3 وCloudflare معاً؟

نعم، يحل CaptchaAI اختبارات reCAPTCHA v2 وv3 وCloudflare Turnstile وCloudflare Challenge، وهي الأنواع الأكثر شيوعاً على مواقع البيانات المالية. يتغيّر اسم الطريقة (method) حسب النوع فقط، بينما يبقى نمط أرسل/استطلع/استخدم الرمز ثابتاً في كل الحالات.

كم تكلفة تشغيل عملية جمع يومية كبيرة الحجم؟

يعتمد تسعير CaptchaAI على عدد الـ Threads المتزامنة لا على عدد عمليات الحل، مع حلول غير محدودة لكل Thread خلال الشهر. تبدأ خطة BASIC من 15$ شهرياً (5 threads)، وترتفع سعة المعالجة المتزامنة في الخطط الأعلى مثل ADVANCE بسعر 90$ شهرياً (50 threads) — ما يجعل تكلفة الجمع اليومي ثابتة ومتوقعة.


أدلة ذات صلة


جمّع بياناتك المالية دون أن يوقفك اختبار CAPTCHA — احصل على مفتاح CaptchaAI وأتمِت أبحاث السوق.

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