Примеры задач
Внутренние проекты. Каждое число ниже подтверждается артефактом на сервере — журналом прогона, отчётом или командой, которая воспроизводит результат.
Как мы доказываем точность
Точность извлечения проверяется не сопоставлением кода с кодом, а слепой ручной сверкой. Из полного массива формируется стратифицированная случайная выборка с фиксированным seed. Для каждой строки вырезается изображение фрагмента исходного документа — без значений базы рядом. Пять независимых процессов расшифровывают изображения вслепую, и только после этого значения сверяются построчно с результатом алгоритма.
На выборке из 250 проверенных значений (50 записей × 5 полей, источники — 15 файлов: 10 PDF, 2 XLS, 3 XLSX) точность извлечения измерена трижды по мере правок:
| Замер | Совпало | Точность |
|---|---|---|
| 1 (24.08.2026) | 212 / 250 | 84,8% |
| 2 | 231 / 250 | 92,4% |
| 3 | 242 / 250 | 96,8% |
Ценность не в финальном числе, а в наличии всех трёх: видно исходное состояние и видно, что правки измерялись, а не декларировались.
Дополнительно, на пяти записях с обезличенными изображениями (персональные данные закрашены на этапе подготовки) — 3 из 5 полных совпадений, 2 из 5 расхождений: разный формат даты и артефакт объединённых ячеек источника. Расхождения не скрываются — они часть того, что показывает метод.
Разбор с честным отказом
Не каждый документ разбирается одинаково надёжно. Перед прогоном 31.08.2026 на 16 файлах (прайс-листы и каталоги с открытых сайтов оптовых компаний) была сделана оценка: разберётся примерно половина. Итог совпал с оценкой почти точно.
Ворота уверенности — правило, по которому файл либо проходит целиком, либо помечается и откладывается, без промежуточного состояния: 9 из 16 файлов прошли ворота уверенности, 7 — отсеяны. Причины отсева зафиксированы поштучно: у 4 файлов доля неразобранной цены выше 15%, у 2 — меньше 20 строк на объём документа, у 1 не нашлись ни цена, ни наименование.
Из прошедших файлов извлечено 10 142 строки из областей, которые алгоритм считает таблицей; 658 из них (6,5%) помечены как сомнительные и не идут в выход без ручной проверки.
Второй прогон, 01–02.09.2026, на другом наборе документов: 42 файла, 29 372 строки, 9 979 сомнительных (34,0%) — партия оказалась заметно грязнее первой, и это видно по доле сомнительных, а не скрывается усреднением.
Состав входа: 41 текстовый PDF, 3 скана, 1 файл не открылся — отказ зафиксирован в журнале блокировок. Документы разного объёма, от одностраничных до многостраничных, самый объёмный документ — 312 страниц. Размер файлов — от ~108 КБ до ~63 МБ.
Машинное время на контрольном прогоне (20 файлов, тот же код, что в проде): 282,94 секунды на весь набор, в среднем 14,15 секунды на файл (от 0,26 до 95,26 секунды). Оборудование: 2 ядра, 3,8 ГБ памяти, пиковое потребление ~1,8 ГБ. Самый тяжёлый файл (~63 МБ) на контрольном замере упал по нехватке памяти песочницы — в боевом прогоне он разобрался, но честного времени именно по нему нет.
В процессе найдены и исправлены три собственных дефекта: дрейф счётчика позиции при многостраничном разборе, взаимная блокировка очереди в параллельной обработке, маскировавшаяся под таймаут, и заголовки таблиц, ошибочно принятые за строки с ценой.
Пять раз инструмент нас обманул
Внутренний проект по сбору структурированных данных с открытых источников. Формулировки запросов и назначение проекта не раскрываются. Ниже — пять случаев, когда инструмент выдавал правдоподобное число, число оказывалось неверным, и ни один случай не был виден в обычном отчёте — все найдены прямым сравнением.
- Правило подсчёта занижало охват. Правило «найдено, если у источника непустая пагинация» отсеивало честные маленькие результаты (16 и 17 записей на одной странице) как «ничего не найдено». Заменено на «найдено, если общее число результатов больше нуля».
- Фильтр был написан, протестирован и не подключён. Прогоны показывали «найдено 30», «найдено 12» — правдоподобные числа. Аудит кода вскрыл: функция фильтрации существовала и была корректно протестирована на синтетических данных, но никогда не вызывалась в рабочем коде. Числа были общим количеством объектов на странице, до всякой фильтрации.
- 807 дублей маскировались под полноту. «Собрано 6 221 запись» выглядело нормальным итогом. Сравнение общего числа строк с числом уникальных пар «запрос + идентификатор» показало 5 414 против 6 221 — 13,0% строк были повторами. Повтор объекта в данных означает, что в тот же момент где-то пропущен другой — дубли оказались не мусором, а маркером скрытого недобора.
- Счётчик считал строки, а не объекты. У 806 организаций из 3 430 число строк отличалось от числа уникальных объектов, максимум на 24 — одна и та же запись под двумя формулировками запроса засчитывалась дважды.
- Ложный сигнал сбоя при полностью целых данных. Скрипт отработал штатно и записал все строки, но лишняя строка кода после закрытия файла вернула код ошибки 1. На автоматизации такой код неотличим от настоящего сбоя.
Объём по под-усилиям одного проекта (единицы между собой не складываются):
| Под-усилие | Измерено |
|---|---|
| Крупный публичный портал | 22 формулировки запроса, 6 295 записей, 5 097 уникальных объектов, 3 430 организаций |
| Каталог организаций | 35 запросов, 112 кандидатов проверено, 8 подтверждено, 104 отклонено |
| Две площадки объявлений | 4 источника оценено, 2 приняты в работу, 109 объектов в истории |
| Государственный реестр | 11 источников оценено, 0 принято — источник недоступен на уровне сети, официальная выгрузка закрыта с 01.01.2025, коммерческие аналоги требуют логин или капчу. Работа остановлена на диагностике, а не имитировалась |
Дисциплина обхода:
- задержка 2,5 секунды между каждым запросом, без исключений;
robots.txtпроверяется перед каждым запросом, включая главную страницу;- файлы не скачиваются целиком — ограничение 2 МБ и 20 секунд, проверяются только заголовки и сигнатура;
- при коде 403, капче или антибот-челлендже источник помечается и покидается; обход не предпринимался ни разу;
- официальный интерфейс одного источника вернул 403 при первой проверке — использование прекращено немедленно;
- одна площадка отдала капчу после серии запросов — выведена из работы решением человека, не автоматикой;
- из 104 отклонённых кандидатов только у 4 причина — блокировка доступа, остальные 100 отклонены по содержательным причинам.
Полнота сбора оценивалась методом повторного отлова (формула Петерсена — стандартная модель оценки размера популяции по перекрытию двух независимых проходов). По 11 поисковым формулировкам независимый второй полный проход добавил 881 ранее не собранную запись, при средней доле пересечения с первым проходом 98,9%. Уникальных записей: 4 803 в первом проходе, 5 633 во втором, пересечение — 4 752. По каждой формулировке итог после объединения совпал с оценкой Петерсена с точностью 0–3 объекта.
Честная оговорка: полное покрытие этим не доказано и в принципе не доказуемо без произвольного числа проходов — зафиксирована оценка, а не гарантия.
Нижняя граница машинного времени: первый проход — 132 запроса × 2,5 сек = 330 сек; повторный проход — 117 запросов ≈ 293 сек. Реальное время больше на сумму задержек ответа сервера, которая не замерялась.
Чем мы меряем
Сравнительный замер четырёх движков извлечения таблиц из PDF. Все документы синтетические, сгенерированы генератором фикстур — весь контент выдуман, ни одного реального названия, адреса или имени. 10 документов, 860 эталонных ячеек размечены вручную.
| Движок | Найдено ячеек | Точность значений | Форма таблицы | Время, сек | Успешных извлечений |
|---|---|---|---|---|---|
| pdfplumber | 0,687 | 0,700 | 0,660 | 0,050 | 7 / 10 |
| camelot-lattice | 0,687 | 0,700 | 0,690 | 0,477 | 7 / 10 |
| camelot-stream | 0,778 | 0,800 | 0,777 | 0,016 | 8 / 10 |
| OCR (tesseract) | 0,665 | 0,880 | 0,435 | 3,023 | 9 / 10 |
Числа продублированы независимым прогоном и совпали построчно.
Пять оговорок, которые делает сам замер:
- на одном документе («таблица без границ») два движка вернули ноль совпадений, третий — все; усреднение по десяти документам смешивает это в одно число;
- оценка формы таблицы занижает OCR-движок из-за паразитного символа, который эвристика реконструкции сетки считает отдельной колонкой (16 вместо 6) — это слабость метрики, а не движка;
- порог нечёткого совпадения 0,85 — субъективный выбор автора замера;
- эталон размечен тем же человеком, который делал фикстуры — независимой перепроверки эталона нет;
- движок tabula не тестировался — требовал JVM, которой не было в среде.
Подрядчик, который сам перечисляет пять слабых мест собственного замера, показывает, что понимает, где измерение врёт.
Почему мы
aichecker.club — работа одного специалиста, самозанятого, без штата: конвейер обрабатывает задачи параллельно, каждый прогон логируется, результат воспроизводится командой из журнала.
Извлечением и структурированием данных занимаюсь год. До этого двенадцать лет вёл собственное диджитал-агентство (2012–2024), где сведение данных из разных источников было частью работы, но не отдельной услугой — оттуда перенесена не статистика, а привычка организовывать процесс: регламент, приёмка, отчётность, определение готовности для каждой задачи.
Что это значит на практике:
- у каждой задачи есть определение готовности, сформулированное до начала работы;
- точность и полнота не заявляются, а измеряются — методами слепой сверки и повторного отлова, описанными выше;
- собственные дефекты фиксируются и публикуются, а не только успешные прогоны;
- файл либо разбирается уверенно, либо помечается и откладывается — без промежуточного состояния.