以编程方式从PDF文件中翻录文本(手动) - 缺少一些文本

时间:2010-10-28 23:28:53

标签: parsing language-agnostic pdf

注意:我对使用解析库不感兴趣。这是我自己的娱乐。

我一直在尝试从搜索小发明的PDF文件中删除文本,但无法从某些pdf文件中提取文本。

请注意,这比直接解析更容易;我不在乎我是否无意中在输出中包含了一些垃圾,我也不在乎文件的格式是否完整。我甚至不在乎这些话是否按顺序出现。

作为第一步,我使用此project上的策略创建了一个非常简单的pdf解析器。基本上,它所做的只是搜索zlib流的pdf文件,缩小它们,并拉出它在括号中找到的任何文本。这无法解析卡在<< >>块内部的数据,但我的理解是这是针对十六进制编码的数据blob,这似乎不在我无法解析的测试文件中...或者至少我没有看到它们。

同样,虽然iText.NetPDFMiner成功,PDFBox也会失败。然而,后两个项目有太多的间接层,很容易检查;我很难弄清楚他们到底在做什么,部分原因是因为我并没有真正使用任何一种语言来习惯于以任何重要的方式调试它。

我的目标是创建一个文本ripper从pdf文件中抓取文本,尽可能少了解pdf格式本身(例如我的测试解析器从括号中抓取文本,但不了解pdf的哪个部分正在检查是标题)。

1 个答案:

答案 0 :(得分:14)

从PDF文件中提取内容可能会有点复杂。我这样做是为了我的日常工作,我想我可以指出你正确的方向。

您要做的事情(在括号中提取字符串)仅适用于简单的WinAnsi或MacRoman编码,与Type1或TrueType字体一起使用。不幸的是,这些单字节编码不支持正确的Unicode内容。您的示例文档使用Type0 aka CID字体,其中每个字符由字形索引标识。这些是非标准的ad-hoc编码,其中字体的设计者可以以任意方式将字形索引分配给任何字符。有时,PDF的制作人故意破坏编码。

它的工作方式是从目录开始,解析页面树。识别页面对象后,您将解析其内容及其资源。资源字典包含页面使用的字体列表。每个CID字体对象都包含一个ToUnicode流,它是一个cmap(字符映射),它建立了字形索引与其Unicode值之间的关系。例如:

<01> <0044>
<02> <0061>
<03> <0074>
<04> <0020>

这意味着字形01是Unicode U + 0044,字形02是U + 0061,依此类推。您必须使用此查找表将字形ID转换回Unicode。

页面内容本身有两个重要的运算符。 Tf是字体选择器,这很重要,因为它标识了字体对象。每种字体都有自己的ToUnicode cmap,因此根据字体,您必须使用不同的查找表。

另一个有趣的运算符是文本节目(通常为TJTj)。对于Type0(CID)字体,Tj不包含人类可读的文本,而是在上面提到的cmap的帮助下,您应该映射到Unicode的一系列字形ID。 Tj通常使用十六进制字符串,例如<000100a50056> Tj,而不是您熟悉的更典型的(Hello, World) Tj。无论哪种方式,字符串都不是人类可读的,并且在没有完全解析页面的情况下无法提取,包括其所有字体资源,尤其是。 ToUnicode cmap,它本身就是一个PostScript对象,但你只关心十六进制部分。

当然我过分简化了这个过程,因为有几十种不同的标准编码,自定义编码(差异或ToUnicode),我们甚至没有触及阿拉伯语,印地语,垂直日语字体,Type3字体等。有时候文本根本无法提取,因为它故意被破坏。