从损坏的(?)pdf文档中提取文本

时间:2012-02-10 07:25:11

标签: pdf corruption mojibake

在我正在开展的项目中,我们从各个政府网站上搜集法律文件,然后在线搜索。

我们偶尔遇到一个似乎已经腐败的PDF。 Here's an example of one

如果您在PDF阅读器中打开它,它看起来很好,但是:

  • 如果您尝试复制并粘贴它,则会收到损坏的文字
  • 如果您通过pdftotext等任何工具运行它,则会损坏文本
  • 如果你做了其他任何事情 - 你猜对了 - 你得到了损坏的文字

然而,如果你在阅读器中打开它,它看起来很好!所以我知道文本在那里,但是出了点问题,错了!结果是在我的网站上看起来真的不好。

我能做些什么吗?

更新:我今天做了更多研究。感谢@Andrew Cash的观察,这本质上是一个凯撒密码,我意识到我可以搜索这些文件。 This link会在我的系统中向您展示其中的200个。通过更大的样本集,看起来这些都是由相同的软件pdffactory v.3.51创建的!所以我责怪一个错误,而不是故意的混淆。

更新2:上述链接不再提供任何结果。使用我的解决方案从系统中清除它们。

2 个答案:

答案 0 :(得分:2)

Tha PDF正在使用子集化字体,其中使用与简单的第二次世界大战替代密码相同的方式将字符重新映射到其他字符。

A = G, B = 1, C =#, D = W, ... ... 等等。每个角色都被重新映射。

字体以这种方式映射,为了在PDF中显示正确的字符,您需要发送“G1#W”,以便打印出ABCD。通常情况下,PDF会有一个ToUnicode表来帮助你进行文本提取,但我怀疑这个表是故意遗漏的。

我自己已经看到了一些这些文件,它们被故意混淆以防止文本提取。我看过一个包含大约5种不同字体的文档,它们都使用不同的序列进行映射。

确定这是否是问题的一种可靠方法是将PDF加载到Acrobat中并将文本复制/粘贴到文本编辑器中。如果Acrobat无法将文本解码回英语,则如果您知道翻译映射,则无法在不重新映射文​​本的情况下提取文本。

从这些类型的文档轻松提取文本的唯一方法是OCR完整文档并删除原始文本。 OCR会将页面转换为TIFF图像,然后对其进行OCR,以便原始的乱码文本不会影响OCR。

答案 1 :(得分:1)

厌倦了这个问题并且不想处理OCR,我手动整理了密码。在这里,她作为一个python dict以及我用来测试它的一些基本代码。我确信这可以改进,但它确实适用于所有字母,除了大写Q和大写X,我还没有找到。

它至少暂时缺少一点点标点符号(所有这些都丢失了,例如:<>?{} \ |!~` @#$%^ _ = +)

# -*- coding: utf-8 -*-

import re
import sys

letter_map = {
 u'¿':'a',
 u'regex':'b',
 u'regex':'c',
 u'regex':'d',
 u'»':'e',
 u'o':'f',
 u'1':'g',
 u'regex':'h',
 u'·':'i',
 u'¶':'j',
 u'μ':'k',
 u'regex':'l',
 u'3':'m',
 u'2':'n',
 u'±':'o',
 u'°':'p',
 u'regex':'q',
 u'®':'r',
 u'-':'s',
 u'¬':'t',
 u'«':'u',
 u'a':'v',
 u'©':'w',
 u'regex':'x',
 u'§':'y',
 u'¦':'z',
 u'ß':'A',
 u'Þ':'B',
 u'Ý':'C',
 u'Ü':'D',
 u'Û':'E',
 u'Ú':'F',
 u'Ù':'G',
 u'Ø':'H',
 u'×':'I',
 u'Ö':'J',
 u'Õ':'K',
 u'Ô':'L',
 u'Ó':'M',
 u'Ò':'N',
 u'Ñ':'O',
 u'Ð':'P',
 u'':'Q', # Missing
 u'Î':'R',
 u'Í':'S',
 u'Ì':'T',
 u'Ë':'U',
 u'Ê':'V',
 u'É':'W',
 u'':'X', # Missing
 u'Ç':'Y',
 u'Æ':'Z',
 u'ð':'0',
 u'ï':'1',
 u'î':'2',
 u'í':'3',
 u'ì':'4',
 u'ë':'5',
 u'ê':'6',
 u'é':'7',
 u'è':'8',
 u'ç':'9',
 u'ò':'.',
 u'ô':',',
 u'æ':':',
 u'å':';',
 u'Ž':"'",
 u'•':"'",
 u'•':"'", # s/b double quote, but identical to single.
 u'Œ':"'", # s/b double quote, but identical to single.
 u'ó':'-', # dash
 u'Š':'-', # n-dash
 u'‰':'--', # em-dash
 u'ú':'&',
 u'ö':'*',
 u'ñ':'/',
 u'÷':')',
 u'ø':'(',
 u'Å':'[',
 u'Ã':']',
 u'‹':'•',
 }

ciphertext = u'''YOUR STUFF HERE'''

plaintext = ''

for letter in ciphertext:
    try:
        plaintext += letter_map[letter]
    except KeyError:
        plaintext += letter

# These are multi-length replacements
plaintext = re.sub(u'm⁄4', 'b', plaintext)
plaintext = re.sub(u'g⁄n', 'c', plaintext)
plaintext = re.sub(u'g⁄4', 'd', plaintext)
plaintext = re.sub(u' ́', 'l', plaintext)
plaintext = re.sub(u' ̧', 'h', plaintext)
plaintext = re.sub(u' ̈', 'x', plaintext)
plaintext = re.sub(u' ̄u', 'qu', plaintext)

for letter in plaintext:
    try:
        sys.stdout.write(letter)
    except UnicodeEncodeError:
        continue