PACER, SEC EDGAR, hệ thống tòa án tiểu bang và cơ sở dữ liệu sáng chế đều dùng reCAPTCHA v2 hoặc CAPTCHA hình ảnh để chặn truy cập tự động — script tra cứu án lệ chạy mượt trên dữ liệu mẫu vẫn có thể bị treo ngay khi đụng dữ liệu thật. Với công ty luật, đội legal-tech và bộ phận tuân thủ cần tra cứu án lệ hàng loạt hay theo dõi hồ sơ vụ án, CAPTCHA thường là nút thắt lớn nhất trong pipeline. Bài này đi thẳng vào cách CaptchaAI giải các thử thách đó qua API, kèm code Python chạy được cho công cụ tìm kiếm án lệ và giám sát hồ sơ theo quy định.
CAPTCHA chặn dữ liệu pháp lý ở đâu
| Nguồn | Loại CAPTCHA | Dữ liệu | Người dùng |
|---|---|---|---|
| PACER | reCAPTCHA v2 | Hồ sơ tòa án liên bang | Đội tranh tụng |
| Hệ thống tòa án tiểu bang | CAPTCHA hình ảnh / reCAPTCHA | Hồ sơ vụ án tiểu bang | Luật sư |
| SEC EDGAR | reCAPTCHA v2 | Hồ sơ doanh nghiệp | Đội tuân thủ |
| Cơ sở dữ liệu sáng chế | reCAPTCHA v2 | Hồ sơ bằng sáng chế | Chuyên gia sở hữu trí tuệ |
| Cổng thông tin quy định | CAPTCHA hình ảnh | Quy định, hướng dẫn | Đội tuân thủ |
| Cơ sở dữ liệu trích dẫn án lệ | reCAPTCHA v2 | Trích dẫn vụ án | Legal tech |
| Danh bạ đoàn luật sư | reCAPTCHA v2 | Hồ sơ luật sư | Thẩm định hồ sơ |
Vì sao đội pháp lý và outsourcing tại Việt Nam quan tâm bài toán này
Nhiều công ty outsourcing và legal-tech tại TP.HCM, Hà Nội xây dựng pipeline tra cứu án lệ, thẩm định hồ sơ (due diligence) cho khách hàng là công ty luật hoặc quỹ đầu tư ở Mỹ. Khối lượng này gần như luôn đụng CAPTCHA, vì PACER hay hệ thống tòa án tiểu bang được thiết kế để chặn bot ngay từ đầu. Khi đội lưu trữ dữ liệu vụ án đã thu thập — nhất là dữ liệu cá nhân trong hồ sơ tố tụng — Nghị định 13/2023/NĐ-CP về bảo vệ dữ liệu cá nhân yêu cầu ghi log truy cập và tối thiểu hóa dữ liệu lưu trữ.
Xây dựng công cụ tìm kiếm án lệ tự động
Class dưới đây gộp cả luồng xử lý: gửi request tìm kiếm, phát hiện CAPTCHA, giải bằng CaptchaAI rồi parse kết quả — dùng được cho cả reCAPTCHA v2 lẫn CAPTCHA hình ảnh trên các cổng án lệ.
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:[email protected]: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")
solve_recaptcha() polling res.php mỗi 5 giây trong tối đa 5 phút; solve_image_captcha() xử lý các cổng tòa án tiểu bang vẫn còn dùng CAPTCHA hình ảnh kiểu cũ, không cần sitekey.
Giám sát hồ sơ theo quy định
Để theo dõi hồ sơ mới trên nhiều cổng quy định cùng lúc, bọc LegalResearchScraper trong một lớp giám sát có nhớ trạng thái đã thấy:
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
RegulatoryMonitor chỉ trả về các mục mới chưa thấy trước đó — chạy theo cron mỗi giờ là đủ cho phần lớn trường hợp giám sát hồ sơ.
Chọn gói CaptchaAI theo khối lượng tra cứu án lệ
CaptchaAI tính phí theo thread, không theo mỗi lần giải — mỗi thread giải không giới hạn số CAPTCHA trong tháng. Đội thẩm định hồ sơ nhỏ chạy vài nghìn lượt tra cứu PACER mỗi tháng thường đủ với gói BASIC ($15/tháng, 5 thread). Khi giám sát nhiều cổng quy định song song hoặc crawl cả SEC EDGAR lẫn cơ sở dữ liệu sáng chế, ADVANCE ($90/tháng, 50 thread) cho throughput cao hơn mà chi phí không tăng theo số CAPTCHA đã giải.
Xử lý lỗi thường gặp
- Tìm kiếm không trả về kết quả — CAPTCHA được trả về thay vì trang kết quả. Kiểm tra CAPTCHA trước khi parse HTML.
- CAPTCHA hình ảnh liên tục sai — Ảnh chữ bị bóp méo mạnh. Báo lỗi task, lấy ảnh mới rồi giải lại.
- PACER chặn truy cập — Vượt giới hạn tần suất request. Đợi 30 phút rồi giảm tần suất request.
- Giám sát hồ sơ bỏ sót mục mới — Chu kỳ kiểm tra quá dài. Tăng tần suất kiểm tra (poll thường xuyên hơn).
- Chi tiết vụ việc không đầy đủ — Nội dung nằm sau bức tường phí. Trả phí mỗi trang nếu hệ thống yêu cầu.
Hướng dẫn liên quan
- Tự động hóa cổng thông tin chính phủ
- Thu thập dữ liệu nghiên cứu học thuật
- Đa dạng nguồn proxy khi giải CAPTCHA
Câu hỏi thường gặp
reCAPTCHA v2 và CAPTCHA hình ảnh trên cổng tòa án khác nhau thế nào khi giải bằng API?
CaptchaAI xử lý cả hai qua cùng cặp endpoint in.php/res.php. Với reCAPTCHA v2 (PACER, SEC EDGAR, phần lớn cơ sở dữ liệu sáng chế), gửi sitekey và pageurl qua method=userrecaptcha, polling res.php lấy token rồi post vào form dưới field g-recaptcha-response. Với CAPTCHA hình ảnh (nhiều hệ thống tòa án tiểu bang cũ), gửi ảnh base64 qua method=base64 và nhận lại text — không cần sitekey.
Thu thập tự động hồ sơ tòa án công khai có hợp pháp không?
Có, về nguyên tắc. Hồ sơ tòa án công khai như PACER hay hồ sơ tiểu bang nói chung được phép truy cập tự động; vấn đề thường nằm ở tốc độ request và điều khoản sử dụng chứ không phải bản thân việc scraping. Luôn tôn trọng rate limit và đọc kỹ terms of use trước khi chạy pipeline quy mô lớn.
Giải CAPTCHA cho vài nghìn lượt tra cứu PACER mỗi tháng tốn bao nhiêu?
Với gói BASIC ($15/tháng, 5 thread), bạn giải không giới hạn CAPTCHA trong tháng — chi phí không tăng theo số lượt tra cứu, chỉ giới hạn bởi số thread chạy song song. Đội xử lý vài nghìn hồ sơ mỗi tháng thường không cần nâng cấp; chỉ khi crawl song song nhiều cổng cùng lúc mới nên lên ADVANCE ($90/tháng, 50 thread).
Cần lưu ý gì về bảo vệ dữ liệu khi lưu hồ sơ vụ án đã thu thập?
Nếu hồ sơ chứa dữ liệu cá nhân (tên đương sự, luật sư, địa chỉ), Nghị định 13/2023/NĐ-CP yêu cầu tối thiểu hóa dữ liệu lưu trữ và ghi log truy cập. Thiết kế pipeline có audit log và thời hạn lưu trữ rõ ràng ngay từ đầu, thay vì bổ sung sau khi phát sinh khiếu nại.
Lấy API key CaptchaAI và đưa reCAPTCHA v2 hay CAPTCHA hình ảnh trên PACER, SEC EDGAR vào pipeline tra cứu án lệ tự động của bạn — lấy API key CaptchaAI ngay hôm nay.