Apache Tika — это набор инструментов Apache Software Foundation для разбора документов: передай ему файл почти любого типа, и он вернёт обычный текст вместе с нормализованным словарём метаданных. В README проекта заявлена поддержка более тысячи форматов, и достигается это за счёт того, что Tika поставляется уже со всеми нужными специализированными библиотеками — PDFBox для PDF, Apache POI для документов Office, jsoup для HTML, ODF-reader для ODT. В итоге всё умещается в один fat jar, и во время разбора ничего дополнительно скачивать не нужно. В конвейере обработки данных это обычно самый неприметный первый шаг: компонент перед поисковым индексом, набором для e-discovery или корпусом для LLM, который приводит разнородную кучу файлов к единому виду. По сути, у него две задачи — понять, что за байтовый поток перед ним, а затем извлечь из него текст и метаданные.
Это один из самых неприхотливых инструментов, которые я настраивал за долгое время. Один jar-файл, java -jar tika-app-3.3.2.jar --text file.pdf, без конфигов, без весов моделей, без постустановочных шагов — и всё заработало даже на свежем JDK, который в тот же день уронил на этом же хосте другое Java- ПО. Но проверять я хотел не заявление о каталоге поддерживаемых форматов, а более узкий и проверяемый вопрос: что Tika реально делает, когда входные данные врут? Для этого я собрал контролируемый набор тестовых файлов, где каждый фрагмент содержимого содержит уникальный маркер, отрендерил один и тот же логический документ в девяти форматах-носителях, а затем атаковал всё это неправильными расширениями, отсутствующими расширениями, файлами вообще без имени, нулевыми файлами и обрезанными бинарниками.
Самое интересное поведение проявляется именно на этапе определения типа. Я переименовал PDF в .txt и спросил Tika, что это за файл; он ответил application/pdf. Потом я вообще убрал имя файла, передал сырые байты через stdin и получил тот же ответ. Для пяти форматов, определяемых по содержимому, это совпало во всех 20 уникальных логических условиях: три условия по имени файла плюс одно безымянное потоковое условие на каждый формат. В рамках тестового стенда потоковый случай трижды запускался под разными метками, так что получилось 30 успешных сырых запусков, но эти повторы не являются независимым доказательством. PDF и RTF выдают узнаваемые байты; DOCX раскрывается по контейнеру; HTML и XML определяются по разметке или корневому содержимому. Разные механизмы, но в этом наборе тестов результат один: расширение не перебило содержимое. А вот в семействе текстовых форматов Markdown сразу сваливается в text/plain, как только имя файла неверное или отсутствует. Его идентичность здесь целиком держалась на .md.
Сразу оговорю два предела для всех чисел дальше. Я тестировал Apache Tika 3.3.2 — проверил 27 июля 2026 года, и это всё ещё была последняя стабильная версия; ветка 4.0.0 существовала только в виде alpha- и beta-сборок в Maven Central. На момент проверки у проекта было примерно 3.9k звёзд на GitHub, лицензия — Apache-2.0, то есть максимально дружелюбная к коммерческому использованию. И OCR я вообще не тестировал. Ни одной отсканированной страницы, ни одного PDF только с изображениями. На машине, где я это запускал, не установлены Tesseract и poppler, так что все OCR-пути были недоступны ещё до начала. Здесь нет OCR-данных просто потому, что OCR-данных здесь нет.
Что такое Tika, если убрать маркетинговую обёртку
Часто считают, что Apache Tika — это конвертер документов: подал DOCX, получил аккуратный Markdown с заголовками и таблицами. На самом деле это не так, и чем раньше это прояснить, тем лучше выглядит сам инструмент.
В этом тесте у Tika было три релевантных этапа: определение типа содержимого, диспетчер, который передаёт байты нужному парсеру, и обработчик вывода CLI --text, который выдаёт плоский текст вместе с отдельно доступными метаданными. В таком контракте вывода нет объектов Title, нет ListItem, нет восстановленной сетки таблицы. У Tika есть и другие обработчики, и API, включая XHTML/SAX-ориентированный вывод; я их не тестировал. Поэтому все выводы о структуре ниже относятся именно к tika-app --text, а не к утверждению, будто у всего тулкита вообще нигде нет структурированного потока событий.
Звучит как ограничение — и в одном смысле это так. Но это также значит, что Tika почти нечего неправильно классифицировать, а именно на этом и ошибаются многие более шумные аналоги.
Само определение типа работает в документированном порядке: сначала сигнатуры байтов, затем проверка корня XML, затем шаблон имени файла, затем тип, который вы указали сами (в документации Tika по детектированию это описано именно так). И только после определения типа диспетчер передаёт байты соответствующему встроенному парсеру — PDFBox, POI, jsoup, TextAndCSVParser для текстового семейства.
Такое разделение на детектирование и разбор — не внутренняя мелочь. Именно поэтому файл может оказаться слишком повреждённым для парсинга, но всё равно быть правильно определённым по типу. И это превращается в самый практичный приём, который даёт Tika, когда что-то начинает ломаться.
Настройка: один jar, одна команда и JVM без капризов
Установка сводится к скачиванию. tika-app-3.3.2.jar из Maven Central весит примерно 67 MB — это fat jar со всеми парсерами внутри — и дальше всё запускается через java -jar tika-app-3.3.2.jar --text file.pdf. Никаких конфигов, никаких весов моделей, никаких post-install шагов, никакой цепочки из brew install.
История с JDK меня приятно удивила. Я запускал всё на OpenJDK 26.0.1, то есть на свежей не-LTS сборке, и команды --version, --text, --metadata и --detect завершались с кодом 0 без каких-либо жалоб на совместимость. Это стоит отдельно отметить, потому что в тот же день я гонял Apache Nutch на этом же хосте, и его цикл обхода вообще не работал на JDK 26 — ему нужен LTS на 21 или ниже из-за удаления SecurityManager в новых JDK. Tika это не волновало. Если вы избегаете JVM-инструментов именно из-за такого класса проблем, Tika — не тот случай, где вас укусит эта боль.
Но есть и честные оговорки по установке. CLI при каждом запуске поднимает свежую JVM, так что холодный старт заметен — 131 запуск в моём стенде заняли около минуты, и большую часть времени съел прогрев JVM. Если вы обрабатываете файлы в больших объёмах, нужен либо библиотечный режим, либо серверный режим, а не shell-цикл по jar-файлу. И ещё один жёсткий предел: извлечение текста из PDF-слоя не требует внешних зависимостей, а OCR требует tesseract и poppler. PDF с текстовым слоем, DOCX, ODT, RTF, HTML, XML, TXT, Markdown, CSV нормально разобрались на машине, где ничего из этого не было установлено. Отсканированные документы — не разобрались бы, и я не делал вид, что это не так.
Этот контраст особенно заметен на фоне соседней библиотеки, которую я тестировал в тот же день, unstructured: путь для электронных PDF у неё был полностью заблокирован, потому что импорт PDF-модуля подтягивает inference stack (torch и связанные пакеты) уже при загрузке — ещё до выбора стратегии, так что даже стратегия “fast” не импортируется без этого. Tika же спокойно разобрал текстовый слой того же PDF обычной командой java -jar.
Тест на лживое расширение: определение MIME-типа не обращает внимания на имя файла

