Apache Tika es el kit de herramientas de análisis de documentos de la Apache Software Foundation: le pasas un archivo de casi cualquier tipo y te devuelve texto plano más un diccionario de metadatos normalizado. El README del proyecto presume de más de mil tipos de archivo soportados, y Tika lo consigue empaquetando él mismo las librerías especializadas — PDFBox para PDF, Apache POI para documentos de Office, jsoup para HTML, un lector ODF para ODT —, de modo que todo se distribuye como un único jar "gordo" sin nada que descargar en el momento del análisis. En una canalización de datos es la etapa inicial, la menos vistosa: el componente que precede a un índice de búsqueda, un conjunto de revisión para e-discovery o un corpus para un LLM, y que convierte un montón heterogéneo de archivos en algo uniforme. En el fondo son dos tareas: averiguar qué es un flujo de bytes, y luego sacarle el texto y los metadatos.
Es la herramienta menos exigente que he instalado en mucho tiempo. Un jar, java -jar tika-app-3.3.2.jar --text file.pdf, sin archivo de configuración, sin pesos de modelo, sin ningún paso posterior a la instalación, y funcionó sin problemas en un JDK de última hornada que esa misma tarde dejó tiesas a otras herramientas Java en el mismo equipo. Pero la promesa del catálogo no era lo que quería comprobar; la pregunta comprobable es más estrecha. Cuando el archivo miente, ¿qué hace Tika en realidad? Así que monté un conjunto de pruebas controlado donde cada bloque de contenido lleva un token identificador único, rendericé el mismo documento lógico en nueve formatos contenedor y luego lo ataqué todo con extensiones incorrectas, extensiones ausentes, sin nombre de archivo, archivos de cero bytes y binarios a medio escribir.
La detección es donde vive el comportamiento interesante. Renombré un PDF a .txt y le pregunté a Tika qué era; respondió application/pdf. Después eliminé el nombre de archivo por completo, envié los bytes en crudo por stdin, y obtuve la misma respuesta. En los cinco formatos detectables por contenido de mi conjunto, eso se cumplió en las 20 condiciones lógicas únicas: tres condiciones de nombre de archivo más una condición sin nombre de archivo por formato. El harness ejecutó el caso de stream tres veces bajo etiquetas distintas, produciendo 30 ejecuciones brutas correctas, pero esas repeticiones no son evidencia independiente. PDF y RTF exponen bytes reconocibles; DOCX expone su contenedor; HTML y XML se pueden identificar por el marcado o por el contenido raíz. Mecanismos distintos, mismo resultado útil en este conjunto de pruebas: la extensión no se impuso al contenido. Luego está el régimen de la familia de texto, donde Markdown cae a text/plain en cuanto el nombre de archivo es incorrecto o desaparece. Aquí su identidad dependía por completo de .md.
Dos límites para cualquier cifra que venga después. Probé Apache Tika 3.3.2 — comprobado el 27 de julio de 2026, seguía siendo la última versión estable; la rama 4.0.0 solo existe como builds alpha y beta en Maven Central. El proyecto rondaba las 3,9 mil estrellas en GitHub cuando lo comprobé el 27 de julio de 2026, y tiene licencia Apache-2.0, de las más despreocupadas que existen para uso comercial. Y no probé OCR en absoluto. Ni una página escaneada, ni un PDF de solo imagen. Tesseract y poppler no están instalados en la máquina donde ejecuté esto, así que cualquier ruta de OCR quedó bloqueada antes de arrancar. No hay cifras de OCR aquí porque no hay cifras de OCR, punto.
Qué es Tika, en cuanto dejas de leer el marketing de la caja
La suposición habitual es que Apache Tika es un conversor de documentos: le das un DOCX y te devuelve Markdown limpio, con encabezados y tablas intactos. No es eso, y cuanto antes quede claro, mejor queda la herramienta.
La ruta probada aquí tiene tres etapas relevantes: un detector de tipo de contenido, un dispatcher que entrega los bytes al parser correcto, y el manejador de salida --text de la CLI, que emite texto plano junto con metadatos disponibles por separado. En ese contrato de salida no hay objetos Title, ni ListItem, ni una rejilla de tabla reconstruida. Tika también expone otros manejadores y APIs, incluida una salida orientada a XHTML/SAX; no los probé. Toda conclusión sobre estructura que aparece más abajo se refiere por tanto a tika-app --text, no a la afirmación de que el toolkit carezca de un flujo de eventos estructurado en cualquier otro sitio.
Suena a limitación, y en un sentido lo es. Pero también significa que Tika no tiene nada que clasificar mal, que es justo la apuesta contraria a la que hacen sus primos más ruidosos.
La detección sigue un orden documentado: primero los bytes de firma, después la inspección de la raíz XML, luego el patrón del nombre de archivo, y por último cualquier tipo que hayas indicado tú mismo (así lo describe la documentación de detección de Tika). Solo cuando el tipo queda resuelto, el dispatcher entrega los bytes al parser empaquetado correspondiente: PDFBox, POI, jsoup, TextAndCSVParser para la familia de texto.
Esa separación entre detectar y parsear no es una anécdota interna. Es la razón por la que un archivo demasiado roto para parsearse puede seguir tipándose correctamente, y eso se convierte en el truco más práctico que ofrece Tika cuando las cosas empiezan a fallar.
Instalación: un jar, una orden y una JVM poco quisquillosa
Instalarlo es descargar un archivo. tika-app-3.3.2.jar desde Maven Central pesa unos 67 MB — un jar "gordo" que empaqueta todos los parsers — y a partir de ahí es java -jar tika-app-3.3.2.jar --text file.pdf. Sin archivo de configuración, sin pesos de modelo, sin paso posterior a la instalación, sin una cadena de brew install que seguir.
Lo del JDK me sorprendió. Ejecuté todo en OpenJDK 26.0.1, una build no-LTS de última generación, y --version, --text, --metadata y --detect devolvieron todos código de salida 0 sin ninguna queja de compatibilidad. Merece mencionarse porque ese mismo día, en el mismo equipo, sometí a Apache Nutch a las mismas pruebas y su ciclo de rastreo no arrancaba en absoluto con JDK 26: necesita un LTS de 21 o inferior, por la eliminación de SecurityManager en los JDK más recientes. A Tika le dio igual. Si has estado evitando herramientas de la JVM por ese tipo concreto de dolor de cabeza, Tika no es donde te va a morder.
Dos deducciones honestas sobre la instalación. La CLI levanta una JVM nueva en cada invocación, así que el arranque en frío es real: ejecutar 131 invocaciones para mi harness llevó cerca de un minuto, casi todo calentamiento de la JVM. Si procesas archivos a volumen, te conviene la librería o el modo servidor, no un bucle de shell alrededor del jar. Y la promesa de "sin dependencias" tiene un límite claro: extraer la capa de texto de un PDF no necesita nada externo, pero el OCR sí necesita tesseract y poppler. PDFs con capa de texto, DOCX, ODT, RTF, HTML, XML, TXT, Markdown y CSV se analizaron todos en un equipo sin ninguno de esos binarios instalados. Los documentos escaneados no habrían funcionado, y no fingí lo contrario.
Ese contraste se nota aún más frente a la librería hermana que probé el mismo día, unstructured, cuya ruta para PDF electrónico quedó bloqueada por completo porque importar su módulo de PDF arrastra la pila de inferencia (torch y compañía) ya al cargarlo, antes incluso de que se elija la estrategia, así que ni la estrategia "rápida" se puede importar sin eso. Tika analizó la capa de texto del mismo PDF con un simple java -jar.
La prueba de la extensión mentirosa: detección de tipo MIME que ignora cómo bautizaste el archivo

