Apache Tika 简介
1. 概述
Apache Tika 是一个工具包,用于从各种类型的文档中提取内容和元数据,例如 Word、Excel 和 PDF,甚至是 JPEG 和 MP4 等多媒体文件。
所有基于文本的和多媒体文件都可以使用一个通用界面进行解析,使 Tika 成为一个功能强大且用途广泛的内容分析库。
在本文中,我们将介绍 Apache Tika,包括它的解析 API 以及它如何自动检测文档的内容类型。还将提供工作示例来说明该库的操作。
2. 入门
为了使用 Apache Tika 解析文档,我们只需要一个 Maven 依赖项:
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
<version>1.17</version>
</dependency>
可以在此处 找到此工件的最新版本。
3. Parser API
Parser API 是 Apache Tika 的核心,抽象出解析操作的复杂性。此 API 依赖于一个方法:
void parse(
InputStream stream,
ContentHandler handler,
Metadata metadata,
ParseContext context)
throws IOException, SAXException, TikaException
该方法的参数含义如下:
- stream – 从要解析的文档创建的InputStream实例
- handler – 一个ContentHandler对象,接收从输入文档解析的一系列 XHTML SAX 事件;然后,此处理程序将处理事件并以特定形式导出结果
- Metadata — 一个Metadata对象,在解析器内外传递元数据属性
- context – 一个ParseContext实例,携带特定于上下文的信息,用于自定义解析过程
如果无法从输入流中读取,则 parse 方法抛出 IOException,如果无法解析从stream中获取的文档,则抛出* TikaException*,如果处理程序无法处理事件,则抛出SAXException 。
在解析文档时,Tika 会尽可能地重用现有的解析器库,例如 Apache POI 或 PDFBox。因此,大多数Parser实现类只是这些外部库的适配器。
在第 5 节中,我们将了解如何使用handler和Metadata参数来提取文档的内容和元数据。
为方便起见,我们可以使用外观类Tika来访问Parser API 的功能。
4. 自动检测
Apache Tika 可以根据文档本身而不是附加信息自动检测文档的类型及其语言。
4.1.文档类型检测
文档类型的检测可以使用Detector接口的实现类来完成,它有一个方法:
MediaType detect(java.io.InputStream input, Metadata metadata)
throws IOException
此方法获取一个文档及其关联的元数据,然后返回一个MediaType对象,该对象描述有关文档类型的最佳猜测。 元数据并不是检测器所依赖的唯一信息来源。检测器还可以使用魔术字节,这是文件开头附近的一种特殊模式,或者将检测过程委托给更合适的检测器。
事实上,检测器使用的算法是依赖于实现的。
例如,默认检测器首先使用魔术字节,然后是元数据属性。如果此时还没有找到内容类型,它将使用服务加载器来发现所有可用的检测器并依次尝试它们。
4.2. 语言检测
除了文档的类型,即使没有元数据信息的帮助,Tika 也可以识别其语言。
在以前的 Tika 版本中,使用LanguageIdentifier实例检测文档的语言。
但是,LanguageIdentifier已被弃用,取而代之的是 Web 服务,这在Getting Started 文档中没有明确说明。
现在通过抽象类LanguageDetector的子类型提供语言检测服务。使用网络服务,您还可以访问成熟的在线翻译服务,例如谷歌翻译或微软翻译。
为简洁起见,我们不会详细介绍这些服务。
5. Tika 示例
本节使用工作示例说明 Apache Tika 功能。
插图方法将包装在一个类中:
public class TikaAnalysis {
// illustration methods
}
5.1.检测文档类型
下面是我们可以用来检测从InputStream读取的文档类型的代码:
public static String detectDocTypeUsingDetector(InputStream stream)
throws IOException {
Detector detector = new DefaultDetector();
Metadata metadata = new Metadata();
MediaType mediaType = detector.detect(stream, metadata);
return mediaType.toString();
}
假设我们在类路径中有一个名为tika.txt的 PDF 文件。该文件的扩展名已更改以试图欺骗我们的分析工具。通过测试仍然可以找到并确认文档的真实类型:
@Test
public void whenUsingDetector_thenDocumentTypeIsReturned()
throws IOException {
InputStream stream = this.getClass().getClassLoader()
.getResourceAsStream("tika.txt");
String mediaType = TikaAnalysis.detectDocTypeUsingDetector(stream);
assertEquals("application/pdf", mediaType);
stream.close();
}
很明显,错误的文件扩展名无法阻止 Tika 找到正确的媒体类型,这要归功于文件开头的魔术字节*%PDF *。
为方便起见,我们可以使用Tika门面类重新编写检测代码,结果相同:
public static String detectDocTypeUsingFacade(InputStream stream)
throws IOException {
Tika tika = new Tika();
String mediaType = tika.detect(stream);
return mediaType;
}
5.2. 提取内容
现在让我们提取文件的内容并将结果作为String返回——使用Parser API:
public static String extractContentUsingParser(InputStream stream)
throws IOException, TikaException, SAXException {
Parser parser = new AutoDetectParser();
ContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();
ParseContext context = new ParseContext();
parser.parse(stream, handler, metadata, context);
return handler.toString();
}
给定类路径中包含以下内容的 Microsoft Word 文件:
Apache Tika - a content analysis toolkit
The Apache Tika™ toolkit detects and extracts metadata and text ...
内容可以提取和验证:
@Test
public void whenUsingParser_thenContentIsReturned()
throws IOException, TikaException, SAXException {
InputStream stream = this.getClass().getClassLoader()
.getResourceAsStream("tika.docx");
String content = TikaAnalysis.extractContentUsingParser(stream);
assertThat(content,
containsString("Apache Tika - a content analysis toolkit"));
assertThat(content,
containsString("detects and extracts metadata and text"));
stream.close();
}
同样,使用Tika类可以更方便地编写代码:
public static String extractContentUsingFacade(InputStream stream)
throws IOException, TikaException {
Tika tika = new Tika();
String content = tika.parseToString(stream);
return content;
}
5.3. 提取元数据
除了文档的内容,Parser API 还可以提取元数据:
public static Metadata extractMetadatatUsingParser(InputStream stream)
throws IOException, SAXException, TikaException {
Parser parser = new AutoDetectParser();
ContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();
ParseContext context = new ParseContext();
parser.parse(stream, handler, metadata, context);
return metadata;
}
当类路径中存在 Microsoft Excel 文件时,此测试用例确认提取的元数据是正确的:
@Test
public void whenUsingParser_thenMetadataIsReturned()
throws IOException, TikaException, SAXException {
InputStream stream = this.getClass().getClassLoader()
.getResourceAsStream("tika.xlsx");
Metadata metadata = TikaAnalysis.extractMetadatatUsingParser(stream);
assertEquals("org.apache.tika.parser.DefaultParser",
metadata.get("X-Parsed-By"));
assertEquals("Microsoft Office User", metadata.get("Author"));
stream.close();
}
最后,这是使用Tika门面类的另一个版本的提取方法:
public static Metadata extractMetadatatUsingFacade(InputStream stream)
throws IOException, TikaException {
Tika tika = new Tika();
Metadata metadata = new Metadata();
tika.parse(stream, metadata);
return metadata;
}