Keywords
ai web scraper, web scraping tools
Content
Apache Tika は Apache Software Foundation の文書解析ツールキットです。ほぼあらゆる種類のファイルを渡すと、平文テキストと正規化されたメタデータ辞書を返してくれます。プロジェクト README では 1,000 種類を超えるファイル形式に対応すると案内されており、その仕組みは各種専門ライブラリを内包することで実現しています。PDF は PDFBox、Office 文書は Apache POI、HTML は jsoup、ODT は ODF リーダーといった具合で、解析時に外部取得が不要な単体の fat jar として配布されています。データパイプラインの中では、検索インデックスや eDiscovery のレビューセット、LLM 用コーパスの手前に置かれる地味な第一段階として働き、バラバラなファイル群を均質な形に整える役割を担います。要するに、やることは 2 つ。バイト列が何者なのかを見極め、その中からテキストとメタデータを取り出すことです。
長い間セットアップした中でも、これほど手間のかからないツールはありませんでした。jar ファイル 1 つ、java -jar tika-app-3.3.2.jar --text file.pdf で終わり。設定ファイルも、モデル重みも、インストール後の追加作業も不要でしたし、その日の午後に同じホスト上で他の Java ツールを止めてしまった最先端の JDK でも、問題なく動きました。とはいえ、今回確かめたかったのはカタログ上の対応数ではありません。もっと絞った問いです。入力がこちらをだましてきたとき、Tika は実際に何をするのか。そこで、各コンテンツブロックに固有の識別トークンを埋め込んだ制御済みの検証用データセットを作成し、同じ論理文書を 9 種類のコンテナ形式に出力したうえで、拡張子の誤り、拡張子なし、ファイル名なし、0 バイト、書きかけのバイナリといった条件を次々にぶつけてみました。
面白い挙動が見えるのは検出処理です。PDF を .txt にリネームして Tika に尋ねると、返ってきたのは application/pdf でした。さらにファイル名を完全に削除し、標準入力で生バイト列を流し込んでも、答えは同じでした。今回のセットに含めた 5 つの内容ベースで判定できる形式では、この結果が 20 個の一意な論理条件 すべてで成立しました。つまり、各形式につき「ファイル名あり 3 条件+ファイル名なしストリーム 1 条件」です。ハーネスはストリームケースを別ラベルで 3 回ずつ実行したため、生の実行回数としては 30 回の成功がありましたが、それらの繰り返しは独立した証拠ではありません。PDF と RTF は特徴的なバイト列を持ち、DOCX はコンテナ構造を露出し、HTML と XML はマークアップやルート要素から識別できます。機構は違っても、この検証セットでは有効な結果は同じでした。拡張子は内容を上書きしなかったのです。一方でテキスト系では、ファイル名が間違っていたり消えていたりすると、Markdown はたちまち text/plain に落ちます。ここでは .md が識別のすべてでした。
以降の数値には 2 つの前提があります。検証対象は Apache Tika 3.3.2 で、2026 年 7 月 27 日時点ではなお最新の安定版でした。4.0.0 系は Maven Central で alpha と beta のビルドがあるだけです。GitHub スター数は同日でおよそ 3.9k、ライセンスは Apache-2.0 で、商用利用のしやすさという意味ではかなり気楽な部類です。そして、OCR は一切テストしていません。 スキャン文書も、画像のみの PDF も 1 つも試していません。今回実行したマシンには Tesseract も poppler も入っていなかったため、OCR の経路は最初から遮断されていました。ここに OCR の数値がないのは、OCR の数値が存在しないからです。それ以上でも以下でもありません。
箱の宣伝文句を読むのをやめたとき、Tika は何者か
Apache Tika は文書変換ツールだ、というのがよくある誤解です。つまり DOCX を食わせれば、見出しや表を保ったきれいな Markdown が返ってくる、と考えられがちです。実際にはそうではありません。そこが早くはっきりしているほど、むしろツールの見え方は良くなります。
今回のテストで見た経路には、3 つの重要な段階があります。まず content-type detector があり、次に適切な parser にバイト列を渡す dispatcher、そして CLI の --text 出力ハンドラがあって、そこではフラットなテキストと個別に取得可能なメタデータが出力されます。この出力契約には Title オブジェクトも ListItem も、再構成された表のグリッドもありません。Tika には XHTML や SAX 寄りの出力を含む別のハンドラや API もありますが、今回はそれらを試していません。したがって、以下の構造に関する結論はすべて tika-app --text に対するものであり、ツールキット全体に構造化イベントストリームが存在しないという主張ではありません。
これだけ聞くと制約のように見えますし、ある意味ではその通りです。ただし裏返せば、Tika には誤分類する余地がほとんどありません。そこが、よりノイジーな類似ツールとの大きな違いでもあります。
検出の順序はドキュメント化されています。まずシグネチャのバイト列、次に XML のルート要素、次にファイル名の glob、最後にユーザーが明示した型、という順です(Tika 自身の検出ドキュメント に説明があります)。型が確定して初めて、dispatcher が対応する組み込み parser にバイト列を渡します。PDFBox、POI、jsoup、そしてテキスト系には TextAndCSVParser です。
この「先に検出、後で解析」という分離は、単なる内部事情ではありません。壊れすぎていて解析できないファイルでも型判定はできる、というのがこの設計の利点であり、壊れ始めた場面で Tika が最も実用的になる理由です。
セットアップ:jar 1 つ、コマンド 1 つ、気難しくない JVM
インストールはダウンロードするだけです。Maven Central から取得できる tika-app-3.3.2.jar は約 67 MB の fat jar で、あとは java -jar tika-app-3.3.2.jar --text file.pdf を叩くだけ。設定ファイルも、モデル重みも、インストール後の追加処理も、brew install の連鎖もいりません。
JDK まわりは少し意外でした。今回は OpenJDK 26.0.1、つまり LTS ではない最先端ビルドで動かしましたが、--version、--text、--metadata、--detect のいずれも exit 0 で、互換性に関する文句はありませんでした。ここを強調するのは理由があります。同じホストで同じ時間帯に Apache Nutch も試したのですが、そちらは JDK 26 ではクロールサイクルが全く動かず、新しい JDK で SecurityManager が削除された影響から、21 以下の LTS を要求しました。Tika はそんなことを気にしません。JVM ツールに対してそうした種類の苦労を避けたい人にとって、Tika はその痛点ではありません。
セットアップ面での率直な注意点も 2 つあります。CLI は実行ごとに新しい JVM を起動するため、コールドスタートは現実です。今回のハーネスで 131 回の呼び出しを走らせたところ、ほとんどが JVM のウォームアップに費やされて、およそ 1 分かかりました。大量のファイルを処理するなら、jar をシェルループで回すより、ライブラリ版かサーバーモードを使うべきです。そして、依存ゼロの話にも限界があります。PDF のテキスト層抽出には外部依存が不要ですが、OCR には tesseract と poppler が必要です。 テキスト層を持つ PDF、DOCX、ODT、RTF、HTML、XML、TXT、Markdown、CSV は、どちらも入っていないホストで普通に解析できましたが、スキャン文書はそうはいきません。そこは正直に試していません。
同じ日に試した姉妹ライブラリ unstructured と比べると、この差はさらに鮮明です。unstructured の電子 PDF 経路は、PDF モジュールを import した時点で推論スタック(torch など)を読み込もうとして完全に止まりました。戦略分岐に入る前の段階、しかも「fast strategy」であっても、依存がないと import できません。Tika は同じ PDF のテキスト層を、ただの java -jar で解析しました。
嘘の拡張子テスト:ファイル名を無視する MIME 判定