Ocho formatos, cada uno presentado con una extensión correcta, una extensión incorrecta a propósito o sin extensión, más un flujo de bytes sin nombre de archivo por stdin. Eso da 32 condiciones lógicas únicas. El harness original también ejecutó los mismos bytes de stream una vez bajo cada etiqueta de nombre de archivo, lo que arrojó 48 ejecuciones brutas; esas tres filas de stream se reducen a una sola condición porque stdin no lleva nombre de archivo.
| Fixture | Tipo real | Renombrado a | Ext. correcta | Ext. mentirosa | Sin ext. | Stream en crudo, sin nombre |
|---|---|---|---|---|---|---|
application/pdf | .txt | ✅ | ✅ | ✅ | ✅ | |
| DOCX | OOXML wordprocessingml | .jpg | ✅ | ✅ | ✅ | ✅ |
| RTF | application/rtf | .html | ✅ | ✅ | ✅ | ✅ |
| HTML | text/html | .csv | ✅ | ✅ | ✅ | ✅ |
| XML | application/xml | .txt | ✅ | ✅ | ✅ | ✅ |
| Texto plano | text/plain | .pdf | ✅ | ✅ | ✅ | ✅ |
| Markdown | text/markdown | .pdf | ✅ | ❌ text/plain | ❌ text/plain | ❌ text/plain |
| CSV | text/csv | .txt | ✅ | ❌ text/plain | ❌ text/plain | ❌ text/plain |
(La columna de stream agrupa las tres condiciones de extensión, porque sin nombre de archivo no hay nada que el patrón glob pueda leer.)
Los cinco formatos detectables por contenido — PDF, DOCX, RTF, HTML y XML — acertaron el tipo real en 20 de 20 condiciones únicas (y 30 de 30 ejecuciones brutas del harness, incluidas las repeticiones de stream). Un PDF llamado report.txt siguió siendo un PDF. Un DOCX llamado photo.jpg siguió siendo un DOCX. Ninguno necesitó nombre de archivo. Esto no significa que los cinco usen firmas de bytes fijas: PDF y RTF tienen cabeceras reconocibles, DOCX es un contenedor basado en ZIP, y HTML/XML se detectan por el marcado o por el contenido raíz. En estas pruebas, la extensión mentirosa no ganó.
Luego llega el régimen de la familia de texto. Markdown solo se resolvió como text/markdown cuando la extensión .md estaba presente y era legible. Renómbralo, quítale la extensión o envíalo como stream, y en esta prueba degradó a text/plain. CSV se comportó igual en esta rejilla deliberadamente pequeña: text/csv solo apareció gracias al patrón de .csv. Contando condiciones únicas, Markdown y CSV resolvieron como su tipo específico en una de cada cuatro condiciones; el texto plano ya era text/plain, así que no había nada de lo que "caer". El harness bruto de 48 ejecuciones sigue siendo útil como registro de repetibilidad, pero no como denominador más amplio.
Un detalle juega a favor de Tika aquí: la extensión mentirosa tampoco gana. Mi fixture de Markdown renombrado a .pdf volvió como text/plain, no como application/pdf. Tika no se creyó la mentira; simplemente no pudo confirmar la verdad. Degradar al tipo padre es un fallo mucho mejor que afirmar con seguridad algo incorrecto, y que text/markdown sea un subtipo documentado de text/plain hace que ese comportamiento por defecto sea coherente, no arbitrario.
Hay una salvedad específica con CSV. Tika tiene un detector estadístico de CSV, y en tiempo de análisis — confirmado porque TextAndCSVParser aparece en la cadena X-TIKA:Parsed-By — mi pequeña rejilla de 2 columnas por 3 filas resolvió como text/plain en lugar de text/csv. Es una única observación sobre un fixture deliberadamente mínimo. Un CSV más grande o con comillas bien podría activar el detector. No estoy afirmando que la detección de contenido para CSV esté rota; afirmo que, en esta rejilla, lo que produjo text/csv fue la extensión.
Por qué esto importa en una canalización real de subidas
El escenario concreto es un router de subidas. Digamos que aceptas archivos que suben los usuarios y los encaminas por tipo: PDFs al parser de facturas, hojas de cálculo al importador contable, todo lo demás a un índice de texto. Si confías en la extensión, alguien que sube un PDF llamado notes.txt acaba en la rama equivocada — y ese es el caso benigno; la versión hostil es un archivo políglota con una extensión de aspecto inocente.
Para los fixtures binarios y de marcado probados aquí, Tika encaminó por contenido incluso después de que el nombre de archivo desapareciera, lo cual es útil cuando un almacén de blobs o un manejador de cuerpo HTTP ya lo ha descartado. Este resultado no cubre la cola larga de Tika, archivos ambiguos ni políglotas. Los fixtures de la familia de texto se comportaron distinto: cuando la canalización eliminaba los nombres de archivo, Markdown y CSV llegaban como text/plain, así que las reglas ligadas a sus tipos de medio específicos dejaban de dispararse. Conserva el nombre de archivo original como metadato auxiliar en lugar de esperar que la detección de contenido lo reconstruya.
El contenido incrustado sobrevivió. --text aplastó la estructura.
La fidelidad es el segundo eje, y se divide con claridad en dos. Renderé un documento canónico (encabezados, dos párrafos de cuerpo, una lista con viñetas, una lista numerada, un párrafo de cierre) en HTML, Markdown, texto plano, DOCX, PDF, RTF, ODT y XML, más un documento con tabla en HTML, Markdown, texto, DOCX, CSV y XML. Catorce renderizados contenedor. Cada bloque lleva un token único — zztitle1, zzitem3, zztblcell_beta y así sucesivamente —, de manera que "sobrevivió" frente a "se perdió" es una comprobación exacta de subcadena, no una valoración subjetiva.
La recuperación de tokens marcadores salió 1.000 en los catorce renderizados. No se perdió ni un solo token incrustado: cada celda de tabla, elemento de lista y encabezado etiquetado estaba presente. Tres repeticiones locales por contenedor tras el calentamiento devolvieron una salida --text idéntica byte a byte. Este oráculo no dice nada sobre caracteres sin etiquetar, orden, espacios en blanco, normalización Unicode, contenido repetido, enlaces, cabeceras, notas al pie u objetos incrustados. Es una comprobación de presencia de bloques, no una prueba de fidelidad documental completa.
La salida en texto plano renuncia a la mayor parte de la estructura de origen.
Así sale del --text el documento con la tabla en HTML:
Tool Throughput
zztblcell_alpha 120
zztblcell_beta 95
Líneas unidas por tabuladores. La fila de cabecera no queda marcada como cabecera. No hay rejilla, ni límites de celda más allá de un tabulador, ni forma de saber que aquello fue alguna vez una <table>. La tabla del DOCX se aplana igual.
Las listas son más sutiles, y se separan según lo que realmente contenía la fuente:
| Qué era la viñeta en la fuente | Contenedores | Qué devuelve --text |
|---|---|---|
Un carácter literal — estos renderizados escribieron - como texto real | texto plano, Markdown, RTF, ODT, PDF | el - sobrevive, porque Tika está pasando los caracteres tal cual |
Estructura real — un <li> de HTML, un estilo List Bullet de DOCX | HTML, DOCX | el marcador desaparece por completo y solo queda el texto del elemento: con sangría en HTML, una línea plana y sin adornos en DOCX |
Tika nunca vuelve a renderizar un marcador que no recibió como texto. Mismo contenido, aspecto de salida distinto.
El caso de Markdown lo deja claro. Dale a Tika un archivo .md con una tabla de barras verticales y las barras vuelven tal cual, lo que parece preservación de estructura. No lo es. Tika lo analizó como texto y devolvió los bytes. Nadie entendió esa tabla.
Así que el contrato medido es más estrecho: todos los marcadores plantados sobrevivieron, mientras que --text no preservó elementos tipados ni una rejilla de tabla reconstruible. Llamar a eso un defecto del parser se quedaría corto. La extracción plana evita deliberadamente el problema de clasificar elementos; y por eso mismo es incapaz de satisfacer a un consumidor posterior que necesite esos tipos. Si necesitas bloques tipados o tablas reconstruidas, --text es una pieza de la pila, no toda la pila. Otros manejadores de Tika pueden exponer más estructura, pero quedaron fuera de esta prueba.
Advertencia estándar para cualquier cifra de fidelidad aquí: proceden de fixtures sintéticos controlados en una máquina, una versión, un JDK. Demuestran que los bloques etiquetados estaban presentes en la salida. No establecen preservación carácter por carácter ni precisión sobre un corpus real y desordenado.
Metadatos: normalizados y, para bien, poco dados a inventar

