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

جمع البيانات البحثية الأكاديمية من المواقع المحمية بـ CAPTCHA

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

تخيّل فريق مراجعة منهجية في جامعة خليجية يبني قاعدة استشهادات من Scopus وWeb of Science إلى جانب مصادر عربية مثل دار المنظومة وe-Marefa. الفريق لا يحتاج إلى «تجاوز» أي موقع، بل إلى مسار جمع مصرَّح به يعمل بثبات لأسابيع دون أن يُحظر عنوان IP الخاص بالمؤسسة.


متى تظهر اختبارات CAPTCHA في القواعد الأكاديمية؟

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

المصدر نوع التحقق المحفّز البيانات
Google Scholar reCAPTCHA v3 كثافة الاستعلامات ووتيرة التصفح الاستشهادات، الروابط، النتائج الأولية
PubMed reCAPTCHA v2 تكرار البحث أو سحب البيانات بسرعة الأدبيات الطبية الحيوية
Web of Science Cloudflare Turnstile التنزيلات المجمعة أو الاستعراض الكثيف مقاييس الاستشهاد والتحليل البحثي
Scopus reCAPTCHA v2 عمليات التصدير المتعددة البيانات الببليومترية
IEEE Xplore reCAPTCHA v2 البحث مع فتح صفحات كثيرة أو تنزيلات متقاربة الأوراق الهندسية والتقنية
JSTOR reCAPTCHA v2 التصفح المتكرر لصفحات المحتوى مواد العلوم الإنسانية والاجتماعية

الأنواع الثلاثة السابقة كلها مدعومة في CaptchaAI. والفكرة ليست «تجاوز» هذه المواقع، بل تشغيل جمعٍ مصرَّح به ضمن معدل مدروس، مع فحص التحدي عند ظهوره ومعالجة النتيجة داخل سير عمل قابل للتتبع والصيانة.


اضبط معدل الطلبات أولًا

المواقع الأكاديمية تتعامل بسرعة مع عناوين IP ذات السلوك الآلي الواضح، لذلك يبدأ نجاح المشروع من هنا لا من الكود. التأخير المحافظ وتدوير الوكلاء السكنيين واحترام الواجهات الرسمية أكثر فاعلية من رفع السرعة:

المصدر التأخير الموصى به الحد الأقصى التقريبي للصفحات في الساعة
Google Scholar 10-15 ثانية 40-50
PubMed 3-5 ثوانٍ 100
Web of Science 5-10 ثوانٍ 60
Scopus 5-10 ثوانٍ 60
IEEE Xplore 3-5 ثوانٍ 100
JSTOR 5-10 ثوانٍ 60

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


بناء جامع بيانات الاستشهادات

الآن نترجم هذا المنطق إلى كود: جلسة HTTP مستقرة، كشف مبكر عن التحدي، إرسال إلى CaptchaAI، ثم إعادة الطلب واستخراج النتائج وتصديرها إلى CSV.

import requests
import time
import re
from bs4 import BeautifulSoup
import csv

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("Timeout")


