Сайт суда, реестр недвижимости или картотека арбитражных дел почти никогда не защищены современной CAPTCHA. За устаревшим интерфейсом почти всегда скрывается что-то простое: искажённый текст, математическая задачка или CAPTCHA собственной разработки — наследие систем, которые писали ещё до reCAPTCHA и Cloudflare Turnstile. Для автоматизации это хорошая новость: такие капчи решаются предсказуемо, без сложной настройки headless-браузера — через обычный image/OCR API.
Ниже — рабочий процесс на Python и JavaScript, который решает CAPTCHA на разных типах порталов публичных записей: от поиска судебных дел до выписок по объектам недвижимости и юрлицам.
Какие CAPTCHA стоят на порталах публичных записей
Тип CAPTCHA обычно зависит не от штата или ведомства, а от того, когда портал в последний раз переписывали. Типичная картина по категориям:
| Категория портала | Типичная CAPTCHA | Пример задачи |
|---|---|---|
| Поиск судебных дел | CAPTCHA собственной разработки (текст) | Искажённые буквы и цифры, 5–6 символов |
| Записи об объектах недвижимости (округ) | Математическая CAPTCHA | «Сколько будет 4 + 7?» |
| Поиск юрлиц и ИП | Image CAPTCHA (текст) | Искажённые буквы с линейным шумом |
| Записи актов гражданского состояния | reCAPTCHA v2 | Выбор нужных изображений в сетке |
| Разрешения на строительство | Простая текстовая CAPTCHA | 4-значный цифровой код |
| Документы по обеспечительным обязательствам (UCC) | CAPTCHA собственной разработки (OCR) | Буквы разного регистра на зашумлённом фоне |
Что передавать в API для государственных порталов
Прежде чем идти в код: у image/OCR метода CaptchaAI есть несколько параметров, которые стоит выставить осознанно уже на первом вызове — иначе первые тесты уйдут на подбор base64 против post и угадывание language.
| Параметр | Значение | Когда использовать |
|---|---|---|
method |
base64 |
Изображение уже загружено в байтах |
method |
post |
Отправляете файл изображения напрямую |
language |
0 |
Латинский/цифровой текст CAPTCHA |
numeric |
1 |
CAPTCHA состоит только из цифр |
min_len / max_len |
зависит от портала | Когда известна длина кода |
textinstructions |
произвольная инструкция | Математические CAPTCHA или нестандартный формат |
Поиск по судебным делам с решением CAPTCHA
Базовый сценарий — класс на Python, который сначала загружает страницу поиска, чтобы получить сессионные cookie и, если нужно, картинку CAPTCHA, а затем решает её и отправляет форму:
import requests
import base64
import time
from urllib.parse import urljoin
class PublicRecordsSearcher:
def __init__(self, api_key):
self.api_key = api_key
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
def search_court_records(self, portal_url, case_number):
"""Search court records, solving image CAPTCHAs as needed."""
# Load the search page
page = self.session.get(f"{portal_url}/search")
# Extract CAPTCHA image
captcha_img_url = self._extract_captcha_url(page.text, portal_url)
if not captcha_img_url:
# No CAPTCHA on this page
return self._submit_search(portal_url, case_number)
# Download and solve CAPTCHA
img_response = self.session.get(captcha_img_url)
captcha_text = self._solve_image_captcha(img_response.content)
# Submit search with solved CAPTCHA
return self._submit_search(portal_url, case_number, captcha_text)
def _extract_captcha_url(self, html, base_url):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
# Look for common CAPTCHA image patterns
captcha_img = (
soup.find("img", {"id": "captchaImage"}) or
soup.find("img", {"class": "captcha"}) or
soup.find("img", attrs={"src": lambda s: s and "captcha" in s.lower()})
)
if captcha_img and captcha_img.get("src"):
return urljoin(base_url, captcha_img["src"])
return None
def _solve_image_captcha(self, image_bytes):
img_base64 = base64.b64encode(image_bytes).decode("utf-8")
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "base64",
"body": img_base64,
"json": 1
})
task_id = resp.json()["request"]
for _ in range(30):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return data["request"]
raise TimeoutError("CAPTCHA solve timed out")
def _submit_search(self, portal_url, case_number, captcha_text=None):
form_data = {"caseNumber": case_number}
if captcha_text:
form_data["captcha"] = captcha_text
response = self.session.post(
f"{portal_url}/search/results",
data=form_data
)
return response.text
# Usage
searcher = PublicRecordsSearcher("YOUR_API_KEY")
results = searcher.search_court_records(
"https://courts.example.gov",
"2024-CV-12345"
)
Если на портале капчи нет вовсе, _extract_captcha_url вернёт None, и класс отправит поиск без лишнего шага. Про это стоит подумать заранее: часть порталов включает CAPTCHA только при подозрительном трафике, а не на каждый запрос, и жёстко ожидать картинку на каждой странице — ошибка.
Математические CAPTCHA: тот же движок, другой промпт
Часть окружных порталов вместо искажённого текста показывает арифметику — как правило, это тот же самый image CAPTCHA механизм, просто с картинкой вида «4 + 7 = ?». CaptchaAI решает такие задачи как обычное распознавание текста, если явно указать это в textinstructions:
def solve_math_captcha(self, image_bytes):
"""Solve math CAPTCHAs like '4 + 7 = ?'"""
img_base64 = base64.b64encode(image_bytes).decode("utf-8")
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "base64",
"body": img_base64,
"textinstructions": "solve the math equation and return only the number",
"json": 1
})
task_id = resp.json()["request"]
# Poll for result
for _ in range(30):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return data["request"]
raise TimeoutError("Math CAPTCHA solve timed out")
Агрегация поиска по нескольким порталам (JavaScript)
Когда нужно опросить сразу несколько реестров одним запуском — например, сверить одно и то же название компании в реестре штата и в картотеке суда, — удобнее собрать логику в отдельный класс на JavaScript, который переживает отказ одного портала, не роняя весь батч:
class RecordsAggregator {
constructor(apiKey) {
this.apiKey = apiKey;
}
async searchAcrossPortals(query, portals) {
const results = [];
for (const portal of portals) {
try {
const data = await this.searchPortal(portal, query);
results.push({ portal: portal.name, records: data });
} catch (error) {
results.push({ portal: portal.name, error: error.message });
}
}
return results;
}
async searchPortal(portal, query) {
const pageResponse = await fetch(portal.searchUrl);
const html = await pageResponse.text();
// Check for image CAPTCHA
const captchaMatch = html.match(/captcha[^"]*\.(?:png|jpg|gif)/i);
let captchaAnswer = null;
if (captchaMatch) {
const imgUrl = new URL(captchaMatch[0], portal.searchUrl).href;
const imgData = await fetch(imgUrl);
const buffer = await imgData.arrayBuffer();
const base64 = Buffer.from(buffer).toString('base64');
captchaAnswer = await this.solveImageCaptcha(base64);
}
// Submit search
const formData = new URLSearchParams({ q: query });
if (captchaAnswer) formData.append('captcha', captchaAnswer);
const response = await fetch(portal.searchUrl, {
method: 'POST',
body: formData
});
return response.text();
}
async solveImageCaptcha(base64Image) {
const submitResp = await fetch('https://ocr.captchaai.com/in.php', {
method: 'POST',
body: new URLSearchParams({
key: this.apiKey,
method: 'base64',
body: base64Image,
json: '1'
})
});
const { request: taskId } = await submitResp.json();
for (let i = 0; i < 30; i++) {
await new Promise(r => setTimeout(r, 3000));
const result = await fetch(
`https://ocr.captchaai.com/res.php?key=${this.apiKey}&action=get&id=${taskId}&json=1`
);
const data = await result.json();
if (data.status === 1) return data.request;
}
throw new Error('CAPTCHA solve timed out');
}
}
// Usage
const aggregator = new RecordsAggregator('YOUR_API_KEY');
const results = await aggregator.searchAcrossPortals('Smith LLC', [
{ name: 'State Business Registry', searchUrl: 'https://sos.example.gov/search' },
{ name: 'County Court Records', searchUrl: 'https://courts.example.gov/search' }
]);
Обратите внимание на try/catch вокруг каждого searchPortal: один упавший портал не должен останавливать проверку остальных — в массив результатов просто попадёт запись об ошибке вместо разорванного Promise.all.
Локальный пример: поиск по российским реестрам
Логика из примеров выше не завязана на американские county-порталы. С тем же подходом парсятся kad.arbitr.ru (картотека арбитражных дел), выписки из ЕГРЮЛ/ЕГРИП на сайте ФНС и сервисы Росреестра: везде встречается либо искажённый текст, либо математическая CAPTCHA, либо reCAPTCHA v2 на старых формах. Разница обычно в разметке HTML страницы и в том, куда конкретно подставлять решённый токен, — сам вызов in.php/res.php не меняется.
При автоматизации таких запросов стоит держать в голове 152-ФЗ «О персональных данных»: собирайте только те поля, которые вам действительно нужны и на обработку которых у вас есть законное основание, и не публикуйте результаты поиска в открытом доступе. Это дисциплина самого пайплайна, а не свойство CaptchaAI, — но именно она снимает большую часть рисков при работе с формально публичными, а по сути персональными данными: ФИО, адресами, номерами дел.
Типичные проблемы при работе с CAPTCHA на госпорталах
Большая часть проблем в проде связана не с точностью распознавания, а с сессиями и повторными запросами:
| Проблема | Причина | Решение |
|---|---|---|
| Картинка CAPTCHA возвращает 403 | Нет сессионной cookie | Сначала загрузите страницу поиска, затем запрашивайте картинку в той же сессии |
| CaptchaAI вернул неверный ответ | Низкое качество изображения | Предобработайте картинку: увеличьте контраст, уберите шум |
| CAPTCHA обновляется при отправке формы | Истёк токен формы | Извлекайте скрытые поля формы вместе с картинкой CAPTCHA и отправляйте их одним запросом |
| После решения CAPTCHA поиск возвращает пустую страницу | Редирект после POST потерял cookie | Используйте allow_redirects=True и один и тот же requests.Session() на весь сценарий |
| На одном портале чередуются разные типы CAPTCHA | Портал переключает вендора или включает reCAPTCHA только при подозрительном трафике | Определяйте тип CAPTCHA на странице перед вызовом API, а не жёстко привязывайтесь к одному методу |
Часто задаваемые вопросы
Почему на государственных порталах до сих пор стоит капча из нулевых?
Большинство таких систем разрабатывались до reCAPTCHA и Cloudflare Turnstile, и с тех пор их почти не трогали: бюджет на переписывание legacy-системы государственный заказчик выделяет нечасто. Поэтому вместо современной защиты на форме остаётся тот же image CAPTCHA или математическая задачка, что и десять лет назад.
Сколько времени занимает решение CAPTCHA на портале суда или реестра?
Для image CAPTCHA типичное время решения — менее 0,5 секунды. Цикл из 30 попыток по 3 секунды в примере выше — это запас на сетевые задержки и очередь на стороне API, а не реальное время ответа; на практике результат почти всегда приходит на первом-втором опросе res.php.
Нужно ли предобрабатывать изображение CAPTCHA перед отправкой?
Не всегда. Предобработка — оттенки серого, повышение контраста, удаление шума — заметно помогает только на изображениях очень низкого качества. Для большинства порталов из таблицы выше достаточно отправить картинку как есть; техники разобраны в руководстве по предобработке изображений CAPTCHA.
Что делать, если после решения CAPTCHA поиск возвращает пустую страницу?
Почти всегда это потерянная сессия: редирект после POST ушёл без сохранённых cookie. Держите один объект сессии (в Python — requests.Session()) на весь сценарий, от загрузки страницы поиска до получения результатов, и явно указывайте allow_redirects=True.
Можно ли использовать один API-ключ CaptchaAI для нескольких порталов одновременно?
Да — один ключ обслуживает все порталы сразу, а число одновременных CAPTCHA ограничено только количеством потоков в тарифе. План BASIC даёт 5 потоков за $15/мес с неограниченным числом решений на поток; для параллельного опроса десятков реестров подойдут более высокие тарифы, вплоть до VIP-3 (5 000 потоков, $7,500/мес).
Итог: с чего начать
Автоматизация поиска по публичным записям — это в первую очередь дисциплина сессий и повторных запросов, а решение самой CAPTCHA сводится к одному вызову API. Получите API-ключ CaptchaAI и подключите его к пайплайну поиска по нужным вам порталам.