Incrusté valores conocidos de autor, título y fecha de creación en cada contenedor que tiene capa de metadatos, y luego comprobé qué devolvía.
| Contenedor | autor → dc:creator | título → dc:title | creado → dcterms:created |
|---|---|---|---|
HTML (<meta name=author>, <title>) | ✅ | ✅ | no incrustado |
| DOCX (propiedades del núcleo) | ✅ | ✅ | ✅ exacto 2021-03-15T09:30:00Z |
| PDF (diccionario info) | ✅ | ✅ | presente, pero era la marca de tiempo del propio generador — no puntúa |
ODT (meta.xml) | ✅ | ✅ | ✅ exacto 2021-03-15T09:30:00Z |
| TXT / MD / CSV / RTF / XML | sin capa de metadatos | — | — |
Autor y título se recuperaron en 4 de 4 contenedores con metadatos, y — esto es lo que vale la pena — llegan normalizados. Un <meta name="author"> de HTML, una propiedad de núcleo de DOCX, una entrada /Author de PDF y un elemento dc:creator de ODT llegan todos bajo la misma clave dc:creator. Escribes un consumidor, no cuatro.
created es el tambaleo honesto. DOCX y ODT devolvieron mi marca de tiempo exacta de 2021 incrustada. El PDF devolvió una fecha de creación, pero era la que estampó mi propia librería generadora al construir el archivo, no el valor que yo quería incrustar, así que lo cuento como presente, no como recuperado. Y los formatos sin capa de metadatos no devolvieron nada, que es la respuesta correcta. Tika no se inventa un autor a partir del cuerpo del texto.
Romperlo a propósito, y el truco de triaje que sale de ahí
Cuatro entradas hostiles. Un archivo de cero bytes. Un PDF válido con el cuerpo cortado. Un ZIP de DOCX truncado. Y un archivo UTF-8 con caracteres multibyte, sin BOM y sin declaración de codificación. Son formas de fixture locales, no umbrales de Tika.
El harness subyacente, los fixtures generados, el JSON en crudo, el checksum del jar y el manifiesto del entorno no están enlazados públicamente aquí, así que un lector externo no puede reproducir de forma independiente los denominadores exactos. Trata las tablas como observaciones reportadas, no como evidencia verificable por terceros.
| Entrada | --text / --json | Qué lanzó | --detect |
|---|---|---|---|
| Archivo de 0 bytes | exit 1, stdout vacío | ZeroByteFileException: InputStream must have > 0 bytes | exit 0 → text/plain con nombre, application/octet-stream desde stream |
| PDF truncado | exit 1, stdout vacío | TikaException: TIKA-198: Illegal IOException from PDFParser | exit 0 → application/pdf |
| DOCX truncado | exit 1, stdout vacío | POI FATAL: "XML document structures must start and end within the same entity" | exit 0 → tipo OOXML |
| UTF-8, sin BOM, sin declarar | exit 0 | nada | exit 0 → text/plain, charset UTF-8 |
La extracción falla de forma ruidosa, y estos fallos comparten la misma silueta. El archivo de 0 bytes, el PDF truncado y el DOCX truncado produjeron cada uno una excepción, exit 1 y stdout vacío. La CLI no traga el fallo y lo convierte en un resultado vacío y silencioso. Es seguro para el proceso en estos casos — sin colgarse, sin segfault —, pero quien la invoque debe comprobar el código de salida y stderr, no limitarse a buscar una cadena vacía.
La detección está desacoplada del parseo. En ambos binarios truncados, --detect devolvió exit 0 con el tipo esperado a partir del contenido inicial intacto; el parser falló después sobre el cuerpo roto. Una canalización puede por tanto usar la detección como señal de triaje independiente antes o después de un parseo fallido. Si conviene detectar primero depende del modo de despliegue: esta prueba no comparó detectar-primero frente a solo-parsear, y dos JVM nuevas por invocación de la CLI pueden ser la peor decisión a gran volumen.
La detección de charset funciona. El archivo UTF-8 sin BOM y sin declarar se decodificó como UTF-8 y 日本語テスト pasó intacto. Un pequeño matiz para quien lea los diccionarios de metadatos: mis fixtures puramente ASCII reportan charset=ISO-8859-1, indistinguible de UTF-8 sobre bytes ASCII. No es un fallo, es un empate.
Tika frente a unstructured: mismos tipos de archivo, trabajos distintos
Ambos se probaron en la misma sesión de investigación, pero esto es una taxonomía de contratos de salida, no un benchmark simétrico. Las herramientas se evaluaron sobre resultados distintos.
Reseña relacionada: reseña de Unstructured.
| Apache Tika | unstructured | |
|---|---|---|
| Sobre qué lo medí | fidelidad de contenido: ¿se perdió algo? | fidelidad de clasificación de elementos: ¿cada bloque recibió el tipo correcto? |
| Resultado | todos los marcadores plantados presentes en los catorce renderizados | en la prueba de clasificación aparte, una tabla en texto plano dio un recall de Table de 0.000, y un encabezado con un verbo se clasificó como texto narrativo |
| Elementos tipados devueltos | ninguno — tampoco volvió estructura | Title, NarrativeText, ListItem, Table — justo lo que Tika se niega a hacer |
| OCR | bloqueado en mi equipo, faltaba tesseract | bloqueado en mi equipo, faltaba tesseract |
Salida plana que conserva marcadores frente a elementos tipados con errores de clasificación observados. Elige según lo que necesite el consumidor posterior. Si es un índice de búsqueda o una ventana de contexto para un LLM, el texto plano puede bastar. Si depende del tipo de elemento, la ruta --text de Tika no puede ofrecer ese contrato.
Ninguno de los dos tiene cifras para documentos escaneados.
Pros y contras
Pros
- La detección de tipo de contenido ignoró nombres de archivo mentirosos en 20/20 condiciones únicas entre los cinco fixtures detectables por contenido; las ejecuciones de stream duplicadas también coincidieron.
- Todos los marcadores plantados sobrevivieron en los 14 renderizados contenedor, incluidas las celdas de tabla y los elementos de lista etiquetados.
- Repetible en tres reejecuciones locales: cada contenedor devolvió texto idéntico byte a byte dentro de este entorno.
- Metadatos normalizados entre formatos —
dc:creator/dc:title/dcterms:createdsin importar el formato de origen, recuperados en 4/4 contenedores con metadatos. - Realmente libre de dependencias para los formatos que probé: la capa de texto de PDF, DOCX, ODT, RTF y HTML se analizan desde un solo jar sin binarios externos.
- Funciona limpio en OpenJDK 26 — sin exigir quedarse en un LTS.
- La detección se mantiene correcta (exit 0) en binarios truncados, lo que da una señal de triaje fiable cuando el parseo falla.
- Apache-2.0, maduro y mantenido activamente.
Contras
- La identidad de Markdown y CSV depende por completo de la extensión del archivo; 10 de 18 celdas sin firma colapsaron a
text/plainen cuanto el nombre faltaba o era incorrecto. --textno devuelve tipos de elemento; las rejillas de tabla se aplanan en líneas unidas por tabuladores y los marcadores estructurales de lista desaparecen.- La extracción lanza errores no capturados ante entradas vacías o corruptas; los dos casos parecen idénticos si solo miras la llamada de extracción.
- Jar de 67 MB más un arranque en frío de la JVM por invocación en modo CLI.
- El OCR y los PDF escaneados no se probaron en absoluto aquí — faltaban tesseract y poppler, así que no se hace ninguna afirmación sobre esa ruta.
- Todas las cifras aquí vienen de una verdad sintética en una sola máquina y una sola versión. No se midieron la precisión sobre corpus real, archivos cifrados, documentos incrustados o recursivos, ni el rendimiento a escala.
Quién debería usarlo, y quién no
Tika encaja cuando tu entrada son archivos que ya tienes y tu salida necesita ser texto más metadatos que una máquina pueda indexar. Indexación para búsqueda, e-discovery, procesamiento de archivos, alimentar un corpus a un LLM, construir la capa de validación de tipo de contenido de una canalización de subidas. Sirve como etapa inicial de triaje y normalización delante de algo más inteligente: detecta los tipos probados, extrae texto plano y pásalo adelante con comprobaciones explícitas para el contenido que tu canalización no se puede permitir perder.
Sáltatelo — o mejor, no te quedes en --text — si necesitas elementos tipados, tablas reconstruidas o maquetación de documento. Sáltatelo si tus documentos son escaneados, al menos hasta que hayas instalado tesseract y hecho tus propias mediciones, porque yo no tengo ninguna. Para trabajo a volumen, compara la librería o el modo servidor contra la CLI sobre documentos representativos. El arranque del proceso fue visible en este harness de archivos pequeños, pero el rendimiento y el coste de recursos no se midieron.
Lo que suele pillar a la gente: si tu capa de almacenamiento elimina los nombres de archivo y trabajas con Markdown o CSV, no confíes en que Tika los distinga del texto plano. Conserva el nombre original.
Alternativas, y dónde encaja Thunderbit
Primero un encuadre justo, porque la comparación honesta aquí trata de entradas, no de calidad. Tika es un toolkit gratuito, Apache-2.0 y autoalojado para analizar archivos. Archivos que ya tienes en disco o en un bucket. No descarga páginas, no ejecuta JavaScript, no lidia con anti-bot y no finge hacerlo.
Ahí es donde puede entrar un servicio gestionado de extracción web, incluido el nuestro, Thunderbit: obtiene páginas en vivo, mientras que Tika analiza archivos que ya están en tu poder. Este artículo no comparó esos servicios frente a Tika, y no son sustitutos para la misma entrada.
La división limpia: Tika para documentos que ya tienes, una API de extracción gestionada para páginas web que necesitas ir a buscar. Muchas canalizaciones usan ambos — rastrean y extraen en el lado web, y luego pasan por Tika los adjuntos PDF y DOCX que llegan.
Si estás comparando dentro del panorama más amplio del código abierto, he escrito la comparativa completa de scrapers open source, un repaso de los proyectos de scraping más útiles en GitHub, una reseña práctica de Crawl4AI que cubre el enfoque de Markdown apoyado en navegador, y un resumen más amplio de herramientas de scraping. Para la vía sin código, también hay una guía sobre cómo extraer un sitio usando IA.
Prueba Thunderbit para extracción de datos web
Veredicto
¿Deberías usar Apache Tika? Sí, si tu trabajo consiste en convertir archivos heterogéneos en texto plano y metadatos normalizados, y validas los campos o marcadores que tu propia canalización no se puede permitir perder.
El detector fue lo más sólido de esta prueba. Devolvió el tipo esperado en 20 de 20 condiciones únicas para los cinco fixtures detectables por contenido, incluidos los streams sin nombre de archivo. Todos los marcadores plantados sobrevivieron en catorce renderizados, y la salida se repitió byte a byte en tres reejecuciones locales. Evidencia útil. Sigue siendo evidencia sintética. Hacerlo desde un solo jar en este JDK, sin binarios externos para las rutas sin OCR probadas, mantuvo el despliegue agradablemente aburrido.
Aun así, dimensiónalo bien. Cada tabla que le entregas vuelve como líneas unidas por tabuladores. Cada marcador estructural de lista desaparece. Markdown y CSV pierden su identidad en cuanto desaparece el nombre de archivo. Los archivos vacíos y los corruptos lanzan el mismo tipo de fallo, y necesitarás la llamada de detección aparte para distinguirlos. Y sobre OCR, la pregunta que más le importa a mucha gente que usa Tika, no tengo nada que ofrecer: no pude ejecutarlo, y no voy a estimarlo.
Dentro de esos límites, Tika hace un trabajo poco vistoso con una fiabilidad poco común. Lee los bytes, no la etiqueta de la caja. Solo no le preguntes qué forma tenían esos bytes.
Prueba Thunderbit para extracción de datos web Get Started Free
Preguntas frecuentes
¿Apache Tika detecta bien el tipo de archivo si la extensión es incorrecta?
Para los cinco fixtures detectables por contenido probados aquí, sí. PDF, DOCX, RTF, HTML y XML resolvieron a su tipo de medio esperado en las 20 condiciones lógicas únicas (30 ejecuciones brutas con repeticiones de stream duplicadas), incluidas extensiones engañosas, sin extensión y streams sin nombre de archivo. Un PDF llamado .txt se siguió detectando como application/pdf. Markdown y el pequeño fixture de CSV dependieron de la información del nombre de archivo y degradaron a text/plain cuando faltaba o era incorrecta.
¿Tika conserva las tablas y la estructura del documento?
No en el modo --text probado aquí. Las rejillas de tabla volvieron como líneas unidas por tabuladores sin semántica de celda ni de cabecera, y los marcadores estructurales de lista (un <li> de HTML, un estilo List Bullet de DOCX) desaparecieron. Todos los marcadores plantados sobrevivieron en los 14 renderizados contenedor, pero eso no demuestra fidelidad completa del contenido, y --text no ofrece tipado de elementos. Para elementos tipados o tablas reconstruidas, prueba otro manejador de salida de Tika o usa otra herramienta junto a él.
¿Puede Apache Tika hacer OCR sobre PDF escaneados? Tika soporta OCR a través de Tesseract, pero no lo probé, y ninguno de estos resultados dice nada sobre esa ruta. Tesseract y poppler no estaban instalados en mi equipo de pruebas, así que cualquier ruta de OCR o de imagen escaneada quedó bloqueada antes de arrancar. No hay cifras de OCR en ningún sitio de esta prueba. Si tu caso de uso es OCR, instala tesseract y haz tu propio benchmark; trata esa parte de Tika como no verificada aquí.
¿Qué hace Tika con archivos vacíos o corruptos?
Falla de forma ruidosa en lugar de silenciosa. Un archivo de 0 bytes lanza ZeroByteFileException; un PDF truncado lanza una TikaException desde PDFParser; un DOCX truncado lanza un error XML de POI. Los tres salen con exit 1 y stdout vacío, así que vacío y corrupto son indistinguibles solo con la llamada de extracción. La detección, en cambio, se mantiene robusta — --detect devolvió exit 0 con el tipo correcto en ambos binarios truncados, lo que la convierte en un paso de triaje fiable antes de gastar un parseo.
¿Qué no cubrió la prueba de Tika? Cuatro cosas, explícitamente. OCR e imágenes escaneadas (bloqueado, sin probar). Precisión sobre corpus real — todos los resultados son fixtures sintéticos controlados con tokens marcadores plantados, lo cual mide fidelidad frente a etiquetas conocidas, no precisión sobre documentos reales y desordenados. Coste de recursos, rendimiento y memoria pico, que no medí. Y la cola larga de la promesa de "mil tipos de archivo": probé nueve formatos representativos y sin dependencias, no el catálogo completo. Todo esto corresponde a Tika 3.3.2 sobre OpenJDK 26.0.1, macOS arm64, una sola máquina.