class AcademicScraper:
    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 search_papers(self, search_url, query, max_pages=10):
        """Search academic database for papers matching query."""
        all_papers = []

        for page in range(max_pages):
            url = f"{search_url}?q={query}&start={page * 10}"
            resp = self.session.get(url, timeout=30)

            # Handle CAPTCHA
            if self._has_captcha(resp.text):
                resp = self._solve_and_retry(resp.text, url)

            papers = self._parse_results(resp.text)
            if not papers:
                break  # No more results

            all_papers.extend(papers)
            print(f"Page {page + 1}: {len(papers)} papers")
            time.sleep(5)  # Respectful delay

        return all_papers

    def get_paper_details(self, paper_url):
        """Get detailed metadata for a single paper."""
        resp = self.session.get(paper_url, timeout=30)

        if self._has_captcha(resp.text):
            resp = self._solve_and_retry(resp.text, paper_url)

        soup = BeautifulSoup(resp.text, "html.parser")
        return {
            "title": self._safe_text(soup, "h1, .article-title"),
            "authors": self._safe_text(soup, ".authors, .author-list"),
            "abstract": self._safe_text(soup, ".abstract, #abstract"),
            "doi": self._safe_text(soup, ".doi, [data-doi]"),
            "journal": self._safe_text(soup, ".journal-name, .publication"),
            "year": self._safe_text(soup, ".pub-date, .year"),
            "citations": self._safe_text(soup, ".citation-count, .cited-by"),
        }

    def export_to_csv(self, papers, filename):
        """Export collected papers to CSV."""
        if not papers:
            return
        keys = papers[0].keys()
        with open(filename, "w", newline="", encoding="utf-8") as f:
            writer = csv.DictWriter(f, fieldnames=keys)
            writer.writeheader()
            writer.writerows(papers)
        print(f"Exported {len(papers)} papers to {filename}")

    def _has_captcha(self, html):
        return any(tag in html.lower() for tag in [
            'data-sitekey', 'g-recaptcha', 'cf-turnstile',
        ])

    def _solve_and_retry(self, html, url):
        match = re.search(r'data-sitekey="([^"]+)"', html)
        if not match:
            return self.session.get(url)

        sitekey = match.group(1)
        if 'cf-turnstile' in html:
            token = solve_captcha("turnstile", sitekey, url)
            return self.session.post(url, data={"cf-turnstile-response": token})
        else:
            token = solve_captcha("userrecaptcha", sitekey, url)
            return self.session.post(url, data={"g-recaptcha-response": token})

    def _parse_results(self, html):
        soup = BeautifulSoup(html, "html.parser")
        papers = []
        for item in soup.select(".gs_r, .search-result, article.result"):
            title_el = item.select_one("h3 a, .result-title a")
            if title_el:
                papers.append({
                    "title": title_el.get_text(strip=True),
                    "url": title_el.get("href", ""),
                    "snippet": self._safe_text(item, ".gs_rs, .abstract-snippet"),
                    "authors": self._safe_text(item, ".gs_a, .author-info"),
                })
        return papers

    def _safe_text(self, soup, selector):
        el = soup.select_one(selector)
        return el.get_text(strip=True) if el else ""


# Usage - Literature review
scraper = AcademicScraper(
    proxy="http://user:pass@residential.proxy.com:5000"
)

papers = scraper.search_papers(
    "https://scholar.example.com/scholar",
    query="machine learning CAPTCHA solving",
    max_pages=5,
)

# Get details for top papers
detailed = []
for paper in papers[:20]:
    if paper["url"]:
        detail = scraper.get_paper_details(paper["url"])
        detailed.append(detail)
        time.sleep(3)

scraper.export_to_csv(detailed, "literature_review.csv")

يفصل هذا البناء منطق الكشف عن منطق الحل عن منطق الاستخراج، وهو ما يبقي مسار الفشل والاسترجاع واضحًا. عند ظهور تحدٍّ يُلتقط مفتاح الموقع، ويُرسل النوع الصحيح إلى CaptchaAI — turnstile لـ Cloudflare أو userrecaptcha لـ reCAPTCHA — ثم يُعاد الطلب بالرمز المستلم دون خلط بين حقول الرموز.


توسيع الجمع إلى شبكة استشهادات ببليومترية

عند بناء شبكة استشهادات لا تكفي الصفحة الأولى من النتائج؛ تحتاج إلى تتبع روابط «استشهد به» على مستويات متعددة. المفتاح هنا هو الحد من عرض الزحف والالتزام بتأخير ثابت، لأن الإفراط في التوازي يرفع احتمال ظهور التحدي أو حظر عنوان IP بسرعة.

def bibliometric_analysis(scraper, seed_papers, depth=2):
    """Follow citations to build a citation network."""
    visited = set()
    network = []

    def _crawl(paper_url, current_depth):
        if current_depth > depth or paper_url in visited:
            return
        visited.add(paper_url)

        try:
            details = scraper.get_paper_details(paper_url)
            network.append(details)

            # Follow "cited by" links
            resp = scraper.session.get(f"{paper_url}/citations", timeout=30)
            if scraper._has_captcha(resp.text):
                resp = scraper._solve_and_retry(resp.text, f"{paper_url}/citations")

            citations = scraper._parse_results(resp.text)
            for cite in citations[:5]:  # Limit breadth
                if cite["url"]:
                    _crawl(cite["url"], current_depth + 1)
                    time.sleep(3)

        except Exception as e:
            print(f"Error crawling {paper_url}: {e}")

    for paper in seed_papers:
        _crawl(paper["url"], 0)

    return network

