#python #exception #error-handling #pdfminer #pdf-parsing
Вопрос:
Я перебираю кучу PDF — файлов в папке, анализирую их содержимое и добавляю его в список. Он работает с подмножеством pdf-файлов. Я не хочу вручную удалять некоторые файлы PDF, запускать код, а затем добавлять некоторые, чтобы запустить его снова, пока я не найду неисправные PDF-файлы. Поскольку некоторые файлы pdf не могут быть открыты или, возможно, содержимое повреждено, я сделал следующее, чтобы обеспечить выполнение цикла: check_extractable
(pdfminer должен выдавать ошибку, если файл pdf не извлекается) — это метод внутреннего класса (PDFTextExtractionNotAllowed), который может предотвратить попытку открыть файл PDF, который на самом деле не может быть открыт
Вопрос: Что мне нужно сделать, чтобы код продолжал работать, даже если файл pdf не может быть открыт или не содержит содержимого (предполагая, что именно поэтому ошибка возникает в этой конкретной точке кода)
import pdfminer
from pdfminer.pdfpage import PDFPage, PDFTextExtractionNotAllowed
import os
import io
from io import StringIO
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter, PDFPageAggregator
from pdfminer.layout import LAParams, LTTextBox, LTFigure, LTImage,
LTTextLine, LTTextContainer, LTChar, LTTextBoxHorizontal
from pdfminer.pdfpage import PDFPage, PDFTextExtractionNotAllowed
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfparser import PDFParser, PDFSyntaxError
directory = 'C:/Users/'
data = []
for file in os.listdir(directory):
if not file.endswith(".pdf"):
continue
fake_file_handle = io.StringIO()
with open(os.path.join(directory, file), 'rb') as fh:
resource_manager = PDFResourceManager()
laparams = LAParams(line_margin = 0.6)
device = PDFPageAggregator(resource_manager, laparams = laparams)
page_interpreter = PDFPageInterpreter(resource_manager, device)
positions = []
raw_text = []
for page in PDFPage.get_pages(fh, caching=True, check_extractable=True):
page_interpreter.process_page(page)
text = fake_file_handle.getvalue()
layout = device.get_result()
for lobj in layout:
if isinstance(lobj, LTTextContainer) or isinstance(lobj, LTTextBox) or isinstance(lobj, pdfminer.layout.LTTextBoxHorizontal):
coord, word = int(lobj.bbox[1]), lobj.get_text().strip()
raw_text.append([coord, word])
for text_line in lobj:
for character in text_line:
if isinstance(character, LTChar):
if character.matrix[0]>0 :
position = character.bbox
positions.append(position)
# if it's a container, recurse
elif isinstance(lobj, LTFigure):
pass
# extract elements below y0=781 und above y0=57
text_pos = []
maxFontpos = 780
minFontpos = 58
for coord, word in raw_text:
if coord <= maxFontpos and coord >= minFontpos:
text_pos.append(word)
else:
pass
try:
wap = text_pos[0]
except:
pass
data.append([text_pos, wap])
fake_file_handle.close()
Конкретная ошибка возникает при
---> 28 for character in text_line:
29 if isinstance(character, LTChar):
30 if character.matrix[0]>0 :
TypeError: 'LTChar' object is not iterable
Комментарии:
1. Если вам все равно, почему некоторые файлы не работают — просто оберните неисправную часть в
try
.2. Вы проверяете
if isinstance(lobj, LTTextContainer)
, но это также будет успешным, еслиlobj
это aLTTextLine
, и в этом случае оно содержит только символы. (см. github.com/pdfminer/pdfminer.six/blob/… )3. Леонард, твой ответ заставил меня полюбопытствовать, почему он терпит неудачу. Я все еще оцениваю последствия, если он содержит только символы. В конце концов, это то, что я анализирую и добавляю. Кроме того, я сделал то, что сказал Гаррит, и теперь он возвращает все данные файлов 1995 года, за исключением 2 файлов
Ответ №1:
Если это просто быстрый и грязный скрипт, я бы рекомендовал просто окружить весь with
блок в общем try
/ except
. Как правило, вы не хотите просто слепо исключать/перехватывать исключения, не указывая, какой тип вы ищете, в случае возникновения другого исключения/ошибки, которых вы не ожидали, но в подобной ситуации, я думаю, это было бы нормально:
from pdfminer.pdfpage import PDFPage, PDFTextExtractionNotAllowed
directory = 'C:/Users/'
data = []
for file in os.listdir(directory):
if not file.endswith(".pdf"):
continue
fake_file_handle = io.StringIO()
try:
with open(os.path.join(directory, file), 'rb') as fh:
resource_manager = PDFResourceManager()
laparams = LAParams(line_margin = 0.6)
device = PDFPageAggregator(resource_manager, laparams = laparams)
page_interpreter = PDFPageInterpreter(resource_manager, device)
positions = []
raw_text = []
for page in PDFPage.get_pages(fh, caching=True, check_extractable=True):
page_interpreter.process_page(page)
text = fake_file_handle.getvalue()
layout = device.get_result()
for lobj in layout:
if isinstance(lobj, LTTextContainer) or isinstance(lobj, LTTextBox) or isinstance(lobj, pdfminer.layout.LTTextBoxHorizontal):
coord, word = int(lobj.bbox[1]), lobj.get_text().strip()
raw_text.append([coord, word])
for text_line in lobj:
for character in text_line:
if isinstance(character, LTChar):
if character.matrix[0]>0 :
position = character.bbox # font-positon
positions.append(position)
# if it's a container, recurse
elif isinstance(lobj, LTFigure):
pass
# extract elements below y0=781 und above y0=57
text_pos = []
maxFontpos = 780
minFontpos = 58
for coord, word in raw_text:
if coord <= maxFontpos and coord >= minFontpos:
text_pos.append(word)
else:
pass
try:
wap = text_pos[0]
except:
pass
except:
continue # Move on to next loop iteration
data.append([text_pos, wap])
fake_file_handle.close()