8 形式に対して、正しい拡張子、わざと間違えた拡張子、拡張子なし、そして標準入力でのファイル名なしバイトストリームをそれぞれ与えました。これで 32 個の一意な論理条件 です。元のハーネスでは、同じストリームバイト列を各ファイル名ラベルの下でさらに 1 回ずつ実行したため、生の実行回数は 48 回でしたが、stdin にはファイル名がないので、その 3 行は 1 条件にまとめられます。
| 検証ファイル | 真の型 | 変更後 | 正しい拡張子 | 嘘の拡張子 | 拡張子なし | 生ストリーム、ファイル名なし |
|---|---|---|---|---|---|---|
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 |
(ストリーム列は 3 つの拡張子条件をまとめています。ファイル名がないので、glob が読む対象がないためです。)
内容ベースで判定できる 5 形式、つまり PDF、DOCX、RTF、HTML、XML は、20 個の一意な条件すべてで真の型に到達しました(重複したストリーム実行を含めると 30/30 の生実行でも成功)。report.txt と名付けた PDF は PDF のままでした。photo.jpg と名付けた DOCX も DOCX のままでした。どちらもファイル名を必要としません。とはいえ、これは 5 形式すべてが固定のバイトシグネチャを持つという意味ではありません。PDF と RTF は特徴的なヘッダを持ち、DOCX は ZIP ベースのコンテナであり、HTML/XML はマークアップやルート要素から検出されます。この検証セットでは、嘘の拡張子は勝てませんでした。
一方で、テキスト系の領域は別です。Markdown は .md が存在し、かつ読めるときだけ text/markdown と判定されました。リネームする、拡張子を消す、あるいはストリームで渡すと、このテストでは text/plain に落ちました。CSV も、この小さなグリッドでは同じ挙動でした。text/csv になったのは .csv の glob が使えたときだけです。ユニーク条件で数えると、Markdown と CSV はそれぞれ 4 条件中 1 条件でしか固有型に到達していません。プレーンテキストはそもそも text/plain なので、「落ちる」先は最初からありません。生の 48 回ハーネスは再現性記録としては意味がありますが、分母を大きくするものではありません。
ここで Tika に有利な点が 1 つあります。嘘の拡張子も勝てない ということです。.pdf にリネームした Markdown の検証ファイルは application/pdf ではなく text/plain で返ってきました。Tika は嘘を信じたのではなく、真実を確認できなかっただけです。親型へとフォールバックするのは、誤った断定をするよりずっと良い失敗ですし、text/markdown が text/plain の文書化されたサブタイプであることを考えると、このフォールバックには筋があります。
CSV については少し注意が必要です。Tika には統計ベースの CSV 検出器があり、解析時には X-TIKA:Parsed-By のチェーンに TextAndCSVParser が出てきたことを確認できましたが、今回の小さな 2 列×3 行のグリッドは text/csv ではなく text/plain に落ちました。これは意図的に最小化した検証用データでの 1 つの観測にすぎません。もっと大きい、あるいは引用符付きの CSV なら、検出器が反応する可能性は十分あります。CSV の内容ベース判定が壊れていると言っているのではなく、このグリッドでは text/csv を生んだのは拡張子だった、と言っているのです。
実際のアップロードパイプラインでなぜ重要なのか
具体的なシナリオは、アップロードのルーティングです。たとえばユーザーのアップロードを受け付け、型に応じて PDF は請求書パーサーへ、スプレッドシートは台帳インポータへ、それ以外はテキストインデックスへ振り分けるとします。拡張子を信用すると、notes.txt という名前の PDF が別の分岐に入ってしまいます。これはまだ穏当なケースで、もっと厄介なのは、やさしい拡張子を付けたポリグロットファイルです。
今回テストしたバイナリとマークアップの検証ファイルでは、ファイル名が消えていても Tika は内容に従って振り分けてくれました。これは、blob ストアや HTTP ボディハンドラがファイル名を捨ててしまう場面ではとても有用です。ただし、この結果は Tika の長い末尾のケース、曖昧なファイル、ポリグロットまではカバーしていません。今回のテキスト系検証ファイルは違う挙動を示しました。パイプラインがファイル名を削除すると、Markdown と CSV は text/plain として届き、それらの固有メディアタイプに紐づくルールは発火しなくなります。内容ベース判定にファイル名の復元まで期待せず、元の名前は sidecar メタデータとして保持してください。
埋め込んだ内容は生き残った。--text は構造を平坦化した。
忠実性は 2 つ目の軸です。そして結果はきれいに二分されました。1 つの正規文書(見出し、本文 2 段落、箇条書き、番号付きリスト、締めの段落)を HTML、Markdown、プレーンテキスト、DOCX、PDF、RTF、ODT、XML に出力し、さらに表の文書を HTML、Markdown、テキスト、DOCX、CSV、XML に出力しました。合計 14 のキャリア表現です。各ブロックには zztitle1、zzitem3、zztblcell_beta など固有トークンを埋め込んであるので、「残った」「失われた」は感覚ではなく厳密な部分文字列チェックで判定できます。
マーカートークンの再現率は 14/14 のレンダリングすべてで 1.000 でした。 埋め込んだトークンは 1 つも欠けていません。タグ付きの表セル、リスト項目、見出しはすべて出力に含まれていました。ウォームアップ後に各キャリアを 3 回ずつ繰り返した結果も、--text の出力はバイト単位で一致しました。ただし、このオラクルが教えてくれるのは、タグのない文字、並び順、空白、Unicode 正規化、重複コンテンツ、リンク、ヘッダ、脚注、埋め込みオブジェクトについてではありません。これはブロックが存在したかどうかの確認であって、文書全体の忠実性を証明するものではありません。
フラットテキスト出力は、ソースの構造の大半を手放します。
これは HTML の表文書を --text で出した結果です。
Tool Throughput
zztblcell_alpha 120
zztblcell_beta 95
タブ区切りの行になっています。ヘッダ行はヘッダとしては示されません。グリッドもなければ、タブ以外のセル境界もなく、これが <table> だったことを知る手段もありません。DOCX の表も同じように平坦化されます。
リストは少し複雑で、ソースが実際に何を含んでいたかによって分かれます。
| ソース中での箇条書きの正体 | キャリア | --text が返すもの |
|---|---|---|
文字そのもの — これらのレンダリングはすべて、実際のテキストとして - を書き出した | プレーンテキスト、Markdown、RTF、ODT、PDF | Tika は文字をそのまま通すので、- は残る |
本物の構造 — HTML の <li>、DOCX の List Bullet スタイル | HTML、DOCX | マーカーは完全に消え、項目テキストだけが返る。HTML ではタブインデント付き、DOCX では装飾なしの 1 行になる |
Tika は、テキストとして受け取っていないマーカーを再構成しません。中身が同じでも、見た目は変わります。
Markdown の例は、この点を端的に示します。パイプテーブルを含む .md ファイルを Tika に渡すと、パイプはそのまま文字として返ってきます。見た目だけ見れば、構造を保っているように見えるでしょう。しかし違います。Tika はそれをテキストとして読み、バイト列をそのまま返しただけです。その表を理解した処理はどこにもありません。
したがって、測定された契約はもっと狭いものです。埋め込んだマーカーはすべて生き残った一方で、--text は型付き要素や再構成可能な表グリッドを保持しませんでした。 これをパーサーの欠陥と呼ぶのは、論点を外しています。フラット抽出は、要素の分類問題をあえて避ける設計です。ただし、その代償として、そうした要素型を必要とする下流の利用者には応えられません。型付きブロックや再構成された表が必要なら、--text はスタックの一部であって、スタック全体ではありません。他の Tika ハンドラならもっと構造を出せるかもしれませんが、今回の実行範囲外です。
忠実性の数値についての通常の注意書きもあります。ここでの結果は、1 台のマシン、1 バージョン、1 つの JDK 上での制御済み人工データに基づいています。タグ付きブロックが出力に含まれていたことは示せますが、文字単位の完全保存や、雑多な実データ群での正確性までは示していません。
メタデータ:正規化され、無理に作り話をしない

