أتمتة البحث القانوني تصطدم غالباً بعقبة واحدة: قبل أن تعرض بوابة السجلّات أي نتيجة، تطلب اجتياز reCAPTCHA v2 أو كابتشا صورة. الحلّ مباشر — يرسل CaptchaAI هذا الاختبار إلى الحل ويعيد إليك رمزاً جاهزاً تُلصقه في الطلب، فيتابع السكربت جمع القضايا دون توقّف.
تخيّل فريق تقنية قانونية في القاهرة أو الرياض يتابع ملفّات شركات على SEC EDGAR وسجلّات براءات اختراع لصفقة اندماج عابرة للحدود؛ يحتاج إلى سحب مئات السوابق يومياً دون التوقّف عند كل اختبار CAPTCHA يدوياً. يمرّ كل طلب في هذا المسار بأربع خطوات:
- أرسِل الـ sitekey أو صورة الاختبار إلى CaptchaAI.
- استطلِع النتيجة دورياً حتى تجهز.
- استلِم الرمز العائد —
g-recaptcha-responseلـ reCAPTCHA أو نص الصورة. - أعِد إرسال الطلب مع الرمز لتتابع جمع البيانات.
أنواع CAPTCHA على المصادر القانونية الشائعة
قبل كتابة أي سكربت، حدّد نوع الاختبار في كل بوابة؛ فالمحاكم الفيدرالية تختلف عن أنظمة الولايات. يلخّص الجدول أكثر المصادر تكراراً وما تستخدمه من تحقّق:
| المصدر | نوع الاختبار | البيانات | المستخدمون |
|---|---|---|---|
| PACER | reCAPTCHA v2 | ملفّات المحاكم الفيدرالية | فرق التقاضي |
| أنظمة محاكم الولايات | كابتشا صورة / reCAPTCHA | سجلّات قضايا الولايات | المحامون |
| SEC EDGAR | reCAPTCHA v2 | ملفّات الشركات | فرق الامتثال |
| قواعد بيانات براءات الاختراع | reCAPTCHA v2 | سجلّات البراءات | باحثو الملكية الفكرية |
| البوابات التنظيمية | كابتشا صورة | اللوائح والإرشادات | فرق الامتثال |
| قواعد بيانات الاستشهاد القانوني | reCAPTCHA v2 | استشهادات القضايا | التقنية القانونية |
| أدلّة نقابات المحامين | reCAPTCHA v2 | سجلّات المحامين | العناية الواجبة |
تحقّق دائماً من نوع الاختبار الفعلي على البوابة قبل البناء؛ فبعض الأنظمة تبدّل بين reCAPTCHA وكابتشا الصور بحسب سمعة عنوان IP وحجم الطلبات.
بناء محرّك بحث في السوابق القضائية
الفكرة بسيطة: عند كل صفحة نتائج افحص الاستجابة، فإن ظهر CAPTCHA أرسله إلى CaptchaAI والصق الرمز العائد في الطلب التالي. الصنف أدناه يغلّف هذا المنطق ويدير الجلسة والخادم الوسيط، مع دوال للبحث وسحب التفاصيل ورصد السجل والتصدير إلى CSV:
import requests
import time
import re
import base64
from bs4 import BeautifulSoup
import csv
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
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("Timeout")
def solve_image_captcha(image_bytes):
img_b64 = base64.b64encode(image_bytes).decode()
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
"key": CAPTCHAAI_KEY, "method": "base64",
"body": img_b64, "json": 1,
})
task_id = resp.json()["request"]
for _ in range(20):
time.sleep(3)
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("Timeout")
class LegalResearchScraper:
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",
})
def search_cases(self, search_url, query, sitekey=None, max_pages=5):
"""Search case law database."""
all_cases = []
for page in range(max_pages):
url = f"{search_url}?q={query}&page={page + 1}"
resp = self.session.get(url, timeout=30)
if self._has_captcha(resp.text):
if sitekey:
token = solve_recaptcha(sitekey, url)
resp = self.session.post(url, data={
"q": query,
"g-recaptcha-response": token,
})
else:
resp = self._solve_image_and_retry(resp.text, url, query)
cases = self._parse_cases(resp.text)
if not cases:
break
all_cases.extend(cases)
print(f"Page {page + 1}: {len(cases)} cases")
time.sleep(5)
return all_cases
def get_case_details(self, case_url):
"""Fetch full case details."""
resp = self.session.get(case_url, timeout=30)
if self._has_captcha(resp.text):
sitekey = self._extract_sitekey(resp.text)
if sitekey:
token = solve_recaptcha(sitekey, case_url)
resp = self.session.post(case_url, data={
"g-recaptcha-response": token,
})
soup = BeautifulSoup(resp.text, "html.parser")
return {
"title": self._text(soup, "h1, .case-title"),
"citation": self._text(soup, ".citation, .case-cite"),
"court": self._text(soup, ".court, .jurisdiction"),
"date": self._text(soup, ".decision-date, .date-decided"),
"judge": self._text(soup, ".judge, .authored-by"),
"summary": self._text(soup, ".summary, .headnote"),
"url": case_url,
}
def monitor_docket(self, docket_url, case_number, sitekey=None):
"""Monitor a specific case docket for new filings."""
resp = self.session.get(docket_url, timeout=30)
data = {"case_number": case_number}
if sitekey and self._has_captcha(resp.text):
token = solve_recaptcha(sitekey, docket_url)
data["g-recaptcha-response"] = token
resp = self.session.post(docket_url, data=data)
return self._parse_docket(resp.text)
def export_results(self, cases, filename):
"""Export case results to CSV."""
if not cases:
return
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=cases[0].keys())
writer.writeheader()
writer.writerows(cases)
def _has_captcha(self, html):
return any(tag in html.lower() for tag in [
'data-sitekey', 'g-recaptcha', 'captcha',
])
def _extract_sitekey(self, html):
match = re.search(r'data-sitekey="([^"]+)"', html)
return match.group(1) if match else None
def _solve_image_and_retry(self, html, url, query):
match = re.search(r'src="(/captcha[^"]+)"', html)
if match:
img_url = url.split("?")[0].rstrip("/") + match.group(1)
img = self.session.get(img_url)
answer = solve_image_captcha(img.content)
return self.session.post(url, data={
"q": query,
"captcha": answer,
})
return self.session.get(url)
def _parse_cases(self, html):
soup = BeautifulSoup(html, "html.parser")
cases = []
for item in soup.select(".case-result, .search-result, tr.result"):
title_el = item.select_one("a, .case-name")
if title_el:
cases.append({
"title": title_el.get_text(strip=True),
"url": title_el.get("href", ""),
"citation": self._text(item, ".citation, .cite"),
"date": self._text(item, ".date"),
"court": self._text(item, ".court"),
})
return cases
def _parse_docket(self, html):
soup = BeautifulSoup(html, "html.parser")
entries = []
for row in soup.select(".docket-entry, tr.filing"):
entries.append({
"date": self._text(row, ".date, td:first-child"),
"entry": self._text(row, ".description, td:nth-child(2)"),
"filed_by": self._text(row, ".filer, td:nth-child(3)"),
})
return entries
def _text(self, el, selector):
found = el.select_one(selector)
return found.get_text(strip=True) if found else ""
# Usage
scraper = LegalResearchScraper(
proxy="http://user:pass@residential.proxy.com:5000"
)
# Search case law
cases = scraper.search_cases(
search_url="https://caselaw.example.com/search",
query="data privacy GDPR",
max_pages=5,
)
# Get details for relevant cases
for case in cases[:10]:
if case["url"]:
details = scraper.get_case_details(case["url"])
print(f"{details['citation']}: {details['title']}")
time.sleep(3)
# Export results
scraper.export_results(cases, "gdpr_cases.csv")
يبحث المثال في نهاية الكود عن قضايا "data privacy GDPR" ويصدّر النتائج إلى CSV — نمط قابل للتكيّف مع أي قاعدة سوابق.
رصد الملفّات التنظيمية آلياً
بعد البحث تأتي المتابعة المستمرة. الصنف التالي يبني فوق LegalResearchScraper ويحتفظ بالملفّات التي سبق رصدها، فلا يُبلّغك إلا بالجديد عند فحص عدة بوابات دفعة واحدة:
class RegulatoryMonitor:
def __init__(self, proxy=None):
self.scraper = LegalResearchScraper(proxy=proxy)
self.seen_entries = set()
def check_new_filings(self, feeds):
"""Check regulatory portals for new filings."""
new_filings = []
for feed in feeds:
try:
cases = self.scraper.search_cases(
feed["url"], feed["query"],
sitekey=feed.get("sitekey"),
max_pages=2,
)
for case in cases:
key = case.get("citation") or case.get("title")
if key and key not in self.seen_entries:
self.seen_entries.add(key)
case["source"] = feed["name"]
new_filings.append(case)
except Exception as e:
print(f"Error checking {feed['name']}: {e}")
time.sleep(5)
return new_filings
مرّر إلى check_new_filings قائمة مصادر يحمل كلٌّ منها رابطه واستعلامه وsitekey عند الحاجة، وشغّلها على فاصل منتظم لتحصل على تنبيهات بالملفّات الجديدة.
تشغيل موثوق ومسؤول
يبقى هذا المسار موثوقاً ما دام يعمل داخل نطاق مصرّح به وعلى بيانات عامة يحقّ لك جمعها. قبل التوسّع، ثبّت الأساسيات التالية:
- التزم بشروط الاستخدام وحدود معدّل الطلبات لكل بوابة؛ الإفراط في الطلبات يستدعي الحجب.
- وزّع الطلبات عبر خادم وسيط سكني ثابت الجلسة، وأبقِ فاصلاً زمنياً بين الصفحات.
- عند فشل قراءة صورة، أعد إرسالها للحصول على صورة جديدة بدل إعادة الطلب كاملاً.
- راقب الرصيد وعدد الـ Threads المتزامنة حتى لا تتجاوز حصّتك أثناء السحب الكبير.
في العمل القانوني تحديداً، احتفظ بسجلّ تدقيق لكل طلب: الرابط، ووقت الوصول، ومعرّف مهمة CAPTCHA، والرمز العائد. هذا السجلّ يثبت مصدر كل مستند تسحبه أمام فرق الامتثال، ويسهّل تتبّع أي نتيجة مشكوك فيها إلى الطلب الذي أنتجها. خزّن الرصيد المتبقّي دورياً كذلك حتى تتنبّأ بموعد نفاد الحصّة قبل توقّف عملية سحب طويلة في منتصفها.
حلّ المشكلات الشائعة
| المشكلة | السبب المحتمل | الإجراء |
|---|---|---|
| فشل متكرّر في كابتشا الصور | نصّ مشوّه يصعب قراءته | أعد الإرسال للحصول على صورة جديدة |
| PACER يحجب الوصول | تجاوز حدّ معدّل الطلبات | انتظر نحو 30 دقيقة وقلّل وتيرة الطلبات |
| تفاصيل القضية ناقصة | المحتوى خلف جدار دفع (paywall) | ادفع رسوم الصفحة عند الحاجة |
| البحث لا يُرجع نتائج | عادت صفحة CAPTCHA بدل النتائج | تحقّق من وجود CAPTCHA قبل التحليل |
| رصد السجل يفوّت ملفّات | فاصل الفحص الدوري طويل جداً | قصّر الفاصل وزد وتيرة الفحص |
الأسئلة الشائعة
ما أنواع CAPTCHA التي يحلّها CaptchaAI على البوابات القانونية؟
يغطّي CaptchaAI أكثر الأنواع شيوعاً هنا: reCAPTCHA v2 (بما فيها Invisible وEnterprise) وreCAPTCHA v3 وكابتشا الصور/OCR وGeeTest v3 وCloudflare Turnstile وChallenge. أمّا hCaptcha وFunCaptcha (Arkose Labs) فغير مدعومين حالياً، لذا تحقّق من نوع الاختبار قبل بناء السكربت.
كم تبلغ تكلفة تشغيل هذا السير على نطاق واسع؟
تعتمد أسعار CaptchaAI على عدد الـ Threads المتزامنة لا على عدد عمليات الحل، مع حلول غير محدودة لكل Thread شهرياً. تبدأ خطة BASIC من 15 دولاراً (5 threads)، وSTANDARD من 30 دولاراً (15 thread)، وADVANCE من 90 دولاراً (50 thread)؛ اختر المستوى بحسب حجم الطلبات المتزامنة.
هل الوصول الآلي إلى السجلّات القضائية العامة مسموح؟
السجلّات القضائية العامة متاحة للاطّلاع عادةً، لكن بعض الأنظمة مثل PACER تفرض رسوماً لكل صفحة مهما كانت طريقة الوصول. التزم بشروط الاستخدام وحدود المعدّل، واقتصر على البيانات العامة التي يحقّ لك جمعها.
كيف أتجنّب حجب المعدّل على بوابات مثل PACER؟
أبقِ وتيرة الطلبات منخفضة مع فواصل بين الصفحات، ووزّع الحركة عبر خادم وسيط سكني، وأوقف السحب مؤقتاً عند أول إشارة حجب. وعند تجاوز الحدّ، انتظر نحو 30 دقيقة قبل الاستئناف.
أدلّة ذات صلة
- أتمتة بوابات الجهات الحكومية وحلّ اختبارات CAPTCHA
- جمع بيانات الأبحاث الأكاديمية من مواقع محمية بـ CAPTCHA
جاهز لتحويل البحث القانوني إلى سير آلي؟ أنشئ مفتاح CaptchaAI الخاص بك وابدأ بحلّ reCAPTCHA v2 وكابتشا الصور على أول بوابة اليوم.