解析PDF使用PDFMiner无/ Root对象(Parsing a PDF with no /Ro

2019-06-26 03:42发布

我试图从大量使用PDFMiner Python绑定的PDF文本。 该模块我写了很多作品的PDF文件,但我得到这个晦涩的错误PDF文件的一个子集:

IPython的堆栈跟踪:

/usr/lib/python2.7/dist-packages/pdfminer/pdfparser.pyc in set_parser(self, parser)
    331                 break
    332         else:
--> 333             raise PDFSyntaxError('No /Root object! - Is this really a PDF?')
    334         if self.catalog.get('Type') is not LITERAL_CATALOG:
    335             if STRICT:

PDFSyntaxError: No /Root object! - Is this really a PDF?

当然,我立即检查,看看这些PDF文件是否被损坏,但他们可以读就好了。

有什么办法尽管没有根对象来读取这些PDF? 我不太知道从哪里何去何从。

非常感谢!

编辑:

我试着用企图PyPDF得到一些鉴别诊断。 堆栈跟踪低于:

In [50]: pdf = pyPdf.PdfFileReader(file(fail, "rb"))
---------------------------------------------------------------------------
PdfReadError                              Traceback (most recent call last)
/home/louist/Desktop/pdfs/indir/<ipython-input-50-b7171105c81f> in <module>()
----> 1 pdf = pyPdf.PdfFileReader(file(fail, "rb"))

/usr/lib/pymodules/python2.7/pyPdf/pdf.pyc in __init__(self, stream)
    372         self.flattenedPages = None
    373         self.resolvedObjects = {}
--> 374         self.read(stream)
    375         self.stream = stream
    376         self._override_encryption = False

/usr/lib/pymodules/python2.7/pyPdf/pdf.pyc in read(self, stream)
    708             line = self.readNextEndLine(stream)
    709         if line[:5] != "%%EOF":
--> 710             raise utils.PdfReadError, "EOF marker not found"
    711 
    712         # find startxref entry - the location of the xref table


PdfReadError: EOF marker not found

Quonux建议,也许PDFMiner停止在达到第一EOF字符之后解析。 这似乎并非如此,但我非常无能。 有什么想法吗?

Answer 1:

有趣的问题。 我已经进行了一些方面的研究:

功能,其解析(从矿工源代码)PDF:

def set_parser(self, parser):
        "Set the document to use a given PDFParser object."
        if self._parser: return
        self._parser = parser
        # Retrieve the information of each header that was appended
        # (maybe multiple times) at the end of the document.
        self.xrefs = parser.read_xref()
        for xref in self.xrefs:
            trailer = xref.get_trailer()
            if not trailer: continue
            # If there's an encryption info, remember it.
            if 'Encrypt' in trailer:
                #assert not self.encryption
                self.encryption = (list_value(trailer['ID']),
                                   dict_value(trailer['Encrypt']))
            if 'Info' in trailer:
                self.info.append(dict_value(trailer['Info']))
            if 'Root' in trailer:
                #  Every PDF file must have exactly one /Root dictionary.
                self.catalog = dict_value(trailer['Root'])
                break
        else:
            raise PDFSyntaxError('No /Root object! - Is this really a PDF?')
        if self.catalog.get('Type') is not LITERAL_CATALOG:
            if STRICT:
                raise PDFSyntaxError('Catalog not found!')
        return

如果你将有问题,EOF另一个将引发异常:“”“从源的另一功能”“”

def load(self, parser, debug=0):
        while 1:
            try:
                (pos, line) = parser.nextline()
                if not line.strip(): continue
            except PSEOF:
                raise PDFNoValidXRef('Unexpected EOF - file corrupted?')
            if not line:
                raise PDFNoValidXRef('Premature eof: %r' % parser)
            if line.startswith('trailer'):
                parser.seek(pos)
                break
            f = line.strip().split(' ')
            if len(f) != 2:
                raise PDFNoValidXRef('Trailer not found: %r: line=%r' % (parser, line))
            try:
                (start, nobjs) = map(long, f)
            except ValueError:
                raise PDFNoValidXRef('Invalid line: %r: line=%r' % (parser, line))
            for objid in xrange(start, start+nobjs):
                try:
                    (_, line) = parser.nextline()
                except PSEOF:
                    raise PDFNoValidXRef('Unexpected EOF - file corrupted?')
                f = line.strip().split(' ')
                if len(f) != 3:
                    raise PDFNoValidXRef('Invalid XRef format: %r, line=%r' % (parser, line))
                (pos, genno, use) = f
                if use != 'n': continue
                self.offsets[objid] = (int(genno), long(pos))
        if 1 <= debug:
            print >>sys.stderr, 'xref objects:', self.offsets
        self.load_trailer(parser)
        return

从维基(PDF规格):PDF文件主要包括对象,其中有八种类型的:

 Boolean values, representing true or false Numbers Strings Names Arrays, ordered collections of objects Dictionaries, collections of objects indexed by Names Streams, usually containing large amounts of data The null object 

对象可以是直接的(嵌入在另一对象)或间接的。 间接对象​​的编号与对象数目和世代号。 所谓的外部参照表的索引表给出了字节从文件开始每个间接对象的偏移。 这种设计可实现高效的随机访问对象的文件,并允许在不重写整个文件(增量更新)进行一些小的修改 。 与PDF版本1.5开始,间接对象也可位于素有对象流专用流。 该技术减少了有大量小的间接对象是标签PDF尤其有用文件的大小。

我THK问题是你的“损坏的PDF”在页面上的几个“根元素”。

Possible solution:

你可以下载源并在外部参照对象检索并在解析器试图解析这个对象在每个地方写`打印功能”。 这将有可能确定错误的全栈(是出现这个错误之前)。

PS:我觉得某种缺陷的产品。



Answer 2:

在石板PDF的解决方案是使用“RB” - >读取的二进制模式。

由于石板PDF是依赖于PDFMiner和我有同样的问题,这应该解决您的问题。

fp = open('C:\Users\USER\workspace\slate_minner\document1.pdf','rb')
doc = slate.PDF(fp)
print doc


Answer 3:

上述情况的一个答案是正确的。 只出现在窗口此错误,和解决方法是替换with open(path, 'rb')fp = open(path,'rb')



Answer 4:

我得到这个错误,以及和不断尝试计划生育=打开(“示例”,“RB”)

不过,我仍然有OP指示的错误。 我发现的是,我有错误在我的代码的PDF仍然另一个功能开在哪里。
因此,请确保您没有在PDF中存储开放其他地方也是如此。



Answer 5:

我曾在Ubuntu的同样的问题。 我有一个非常简单的解决方案。 只是打印PDF文件为PDF。 如果你是在Ubuntu:

  1. 使用(Ubuntu的)文档查看器打开PDF文件。

  2. 转到文件

  3. 转到打印

  4. 选择打印的文件,并检查标记“PDF”

如果你想使这个过程自动化,请按照例如本 ,即使用这个脚本来自动打印所有的PDF文件。 像这样的Linux的脚本也可以工作:

for f in *.pdfx
do
lowriter --headless --convert-to pdf "$f"
done

注意:我叫原(有问题的)PDF文件作为PDFX。



文章来源: Parsing a PDF with no /Root object using PDFMiner