تحدّ الدالة العمق وعدد الاستشهادات المتتبَّعة لكل ورقة، وتخزّن ما تمت زيارته لتفادي الحلقات المكررة. في مشروع ممتد على عشرات الآلاف من الأوراق، هذا الضبط هو الفرق بين تشغيل مستقر لأيام وبين حظرٍ مبكر يُفشل الدفعة كلها.


عندما يتعثر الجمع: تشخيص سريع

معظم مشكلات الجمع الأكاديمي تعود إلى أسباب متكررة، وحلّها غالبًا في ضبط المعدل والجلسة لا في الكود:

المشكلة السبب المحتمل الإجراء الموصى به
ظهور CAPTCHA في كل عملية بحث تم تصنيف عنوان IP على أنه عالي الخطورة بدّل البروكسي، وارفع التأخير إلى 15 ثانية أو أكثر، وقلل عدد الطلبات المتزامنة
عدم ظهور نتائج رغم نجاح الطلب تمت إعادة صفحة التحدي بدل صفحة النتائج افحص وجود CAPTCHA قبل التحليل، ولا تفترض أن كل استجابة HTML تحتوي على النتائج المطلوبة
غياب الملخص أو البيانات الوصفية المحتوى خلف جدار دفع أو يحتاج وصولًا مؤسسيًا استخدم وصولًا مصرحًا به أو مصادر مفتوحة، ولا تعتمد على HTML العام وحده
حظر Google Scholar لعنوان IP تجاوزت حدود المعدل المسموح ضمنيًا انتظر فترة راحة، واستخدم عنوان IP مختلفًا، وخفّض كثافة الاستعلامات
قيود على التصدير أو التنزيل المنصة تحدّ من تنزيلات الدفعات الكبيرة قسم العمل إلى دفعات أصغر، وخزّن نقاط الاستئناف بين الجلسات

الأسئلة الشائعة

ما أنواع CAPTCHA التي تظهر على القواعد الأكاديمية وهل يدعمها CaptchaAI؟

الأكثر شيوعًا هي reCAPTCHA v2 على PubMed وScopus وIEEE Xplore وJSTOR، وreCAPTCHA v3 على Google Scholar، وTurnstile على Web of Science — وكلها مدعومة في CaptchaAI. أما hCaptcha وFunCaptcha فغير مدعومة حاليًا، لذا خطّط مصادرك على أساس ما هو مدعوم فعليًا.

كيف أتعامل مع reCAPTCHA v3 القائم على النقاط في Google Scholar؟

reCAPTCHA v3 لا يعرض لغزًا مرئيًا بل يمنح درجة سلوكية للجلسة. لذلك يعتمد النجاح على الثبات: جلسة مستقرة، وتأخير 10-15 ثانية، وملفات ارتباط متسقة، مع تدوير الوكلاء السكنيين عند الحجم الكبير.

هل الأفضل استخدام الواجهة الرسمية بدل الاستخراج المباشر؟

نعم كلما كانت متاحة. تقدّم PubMed واجهة E-utilities رسمية تجنّبك التحديات تمامًا. اعتمد الواجهة الرسمية أولًا للبيانات الوصفية العامة، واحتفظ بمسار الاستخراج مع حل CAPTCHA للحالات التي لا تغطيها.

ما حجم الخطة المناسب لمشروع ببليومتري كبير؟

يعتمد ذلك على التزامن لا على عدد الأوراق فقط، لأن CaptchaAI يُسعّر على أساس الخيوط (Threads). لمراجعة فردية تكفي خطة BASIC بسعر 15 دولارًا أو STANDARD بسعر 30 دولارًا، أما مشاريع الفرق ذات الزحف المتوازي فقد تحتاج ADVANCE بسعر 90 دولارًا أو أعلى.


ابدأ بمسار أكثر ثباتًا لأبحاثك: أنشئ مفتاح CaptchaAI ونظّم جمع البيانات والاستشهادات بطريقة قابلة للتكرار والمتابعة.

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