Si te encuentras con alguna parte que no comprendes puedes comentarlo y te responderemos tan rápido como podamos.
Solución:
Las líneas nuevas se convierten en guiones bajos en la salida final. Esta es la solución de trabajo mínima que encontré.
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfpage import PDFTextExtractionNotAllowed
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.pdfdevice import PDFDevice
from pdfminer.layout import LAParams
from pdfminer.converter import PDFPageAggregator
import pdfminer
# Open a PDF file.
fp = open('/Users/me/Downloads/test.pdf', 'rb')
# Create a PDF parser object associated with the file object.
parser = PDFParser(fp)
# Create a PDF document object that stores the document structure.
# Password for initialization as 2nd parameter
document = PDFDocument(parser)
# Check if the document allows text extraction. If not, abort.
if not document.is_extractable:
raise PDFTextExtractionNotAllowed
# Create a PDF resource manager object that stores shared resources.
rsrcmgr = PDFResourceManager()
# Create a PDF device object.
device = PDFDevice(rsrcmgr)
# BEGIN LAYOUT ANALYSIS
# Set parameters for analysis.
laparams = LAParams()
# Create a PDF page aggregator object.
device = PDFPageAggregator(rsrcmgr, laparams=laparams)
# Create a PDF interpreter object.
interpreter = PDFPageInterpreter(rsrcmgr, device)
def parse_obj(lt_objs):
# loop over the object list
for obj in lt_objs:
# if it's a textbox, print text and location
if isinstance(obj, pdfminer.layout.LTTextBoxHorizontal):
print "%6d, %6d, %s" % (obj.bbox[0], obj.bbox[1], obj.get_text().replace('n', '_'))
# if it's a container, recurse
elif isinstance(obj, pdfminer.layout.LTFigure):
parse_obj(obj._objs)
# loop over all pages in the document
for page in PDFPage.create_pages(document):
# read the page into a layout object
interpreter.process_page(page)
layout = device.get_result()
# extract text from this object
parse_obj(layout._objs)
Aquí hay un ejemplo listo para copiar y pegar que enumera las esquinas superiores izquierdas de cada bloque de texto en un PDF, y que creo que debería funcionar para cualquier PDF que no incluya “Form XObjects” que contengan texto:
from pdfminer.layout import LAParams, LTTextBox
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
fp = open('yourpdf.pdf', 'rb')
rsrcmgr = PDFResourceManager()
laparams = LAParams()
device = PDFPageAggregator(rsrcmgr, laparams=laparams)
interpreter = PDFPageInterpreter(rsrcmgr, device)
pages = PDFPage.get_pages(fp)
for page in pages:
print('Processing next page...')
interpreter.process_page(page)
layout = device.get_result()
for lobj in layout:
if isinstance(lobj, LTTextBox):
x, y, text = lobj.bbox[0], lobj.bbox[3], lobj.get_text()
print('At %r is text: %s' % ((x, y), text))
El código anterior se basa en el ejemplo de Realizar análisis de diseño en los documentos de PDFMiner, además de los ejemplos de pnj (https://stackoverflow.com/a/22898159/1709587) y Matt Swain (https://stackoverflow.com/a/ 25262470/1709587). Hay un par de cambios que hice a partir de estos ejemplos anteriores:
- yo suelo
PDFPage.get_pages()
, que es una forma abreviada de crear un documento, verificándolois_extractable
y pasárselo aPDFPage.create_pages()
- No me molesto en manejar
LTFigure
s, ya que PDFMiner actualmente no es capaz de manejar el texto dentro de ellos de forma limpia.
LAParams
le permite establecer algunos parámetros que controlan cómo los caracteres individuales en el PDF se agrupan mágicamente en líneas y cuadros de texto por PDFMiner. Si le sorprende que tal agrupación sea algo que debe suceder, está justificado en los documentos pdf2txt:
En un archivo PDF real, las partes de texto se pueden dividir en varios fragmentos en medio de su ejecución, según el software de creación. Por lo tanto, la extracción de texto debe empalmar fragmentos de texto.
LAParams
Los parámetros, como la mayoría de PDFMiner, no están documentados, pero puede verlos en el código fuente o llamando help(LAParams)
en su shell de Python. El significado de algunos de los parámetros se proporciona en https://pdfminer-docs.readthedocs.io/pdfminer_index.html#pdf2txt-py ya que también se pueden pasar como argumentos a pdf2text
en la línea de comando.
los layout
el objeto de arriba es un LTPage
, que es un iterable de “objetos de diseño”. Cada uno de estos objetos de diseño puede ser uno de los siguientes tipos …
LTTextBox
LTFigure
LTImage
LTLine
LTRect
… o sus subclases. (En particular, sus cuadros de texto probablemente estarán LTTextBoxHorizontal
s.)
Más detalle de la estructura de un LTPage
se muestra en esta imagen de los documentos: