Разбор PDF без /Root объекта с использованием PDFMiner
Я пытаюсь извлечь текст из большого количества PDF-файлов, используя привязки Python PDFMiner. Модуль, который я написал, работает для многих 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. Казалось бы, можно предположить иное, но я очень невежественен. Какие-нибудь мысли?
4 ответа
Интересная проблема. я провел какое-то исследование:
функция, которая анализировала 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 с тегами.
Я думаю, проблема в том, что у вашего "поврежденного pdf" есть несколько "корневых элементов" на странице.
Possible solution:
Вы можете скачать исходники и написать `функцию печати 'в каждом месте, где извлекаются внешние объекты и где анализатор пытался проанализировать эти объекты. можно будет определить полный стек ошибок (до появления этой ошибки).
PS: я думаю, что это какая-то ошибка в продукте.
Решение в slate pdf - использовать 'rb' -> чтение в двоичном режиме.
Поскольку формат PDF зависит от PDFMiner, и у меня та же проблема, это должно решить вашу проблему.
fp = open('C:\Users\USER\workspace\slate_minner\document1.pdf','rb')
doc = slate.PDF(fp)
print doc
У меня была такая же проблема в Ubuntu. У меня очень простое решение. Просто распечатайте PDF-файл в формате PDF. Если вы находитесь в Ubuntu:
Откройте файл PDF с помощью (ubuntu) средства просмотра документов.
Перейти к файлу
Перейти к печати
Выберите печать как файл и отметьте галочкой "pdf"
Если вы хотите сделать процесс автоматическим, следуйте, например, этому, т. Е. Используйте этот скрипт для автоматической печати всех ваших PDF-файлов. Подобный сценарий Linux также работает:
for f in *.pdfx
do
lowriter --headless --convert-to pdf "$f"
done
Обратите внимание, что я назвал оригинальные (проблемные) файлы PDF как PDFX.
Я также получил эту ошибку и продолжал пробовать fp = open('example','rb')
Тем не менее, я все еще получил сообщение об ошибке. Что я обнаружил, так это то, что в моем коде была ошибка, когда PDF все еще был открыт другой функцией.
Поэтому убедитесь, что у вас нет открытых файлов PDF в других местах.
Ответ выше правильный. Эта ошибка появляется только в Windows, и обходной путь должен заменить with open(path, 'rb')
вfp = open(path,'rb')