Восемь форматов, каждый подан либо с правильным расширением, либо с намеренно неверным, либо вообще без расширения, плюс поток байтов без имени файла через stdin. Итого 32 уникальных логических условия. В исходном стенде один и тот же поток также прогонялся под каждой меткой имени файла, что дало 48 сырых запусков; но три строковых случая с потоком сводятся к одному условию, потому что stdin не несёт имени файла.
| Тестовый файл | Истинный тип | Переименован в | Правильное расширение | Лживое расширение | Без расширения | Сырой поток без имени файла |
|---|---|---|---|---|---|---|
application/pdf | .txt | ✅ | ✅ | ✅ | ✅ | |
| DOCX | OOXML wordprocessingml | .jpg | ✅ | ✅ | ✅ | ✅ |
| RTF | application/rtf | .html | ✅ | ✅ | ✅ | ✅ |
| HTML | text/html | .csv | ✅ | ✅ | ✅ | ✅ |
| XML | application/xml | .txt | ✅ | ✅ | ✅ | ✅ |
| Обычный текст | text/plain | .pdf | ✅ | ✅ | ✅ | ✅ |
| Markdown | text/markdown | .pdf | ✅ | ❌ text/plain | ❌ text/plain | ❌ text/plain |
| CSV | text/csv | .txt | ✅ | ❌ text/plain | ❌ text/plain | ❌ text/plain |
(Колонка stream объединяет все три условия по расширению, потому что без имени файла glob просто не на что смотреть.)
Пять форматов, определяемых по содержимому — PDF, DOCX, RTF, HTML и XML — попали в истинный тип во всех 20 из 20 уникальных условий (и в 30 из 30 сырых запусков с повторами потокового кейса). PDF с именем report.txt всё равно остался PDF. DOCX, названный photo.jpg, всё равно остался DOCX. Имя файла не понадобилось ни в одном из этих случаев. Это не значит, что все пять используют только фиксированные сигнатуры байтов: у PDF и RTF есть узнаваемые заголовки, DOCX — это контейнер на базе ZIP, а HTML/XML определяются по разметке или корневому содержимому. Но в этих тестах лживое расширение не победило.
А вот дальше начинается режим текстовых форматов. Markdown определялся как text/markdown только тогда, когда расширение .md было на месте и читаемым. Переименуйте его, уберите расширение или передайте как поток — и в этом тесте он деградировал в text/plain. CSV в этой специально маленькой сетке вел себя так же: text/csv появлялся только из .csv-шаблона имени. Если считать по уникальным условиям, Markdown и CSV в своём специфическом типе определялись лишь в одном из четырёх условий; обычный текст и так уже был text/plain, так что ему не было куда “схлопываться”. Сырые 48 запусков по-прежнему полезны как запись о повторяемости, но не как увеличенный знаменатель.
Есть один нюанс, который играет в пользу Tika: лживое расширение тоже не побеждает. Мой Markdown-файл, переименованный в .pdf, вернулся как text/plain, а не application/pdf. Tika не поверил в подмену; он просто не смог подтвердить истину. Падение к родительскому типу — гораздо лучший сбой, чем уверенное заявление неверного типа, а то, что text/markdown является документированным подтипом text/plain, делает такой fallback осмысленным, а не произвольным.
С CSV есть отдельная оговорка. У Tika есть статистический детектор CSV, и на этапе парсинга — это подтверждается цепочкой X-TIKA:Parsed-By, где появляется TextAndCSVParser — мой маленький грид 2×3 определялся как text/plain, а не text/csv. Это всего одно наблюдение на намеренно минимальном наборе. Более крупный или заключённый в кавычки CSV вполне может включить детектор. Я не утверждаю, что контент-детектирование CSV сломано; я утверждаю, что на этой сетке именно расширение давало text/csv.
Почему это важно в реальном пайплайне загрузки файлов
Практический сценарий здесь — маршрутизатор загрузок. Допустим, вы принимаете пользовательские файлы и отправляете их по типам: PDF — в парсер счетов, таблицы — в импортёр бухгалтерских данных, всё остальное — в текстовый индекс. Если доверять расширению, PDF с именем notes.txt попадёт не туда. И это ещё мягкий случай; более опасный вариант — полиглот-файл с безобидным расширением.
Для бинарных и разметочных тестовых файлов Tika направлял поток по содержимому даже после исчезновения имени файла, и это очень полезно, когда blob store или HTTP-обработчик уже отбросил имя. Но этот результат не покрывает длинный хвост редких форматов, неоднозначные файлы и полиглоты. А вот текстовые форматы в тесте повели себя иначе: когда пайплайн убирал имя файла, Markdown и CSV приходили как text/plain, и правила, завязанные на их конкретные media type, переставали срабатывать. Поэтому лучше сохранять исходное имя как sidecar-метаданные, а не надеяться, что детектор содержимого восстановит его сам.
Поданный контент сохранился. --text сплющил структуру.
Вторая ось — это точность сохранения содержимого, и здесь картина делится на две части. Один канонический документ с заголовками, двумя основными абзацами, маркированным списком, нумерованным списком и заключительным абзацем я отрендерил в HTML, Markdown, обычный текст, DOCX, PDF, RTF, ODT и XML; а таблицу — в HTML, Markdown, текст, DOCX, CSV и XML. Всего четырнадцать вариантов-носителей. Каждый блок содержит уникальный маркер — zztitle1, zzitem3, zztblcell_beta и так далее — так что “сохранилось” и “потерялось” здесь определяется точной проверкой подстроки, а не субъективной оценкой.
Полнота восстановления маркеров оказалась 1.000 на всех четырнадцати рендерах. Ни один из поданных маркеров не пропал: каждая помеченная ячейка таблицы, пункт списка и заголовок присутствовали. Три локальных повтора на каждом носителе после прогрева возвращали байт-в-байт одинаковый вывод --text. Но этот оракул ничего не говорит о непомеченных символах, порядке, пробелах, нормализации Unicode, повторяющемся содержимом, ссылках, заголовках, сносках или встроенных объектах. Это проверка на наличие блоков, а не доказательство полной верности документа.
Плоский текстовый вывод при этом отказывается от большей части исходной структуры.
Вот так таблица HTML выходит через --text:
Tool Throughput
zztblcell_alpha 120
zztblcell_beta 95
Строки, соединённые табами. Строка заголовка не помечена как заголовок. Нет сетки, нет границ ячеек, кроме таба, и невозможно узнать, что это когда-то было <table>. Таблица в DOCX сплющивается так же.
Списки чуть тоньше, и тут всё зависит от того, что именно было в исходнике:
| Чем маркер был в исходнике | Носители | Что возвращает --text |
|---|---|---|
Буквальный символ — в этих рендерах - был записан как обычный текст | plain text, Markdown, RTF, ODT, PDF | - сохраняется, потому что Tika просто пропускает символы через себя |
Реальная структура — HTML <li>, стиль DOCX List Bullet | HTML, DOCX | маркер исчезает полностью, и остаётся только текст пункта: с табовым отступом в HTML, обычной ненаряженной строкой в DOCX |
Tika никогда не “перерисовывает” маркер, если не получил его как текст. То же содержимое, но разный внешний вид вывода.
С Markdown всё видно особенно наглядно. Если дать Tika .md-файл с табличной разметкой через вертикальные черты, он вернёт эти символы буквально, и это выглядит как сохранение структуры. На самом деле нет: Tika просто разобрал текст и вернул байты обратно. Таблица при этом ни на что не “понятна”.
Значит, измеряемый контракт гораздо уже: все поданные маркеры сохранились, но --text не сохранил типизированные элементы и не восстановил сетку таблицы. Называть это дефектом парсера было бы мимо сути. Плоское извлечение намеренно избегает задачи классификации элементов; зато оно не может удовлетворить downstream-потребителя, которому эти типы элементов нужны. Если вам нужны типизированные блоки или восстановленные таблицы, --text — это лишь один компонент стека, а не весь стек. Другие обработчики Tika могут давать больше структуры, но в этот прогон они не входили.
Как и всегда, стандартная оговорка: все числа по сохранности здесь получены на контролируемых синтетических тестах, на одной машине, одной версии и одном JDK. Они показывают, что помеченные блоки присутствовали в выводе. Они не доказывают посимвольную точность или корректность на грязном реальном корпусе.
Метаданные: нормализованы и приятно не фантазируют