メタデータ層を持つ各キャリアに、既知の author、title、created 値を埋め込み、それがどう戻るかを確認しました。
| キャリア | 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 | メタデータ層なし | — | — |
author と title は、メタデータを持つ 4/4 のキャリア から回収できました。そして重要なのは、これらが正規化されていることです。HTML の <meta name="author">、DOCX の core property、PDF の /Author、ODT の dc:creator は、すべて同じ dc:creator キーにまとまって返ってきます。つまり、利用側は 4 種類ではなく 1 種類だけを書けばよいのです。
created は正直に揺れます。DOCX と ODT は、埋め込んだ 2021 年のタイムスタンプをそのまま返しました。PDF も作成日時を返しましたが、それは私が埋め込もうとした値ではなく、生成ライブラリがビルド時に付けた日時でした。そのため、ここでは「存在した」とは採点しますが、「回収できた」とはしません。そもそもメタデータ層のない形式では何も出てきませんが、それが正しい答えです。Tika は本文のテキストから作者を推測したりはしません。
わざと壊したときに見える、三次対応の使い方
4 つの敵対的入力を用意しました。0 バイトのファイル。本文を切り落とした有効な PDF ヘッダ。途中で切れた DOCX の ZIP。BOM もエンコーディング宣言もない、マルチバイト文字を含む UTF-8 ファイルです。これらは Tika の境界条件ではなく、ローカルな検証用の形です。
生成した検証用ファイル、元データ、raw JSON、jar の checksum、環境マニフェストは、この草稿にはリンクしていません。したがって、外部の読者が同じ分母を独立再現することはまだできません。表は報告された観測結果として扱ってください。第三者の証拠として使うなら、公開時には安定した一式を添付するべきです。
| 入力 | --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 type |
| UTF-8、BOM なし、宣言なし | exit 0 | なし | exit 0 → text/plain、charset UTF-8 |
抽出は大きな声で失敗し、しかもその失敗の外形は共通しています。 0 バイトファイル、途中で切れた PDF、途中で切れた DOCX は、それぞれ例外、exit 1、stdout 空を返しました。CLI は失敗を都合よく空結果に丸めません。今回のケースではプロセスとしては安全でしたが(ハングもセグフォもなし)、呼び出し側は空文字列を見るだけではなく、終了コードと stderr を確認しなければなりません。
検出と解析は分離されています。 途中で切れた両方のバイナリについて、--detect は壊れていない先頭部分から期待通りの型を返して exit 0 でした。その後、壊れた本文で parser が失敗します。したがって、パイプラインは失敗した解析の前後どちらかで、検出結果を別の三次対応シグナルとして使えます。detect-first がデフォルトとして良いかは、配備形態次第です。このテストでは detect-first と parse-only のベンチマークはしていませんし、大量処理では新しい CLI JVM を毎回起動するやり方は得策でないかもしれません。
文字コード検出は機能します。 BOM なし、宣言なしの UTF-8 ファイルは UTF-8 としてデコードされ、日本語テスト もそのまま通りました。メタデータ辞書を見る人向けの小さな注意として、純 ASCII の検証ファイルは charset=ISO-8859-1 と返しますが、ASCII バイト上では UTF-8 と区別できません。これは取りこぼしではなく、引き分けです。
Tika と unstructured を並べてみる:同じファイル形式、違う仕事
両方とも同じ調査セッションで試しましたが、これは対称的なベンチマークではなく、出力契約の分類です。評価している結果が異なります。
関連レビュー:Unstructured review。
| Apache Tika | unstructured | |
|---|---|---|
| 何を測ったか | 内容忠実性:何かが欠けていないか | 要素分類の忠実性:各ブロックに正しい型が付くか |
| 結果 | 14 のレンダリングすべてで埋め込みマーカーは残存 | 別の分類テストでは、プレーンテキストの表で Table の再現率が 0.000 で、動詞を含む見出し 1 つが narrative text に分類された |
| 返ってくる型付き要素 | なし — 構造は一切返らない | Title、NarrativeText、ListItem、Table — Tika が返さないものそのもの |
| OCR | このホストでは tesseract 不在のため不可 | このホストでは tesseract 不在のため不可 |
マーカーを保ったフラット出力と、分類誤りの観測がある型付き要素。下流の利用者が何を必要とするかで選ぶべきです。検索インデックスや LLM のコンテキストウィンドウなら、フラットテキストで十分かもしれません。要素タイプをキーにするなら、Tika の --text 経路ではその契約は満たせません。
どちらもスキャン文書の数値は持っていません。
長所と短所
長所
- 内容ベースの型判定は、5 つの内容判定可能な検証ファイルで 20/20 の一意条件すべてにおいて嘘のファイル名を無視した。重複したストリーム実行でも同じ結果だった。
- 14 のキャリア表現すべてで埋め込みマーカーが残り、タグ付き表セルやリスト項目も欠けなかった。
- ローカルで 3 回繰り返しても再現可能で、この環境では各キャリアのテキストはバイト単位で一致した。
- メタデータは形式をまたいで正規化される。元形式に関係なく
dc:creator/dc:title/dcterms:createdにまとまり、メタデータを持つ 4/4 のキャリアから回収できた。 - 今回試した形式については本当に依存不要。PDF のテキスト層、DOCX、ODT、RTF、HTML は 1 つの jar だけで外部バイナリなしに解析できた。
- OpenJDK 26 でも問題なく動き、LTS 限定ではない。
- 途中で切れたバイナリでも検出は正しく exit 0 になり、解析失敗時の三次対応シグナルとして信頼できる。
- Apache-2.0、成熟していて、現在も活発に保守されている。
短所
- Markdown と CSV の識別はファイル拡張子に完全依存しており、拡張子なしまたは誤りの条件では 18 個のシグネチャレスなセルのうち 10 個が
text/plainに落ちた。 --textは要素型を返さない。表はタブ区切りの行に平坦化され、構造的なリストマーカーは消える。- 空ファイルや破損ファイルでは例外がそのまま投げられ、抽出呼び出しだけでは 2 ケースが見分けられない。
- 67 MB の jar と、CLI モードでの実行ごとの JVM コールドスタートがある。
- OCR とスキャン画像 PDF はここでは完全に未検証。tesseract と poppler がなかったため、その経路については何も主張できない。
- ここにある数値はすべて 1 台・1 バージョンの人工データに基づくもの。実データでの精度、暗号化ファイル、埋め込み・再帰文書、大規模処理時のスループットは測っていません。
使うべき人、使うべきでない人
Tika が向いているのは、すでに手元にあるファイルを、機械がインデックスできる テキストとメタデータ に変えたいときです。検索インデックス、eDiscovery、アーカイブ処理、LLM へのコーパス投入、アップロードパイプラインの content-type 検証レイヤー構築。検出、フラットテキスト抽出、その後の受け渡しという第一段のふるい分けと正規化としてはかなり有用です。失ってはいけない内容については、明示的なチェックを付けて次段に渡してください。
逆に、型付き要素、再構成された表、文書レイアウトが必要なら、--text で止まらないでください。文書がスキャン画像なら、少なくとも tesseract を入れて自分で数値を取るまでは見送りです。ここにはその数値がありません。大量処理なら、CLI ではなくライブラリ版やサーバーモードを代表的な文書でベンチマークしてください。今回の小ファイルハーネスではプロセス起動のコストは見えましたが、スループットとリソース消費は測っていません。
人が見落としがちな点を 1 つ挙げると、保存層がファイル名を削る場合に Markdown や CSV を扱うなら、Tika にプレーンテキストと区別させることはできません。元の名前を保持してください。
代替案と、Thunderbit が位置する場所
まず公平な前提から。ここでの本当の比較は 入力 の違いです。Tika は無料で Apache-2.0、自己ホスト型のファイル解析ツールです。対象はすでにディスクやバケットにあるファイル。ページを取りに行ったり、JavaScript を実行したり、bot 対策に対応したりはしませんし、そんなふりもしません。
その境界線の先で、Thunderbit を含む管理型のウェブ抽出サービスがアーキテクチャに入ります。こちらはライブページを取得しますが、Tika は手元にあるファイルを解析します。この記事ではそれらのサービスを Tika と直接ベンチマークしていませんし、同じ入力に対する置き換えでもありません。
きれいに分けるならこうです。すでに所有している文書には Tika、取りに行く必要があるウェブページには管理型抽出 API。実際には、Web 側でクロールと抽出を行い、戻ってきた PDF や DOCX 添付には Tika を使う、というパイプラインもよくあります。
オープンソース全体で比較したい場合は、オープンソーススクレイパーの総まとめ、GitHub で特に役立つ スクレイピングプロジェクト一覧、ブラウザ依存の Markdown 方式を扱った Crawl4AI レビュー、そしてより広い スクレイピングツールの比較記事 も書いています。ノーコードで進めたいなら、AI でサイトをスクレイピングする方法 の手順解説もあります。
結論
Apache Tika を使うべきか。答えはイエスです。異種混在のファイルをフラットテキストと正規化されたメタデータに変換し、自分のパイプラインで失ってはいけないフィールドやマーカーを検証できるなら、使う価値があります。
今回の実行で最も強かったのは検出器でした。内容判定可能な 5 形式について、ファイル名なしのストリームを含む 20 個の一意条件すべてで期待通りの型を返しました。埋め込んだマーカーは 14 のレンダリングすべてで残り、出力はローカル再実行 3 回で 1 バイト単位まで一致しました。十分に有用な証拠です。ただし、あくまで人工データです。今回試した非 OCR 経路については、この JDK で 1 つの jar から外部バイナリなしで動かせたため、導入は驚くほど平凡でした。
ただし、期待値は適切に持つべきです。表はどれもタブ区切りの行に戻り、構造的なリストマーカーは消えます。Markdown と CSV はファイル名がなくなると識別を失います。空ファイルと壊れたファイルは同じ形の失敗を返し、それらを見分けるには別途 detect 呼び出しが必要です。そして、多くの Tika ユーザーが最も気にする OCR については、今回は何も言えません。実行できなかったし、推測もしません。
その条件の中では、Tika はあまり華やかではない仕事をかなり高い信頼性でこなします。箱に書かれたラベルではなく、バイトそのものを読むのです。ただし、そのバイトがどんな形だったのかまでは尋ねないでください。
Web データ抽出で Thunderbit を試す Get Started Free
よくある質問
Apache Tika は拡張子が間違っていてもファイル形式を正しく判定できますか?
今回テストした 5 つの内容判定可能な検証ファイルについては、はい。PDF、DOCX、RTF、HTML、XML は、誤った拡張子、拡張子なし、ファイル名なしのストリームを含む 20 個の一意な論理条件すべてで、期待した media type に解決されました(重複したストリーム実行を含めると生の実行は 30 回)。.txt と名付けた PDF も application/pdf として検出されました。Markdown と小さな CSV の検証ファイルはファイル名情報に依存しており、それが欠けたり誤っていたりすると text/plain に落ちました。
Tika は表や文書構造を保持しますか?
今回試した --text モードでは、保持しません。表はセルやヘッダの意味を持たないタブ区切り行になり、構造的なリストマーカー(HTML の <li> や DOCX の List Bullet スタイル)は消えました。埋め込んだマーカー自体は 14 のキャリア表現すべてで残っていましたが、それは完全な内容忠実性の証明ではありませんし、--text は要素型を返しません。型付き要素や再構成された表が必要なら、別の Tika 出力ハンドラを試すか、別ツールと併用してください。
Apache Tika でスキャン済み PDF に OCR は使えますか? Tika は Tesseract 経由で OCR をサポートしていますが、今回はテストしていませんし、ここでの結果は OCR について何も主張しません。 テスト環境には Tesseract も poppler もなかったので、OCR とスキャン画像の経路は実行前に遮断されました。この検証では OCR の数値は一切ありません。OCR が用途なら、tesseract を入れて自分でベンチマークしてください。ここでの Tika の OCR 部分は未検証と考えるべきです。
空ファイルや破損ファイルに対して Tika はどう振る舞いますか?
静かに失敗するのではなく、はっきり失敗します。0 バイトファイルは ZeroByteFileException、途中で切れた PDF は PDFParser からの TikaException、途中で切れた DOCX は POI の XML エラーを投げます。3 つとも exit 1 で stdout は空なので、抽出呼び出しだけでは空ファイルと破損ファイルは区別できません。ただし検出は堅牢で、--detect は両方の途中切れバイナリで正しい型を返して exit 0 でした。解析に時間をかける前の三次対応ステップとしては信頼できます。
今回の Tika テストでカバーしなかったものは何ですか? 明示的に 4 つあります。OCR とスキャン画像(遮断されており未検証)。実データでの精度――すべての結果は、既知ラベル付きのマーカートークンを埋め込んだ制御済み人工データであり、雑多な実文書での精度ではありません。リソース消費、スループット、ピークメモリ――測定していません。そして「1,000 種類のファイル形式」という主張のロングテールです。今回は 9 種類の代表的で依存不要な形式だけを試しており、カタログ全体ではありません。ここにある結果はすべて Tika 3.3.2、OpenJDK 26.0.1、macOS arm64、単一マシンでのものです。