Я встроил известные значения автора, заголовка и даты создания в каждый носитель, где есть слой метаданных, и затем посмотрел, что вернулось.
| Носитель | author → dc:creator | title → dc:title | created → dcterms:created |
|---|---|---|---|
HTML (<meta name=author>, <title>) | ✅ | ✅ | не встроено |
| DOCX (core properties) | ✅ | ✅ | ✅ точное 2021-03-15T09:30:00Z |
| PDF (info dict) | ✅ | ✅ | присутствует, но это метка времени генератора — не засчитано |
ODT (meta.xml) | ✅ | ✅ | ✅ точное 2021-03-15T09:30:00Z |
| TXT / MD / CSV / RTF / XML | нет слоя метаданных | — | — |
Автор и заголовок были восстановлены на 4 из 4 носителей, где вообще есть метаданные, и — вот это как раз важно — всё нормализовано. HTML <meta name="author">, core property в DOCX, запись /Author в PDF и элемент dc:creator в ODT приходят под одним и тем же ключом dc:creator. Один потребитель, а не четыре.
С created ситуация честно более неровная. В DOCX и ODT вернулся точный встроенный timestamp 2021 года. PDF тоже отдал дату создания, но это была дата, которую поставила моя библиотека-генератор при сборке, а не то значение, которое я хотел встроить, так что я засчитываю его как присутствующее, а не как восстановленное. А форматы без слоя метаданных ничего и не показывают — и это правильный ответ. Tika не придумывает автора из тела текста.
Ломаем специально и извлекаем полезный приём для triage
Четыре враждебных входа. Файл нулевого размера. Валидный заголовок PDF с обрезанным телом. Обрезанный ZIP в DOCX. И UTF-8-файл с многобайтными символами без BOM и без объявления кодировки. Это локальные формы тестовых файлов, а не предельные значения Tika.
Базовый стенд, сгенерированные тестовые файлы, raw JSON, checksum jar и манифест окружения не приложены к этому черновику. Поэтому внешний читатель пока не может независимо воспроизвести точные знаменатели. Считай таблицы зафиксированными наблюдениями; перед публикацией нужно прикрепить стабильный пакет данных, прежде чем использовать эти числа как стороннее доказательство.
| Вход | --text / --json | Что выбросил | --detect |
|---|---|---|---|
| Файл 0 байт | exit 1, пустой stdout | ZeroByteFileException: InputStream must have > 0 bytes | exit 0 → text/plain с именем файла, application/octet-stream из потока |
| Обрезанный PDF | exit 1, пустой stdout | TikaException: TIKA-198: Illegal IOException from PDFParser | exit 0 → application/pdf |
| Обрезанный DOCX | exit 1, пустой stdout | POI FATAL: "XML document structures must start and end within the same entity" | exit 0 → тип OOXML |
| UTF-8, без BOM, без объявления кодировки | exit 0 | ничего | exit 0 → text/plain, charset UTF-8 |
Извлечение падает громко, и форма этих сбоев одинакова. Файл нулевого размера, обрезанный PDF и обрезанный DOCX каждый приводили к исключению, exit 1 и пустому stdout. CLI не прячет провал за аккуратным пустым результатом. С точки зрения процесса это безопасно — ни зависаний, ни segfault — но вызывающий код обязан проверять статус выхода и stderr, а не только смотреть на пустую строку.
Определение типа отделено от парсинга. И для обрезанного PDF, и для обрезанного DOCX --detect возвращал exit 0 с ожидаемым типом по уцелевшему началу файла, а уже парсер падал на повреждённом теле. Значит, пайплайн может использовать detection как отдельный сигнал triage до или после неудачного парсинга. Хороша ли стратегия detect-first по умолчанию, зависит от режима развёртывания: в этом тесте я не сравнивал detect-first с parse-only, а два свежих CLI-JVM могут быть плохой ценой на больших объёмах.
Определение кодировки работает. UTF-8-файл без BOM и без объявления был декодирован как UTF-8, и 日本語テスト прошёл без искажений. Небольшая оговорка для тех, кто смотрит на словари метаданных: мои чисто ASCII-файлы показывают charset=ISO-8859-1, что на ASCII-байтах неотличимо от UTF-8. Это не промах, а ничья.
Tika рядом с unstructured: типы файлов те же, задачи разные
Оба инструмента я гонял в рамках одной исследовательской сессии, но это таксономия контрактов вывода, а не симметричный бенчмарк. Инструменты оценивались по разным результатам.
Связанный обзор: обзор Unstructured.
| Apache Tika | unstructured | |
|---|---|---|
| Что я измерял | сохранность содержимого: что-нибудь потерялось или нет? | точность классификации элементов: правильно ли каждый блок получил свой тип? |
| Результат | все поданные маркеры присутствуют во всех четырнадцати рендерах | в отдельном тесте на классификацию обычная текстовая таблица дала recall по Table на уровне 0.000, а один заголовок с глаголом был отнесён к narrative text |
| Возвращаемые типизированные элементы | нет — никакой структуры обратно не приходит | Title, NarrativeText, ListItem, Table — именно то, чего Tika делать не пытается |
| OCR | заблокировано на моём хосте, нет tesseract | заблокировано на моём хосте, нет tesseract |
Плоский вывод, который сохраняет маркеры, против типизированных элементов с наблюдаемыми ошибками классификации. Выбор зависит от того, что нужно downstream-потребителю. Если это поисковый индекс или контекстное окно LLM, плоского текста может хватить. Если обработка завязана на тип элемента, путь --text у Tika этот контракт не обеспечит.
Ни у кого из нас нет чисел по отсканированным документам.
Плюсы и минусы
Плюсы
- Определение типа игнорировало лживые имена файлов в 20/20 уникальных условий для пяти форматов, определяемых по содержимому; повторные прогоны потока тоже совпали.
- Все поданные маркеры сохранились во всех 14 рендерах-носителях, включая помеченные ячейки таблиц и пункты списков.
- Повторяемость подтверждена в трёх локальных повторах: каждый носитель возвращал байт-в-байт одинаковый текст в этой среде.
- Метаданные нормализуются между форматами —
dc:creator/dc:title/dcterms:createdнезависимо от исходного формата, восстановлены на 4/4 носителях с метаданными. - По-настоящему без внешних зависимостей для протестированных форматов: PDF с текстовым слоем, DOCX, ODT, RTF, HTML разбираются из одного jar без внешних бинарников.
- Чисто работает на OpenJDK 26 — без ограничения только на LTS.
- Детектирование корректно остаётся успешным (exit 0) на обрезанных бинарниках, давая надёжный сигнал для triage при сбое парсинга.
- Apache-2.0, зрелый, активно поддерживается.
Минусы
- Markdown и CSV зависят целиком от расширения файла; 10 из 18 ячеек без сигнатуры свалились в
text/plain, когда имя файла исчезало или было неверным. --textне возвращает типы элементов; таблицы сплющиваются в строки с табами, а структурные маркеры списков исчезают.- Извлечение падает необработанным исключением на пустых и повреждённых входах; с точки зрения самого вызова извлечения оба случая выглядят одинаково.
- Jar на 67 MB плюс холодный старт JVM на каждый запуск в CLI-режиме.
- OCR и PDF со сканами здесь вообще не тестировались — tesseract и poppler отсутствовали, так что никаких выводов об этом пути я не делаю.
- Все числа здесь — синтетическая ground truth на одной машине и одной версии. Точность на реальном корпусе, зашифрованные файлы, встроенные/рекурсивные документы и производительность на масштабе не измерялись.
Кому стоит использовать, а кому — нет
Tika подходит, когда у вас есть уже имеющиеся файлы, а на выходе нужно текст плюс метаданные, пригодные для индексации. Поисковая индексация, e-discovery, архивная обработка, подача корпуса в LLM, построение слоя проверки типа контента в пайплайне загрузки. Его удобно использовать как первый этап triage и нормализации перед чем-то более умным: определить протестированные типы, извлечь плоский текст и передать дальше с явными проверками на то содержимое, которое ваш пайплайн не может позволить себе потерять.
Лучше пропустить его — точнее, не ограничиваться --text — если вам нужны типизированные элементы, восстановленные таблицы или макет документа. Пропустить его стоит и в случае сканов, по крайней мере пока вы сами не установите tesseract и не прогоните собственные числа, потому что у меня их нет. Для работы с большими объёмами сравнивайте библиотечный или серверный режим с CLI на репрезентативных документах. В этом малом файловом стенде заметен был старт процесса, но пропускная способность и стоимость ресурсов не измерялись.
Самая частая ловушка: если ваш слой хранения убирает имена файлов, а вы работаете с Markdown или CSV, не полагайтесь на Tika в различении этих форматов от обычного текста. Сохраняйте оригинальное имя.
Альтернативы и место Thunderbit
Сначала честная рамка: здесь сравнение идёт по типу входных данных, а не по качеству. Tika — это бесплатный self-hosted инструмент Apache-2.0 для разбора файлов. Файлов, которые уже лежат у вас на диске или в bucket’е. Он не ходит за страницами, не исполняет JavaScript, не занимается антибот-защитой и не делает вид, будто умеет.
Именно на этой границе в архитектуру может войти managed-сервис веб-извлечения, в том числе наш Thunderbit: он забирает живые веб-страницы, тогда как Tika разбирает файлы, уже находящиеся у вас. Эта статья не сравнивала эти сервисы с Tika, и они не являются заменой друг другу для одного и того же входа.
Чёткое разделение такое: Tika — для документов, которые уже у вас есть; managed extraction API — для веб-страниц, которые вам ещё нужно получить. Во многих пайплайнах используются оба подхода: обход и извлечение на веб-стороне, Tika — для PDF и DOCX-вложений, которые возвращаются обратно.
Если вы сравниваете с более широким open-source полем, я уже писал полное сравнение open-source scraper-ов, обзор самых полезных scraping-проектов на GitHub, практический обзор Crawl4AI с разбором Markdown-подхода на базе браузера и более общий обзор инструментов для парсинга данных. Для no-code маршрута есть и пошаговый материал о том, как собрать данные с сайта с помощью AI.
Попробовать Thunderbit для извлечения веб-данных
Итог
Стоит ли использовать Apache Tika? Да, если ваша задача — превратить разнородные файлы в плоский текст и нормализованные метаданные, а затем проверять поля или маркеры, которые ваш пайплайн не может позволить себе потерять.
Самой сильной частью этого прогона был детектор. Он возвращал ожидаемый тип в 20 из 20 уникальных условий для пяти форматов, определяемых по содержимому, включая потоки без имени файла. Все поданные маркеры сохранились во всех четырнадцати рендерах, а вывод в трёх локальных повторах совпадал байт-в-байт. Это полезное доказательство. Но всё ещё синтетическое. То, что всё это работает из одного jar на этом JDK и без внешних бинарников для протестированных путей без OCR, делает развёртывание приятно скучным.
Но размеры надо понимать правильно. Любая таблица, которую вы ему скормите, вернётся строками, соединёнными табами. Любой структурный маркер списка исчезнет. Markdown и CSV теряют свою идентичность сразу, как только пропадает имя файла. Пустые и повреждённые файлы выбрасывают ошибки одинаковой формы, и чтобы различить их, нужен отдельный вызов detect. А про OCR — то, что многих пользователей Tika интересует больше всего, — мне сказать нечего: я не смог это запустить и не буду гадать.
В этих границах Tika делает неброскую работу с редкой надёжностью. Он читает байты, а не надпись на коробке. Только не просите его сказать, какой формы были эти байты.
Попробовать Thunderbit для извлечения веб-данных Get Started Free
FAQ
Определяет ли Apache Tika тип файла правильно, если расширение неверное?
Для пяти протестированных форматов, определяемых по содержимому, да. PDF, DOCX, RTF, HTML и XML во всех 20 уникальных логических условиях (30 сырых запусков с повторяющимися потоковыми прогонками) определялись как ожидаемые media type, даже при ложных расширениях, полном отсутствии расширения и потоках без имени файла. PDF с именем .txt всё равно распознавался как application/pdf. Markdown и небольшой CSV-тест зависели от имени файла и сваливались в text/plain, когда оно отсутствовало или было неверным.
Сохраняет ли Tika таблицы и структуру документа?
В тестированном здесь режиме --text — нет. Сетки таблиц возвращались как строки, соединённые табами, без семантики ячеек и заголовков, а структурные маркеры списка (HTML <li>, стиль DOCX List Bullet) исчезали. Все поданные маркеры сохранились во всех 14 рендерах, но это не доказывает полную сохранность содержимого, и --text не возвращает типы элементов. Если нужны типизированные элементы или восстановленные таблицы, попробуй другой обработчик вывода Tika или используй рядом другой инструмент.
Может ли Apache Tika делать OCR на PDF со сканами? Tika поддерживает OCR через Tesseract, но я это не тестировал, и ни один из результатов здесь не является утверждением об этом пути. На моём тестовом хосте не было Tesseract и poppler, поэтому все OCR- и scanned-image-пути были недоступны ещё до запуска. Здесь нет никаких OCR-чисел. Если OCR — твой сценарий, установи tesseract и прогони собственный бенчмарк; считай эту часть Tika здесь неподтверждённой.
Что делает Tika с пустыми или повреждёнными файлами?
Он падает громко, а не тихо. Файл 0 байт вызывает ZeroByteFileException; обрезанный PDF вызывает TikaException из PDFParser; обрезанный DOCX вызывает XML-ошибку POI. Во всех трёх случаях exit 1 и пустой stdout, так что пустой и повреждённый вход не отличить только по вызову извлечения. А вот detection остаётся надёжным — --detect возвращал exit 0 с правильным типом и на обрезанном PDF, и на обрезанном DOCX, что делает его хорошим шагом triage перед самим парсингом.
Что не покрывало тестирование Tika? Четыре вещи, и я это проговариваю явно. OCR и сканы — заблокированы, не тестировались. Точность на реальном корпусе — все результаты основаны на контролируемых синтетических файлах с поданными маркерами, то есть измеряется сохранность относительно известных меток, а не точность на грязных реальных документах. Стоимость ресурсов, пропускная способность и пиковая память — я их не измерял. И длинный хвост заявления о “тысяче типов файлов”: я тестировал девять репрезентативных форматов без внешних зависимостей, а не весь каталог. Всё здесь — Tika 3.3.2 на OpenJDK 26.0.1, macOS arm64, одна машина.


