¿Cómo uso pdfminer como una biblioteca?

Estoy tratando de obtener datos de texto de un pdf usando pdfminer . Puedo extraer estos datos en un archivo .txt correctamente con la herramienta de línea de comandos pdfminer pdf2txt.py. Actualmente hago esto y luego uso un script de Python para limpiar el archivo .txt. Me gustaría incorporar el proceso de extracción de pdf en el script y guardarme un paso.

Pensé que estaba en algo cuando encontré este enlace , pero no tuve éxito con ninguna de las soluciones. Quizás la función que se indica allí deba actualizarse nuevamente porque estoy usando una versión más reciente de pdfminer.

También probé la función que se muestra aquí, pero tampoco funcionó.

Otro enfoque que intenté fue llamar al script dentro de un script usando os.system . Esto tampoco tuvo éxito.

Estoy usando la versión 2.7.1 de Python y la versión 20110227 de pdfminer.

Aquí hay una versión limpia que finalmente produje y que funcionó para mí. Lo siguiente simplemente devuelve la cadena en un PDF, dado su nombre de archivo. Espero que esto le ahorre tiempo a alguien.

 from pdfminer.pdfinterp import PDFResourceManager, process_pdf from pdfminer.converter import TextConverter from pdfminer.layout import LAParams from cStringIO import StringIO def convert_pdf(path): rsrcmgr = PDFResourceManager() retstr = StringIO() codec = 'utf-8' laparams = LAParams() device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams) fp = file(path, 'rb') process_pdf(rsrcmgr, device, fp) fp.close() device.close() str = retstr.getvalue() retstr.close() return str 

Esta solución fue válida hasta que la API cambie en noviembre de 2013 .

Aquí hay una nueva solución que funciona con la última versión:

 from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter from pdfminer.converter import TextConverter from pdfminer.layout import LAParams from pdfminer.pdfpage import PDFPage from cStringIO import StringIO def convert_pdf_to_txt(path): rsrcmgr = PDFResourceManager() retstr = StringIO() codec = 'utf-8' laparams = LAParams() device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams) fp = file(path, 'rb') interpreter = PDFPageInterpreter(rsrcmgr, device) password = "" maxpages = 0 caching = True pagenos=set() for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True): interpreter.process_page(page) fp.close() device.close() str = retstr.getvalue() retstr.close() return str 

Sé que es de mal gusto responder a su propia pregunta, pero creo que puedo haberlo resuelto y no quiero que nadie más pierda el tiempo buscando una solución a mi problema.

Seguí la sugerencia en uno de los enlaces publicados en mi pregunta y volví a proponer el script actual pdf2txt.py incluido con pdfminer. Aquí está la función en caso de que sea útil para alguien más. Gracias al usuario skyl por publicar esa respuesta, todo lo que tuve que hacer fue hacer un par de cambios para que funcionara con la versión actual de pdfminer.

Esta función toma un pdf y crea un archivo .txt en el mismo directorio con el mismo nombre.

 def convert_pdf(path, outtype='txt', opts={}): import sys from pdfminer.pdfparser import PDFDocument, PDFParser from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter, process_pdf from pdfminer.pdfdevice import PDFDevice, TagExtractor from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter from pdfminer.cmapdb import CMapDB from pdfminer.layout import LAParams import getopt outfile = path[:-3] + outtype outdir = '/'.join(path.split('/')[:-1]) # debug option debug = 0 # input option password = '' pagenos = set() maxpages = 0 # output option # ?outfile = None # ?outtype = None outdir = None #layoutmode = 'normal' codec = 'utf-8' pageno = 1 scale = 1 showpageno = True laparams = LAParams() for (k, v) in opts: if k == '-d': debug += 1 elif k == '-p': pagenos.update( int(x)-1 for x in v.split(',') ) elif k == '-m': maxpages = int(v) elif k == '-P': password = v elif k == '-o': outfile = v elif k == '-n': laparams = None elif k == '-A': laparams.all_texts = True elif k == '-V': laparams.detect_vertical = True elif k == '-M': laparams.char_margin = float(v) elif k == '-L': laparams.line_margin = float(v) elif k == '-W': laparams.word_margin = float(v) elif k == '-F': laparams.boxes_flow = float(v) elif k == '-Y': layoutmode = v elif k == '-O': outdir = v elif k == '-t': outtype = v elif k == '-c': codec = v elif k == '-s': scale = float(v) # #PDFDocument.debug = debug #PDFParser.debug = debug CMapDB.debug = debug PDFResourceManager.debug = debug PDFPageInterpreter.debug = debug PDFDevice.debug = debug # rsrcmgr = PDFResourceManager() outtype = 'text' if outfile: outfp = file(outfile, 'w') else: outfp = sys.stdout device = TextConverter(rsrcmgr, outfp, codec=codec, laparams=laparams) fp = file(path, 'rb') process_pdf(rsrcmgr, device, fp, pagenos, maxpages=maxpages, password=password, check_extractable=True) fp.close() device.close() outfp.close() return 

Esto me funcionó con la versión más reciente de pdfminer (a partir de septiembre de 2014):

 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.converter import TextConverter from pdfminer.layout import LAParams import unicodedata, codecs from io import StringIO def getPDFText(pdfFilenamePath): retstr = StringIO() parser = PDFParser(open(pdfFilenamePath,'r')) try: document = PDFDocument(parser) except Exception as e: print(pdfFilenamePath,'is not a readable pdf') return '' if document.is_extractable: rsrcmgr = PDFResourceManager() device = TextConverter(rsrcmgr,retstr, codec='ascii' , laparams = LAParams()) interpreter = PDFPageInterpreter(rsrcmgr, device) for page in PDFPage.create_pages(document): interpreter.process_page(page) return retstr.getvalue() else: print(pdfFilenamePath,"Warning: could not extract text from pdf file.") return '' if __name__ == '__main__': words = getPDFText(path) 

Aquí está mi solución

 from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter from pdfminer.converter import TextConverter from pdfminer.layout import LAParams from pdfminer.pdfpage import PDFPage from io import StringIO import os def convert_pdf_to_txt(path, pages=None): if not pages: pagenums = set() else: pagenums = set(pages) output = StringIO() manager = PDFResourceManager() converter = TextConverter(manager, output, laparams=LAParams()) interpreter = PDFPageInterpreter(manager, converter) infile = open(path, 'rb') for page in PDFPage.get_pages(infile, pagenums): interpreter.process_page(page) infile.close() converter.close() text = output.getvalue() output.close() return text 

Por ejemplo, solo desea leer las primeras 3 páginas de un archivo pdf:

 text = convert('../Data/EN-FINAL Table 9.pdf', pages=[0,1,2]) 

pdfminer.six == 20160614

python: 3.x

La siguiente modificación de las respuestas non-process_pdf extrae el texto directamente de un nombre de cadena de URL y funciona con la versión 20140328 y Python 2.7:

 from urllib2 import urlopen from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter from pdfminer.converter import TextConverter from pdfminer.layout import LAParams from pdfminer.pdfpage import PDFPage from cStringIO import StringIO def convert_pdf_to_txt(url): rsrcmgr = PDFResourceManager() retstr = StringIO() codec = 'utf-8' laparams = LAParams() device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams) scrape = urlopen(url).read() fp = StringIO(scrape) interpreter = PDFPageInterpreter(rsrcmgr, device) password = "" maxpages = 0 caching = True pagenos=set() for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True): interpreter.process_page(page) fp.close() device.close() textstr = retstr.getvalue() retstr.close() return textstr 

Si está trabajando con datos raspados a través de urllib2, intente esto (que se desarrolla y explica aquí ):

 def pdf_to_text(scraped_pdf_data): from pdfminer.pdfinterp import PDFResourceManager, process_pdf from pdfminer.pdfdevice import PDFDevice from pdfminer.converter import TextConverter from pdfminer.layout import LAParams import StringIO fp = StringIO.StringIO() fp.write(scraped_pdf_data) fp.seek(0) outfp = StringIO.StringIO() rsrcmgr = PDFResourceManager() device = TextConverter(rsrcmgr, outfp, laparams=LAParams()) process_pdf(rsrcmgr, device, fp) device.close() t = outfp.getvalue() outfp.close() fp.close() return t 

Al igual que las otras respuestas, el código aquí adapta la utilidad pdf2txt que proporciona PDFMiner. Por lo tanto, también puede convertir a html o xml – solo sub HTMLConverter o XMLConverter para TextConverter todas partes arriba.

El siguiente código me funciona con la última versión de PDFMiner, toma la ruta del pdf y devuelve el texto en formato .txt.

PD: Esta es una modificación de la respuesta anterior.

 from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter from pdfminer.converter import TextConverter from pdfminer.layout import LAParams from pdfminer.pdfpage import PDFPage from cStringIO import StringIO def convert_pdf_to_txt(path, outtype='txt'): outfile = path[:-3] + outtype rsrcmgr = PDFResourceManager() codec = 'utf-8' laparams = LAParams() if outfile: outfp = file(outfile, 'w') else: outfp = sys.stdout device = TextConverter(rsrcmgr, outfp, codec=codec, laparams=laparams) fp = file(path, 'rb') interpreter = PDFPageInterpreter(rsrcmgr, device) password = "" maxpages = 0 caching = True pagenos=set() for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True): interpreter.process_page(page) fp.close() device.close() outfp.close() return 

En caso de que alguien todavía lo necesite, lo hizo trabajar con solicitudes y Python 3.4. Gracias a @bahmait por su respuesta anterior 🙂

 import requests from io import StringIO from pdfminer.pdfinterp import PDFResourceManager, process_pdf from pdfminer.converter import TextConverter from pdfminer.layout import LAParams def pdf_to_text(url=None): text = None pdf = requests.get(url) if pdf.ok: fp = StringIO(str(pdf.content, 'utf-8')) outfp = StringIO() rsrcmgr = PDFResourceManager() device = TextConverter(rsrcmgr, outfp, laparams=LAParams()) process_pdf(rsrcmgr, device, fp) device.close() text = outfp.getvalue() outfp.close() fp.close() return text if __name__ == "__main__": hello_world_text = pdf_to_text("https://bytebucket.org/hsoft/pdfminer3k/raw/28edfc91caed830674ca0b928f42571f7dee6091/samples/simple1.pdf") no_pdf = pdf_to_text('http://www.google.com/404') print(hello_world_text) print(no_pdf) 

Aquí hay una versión limpia que finalmente produje y que funcionó para mí. Lo siguiente simplemente devuelve la cadena en un PDF, dado su nombre de archivo. Espero que esto le ahorre tiempo a alguien.

 from pdfminer.pdfinterp import PDFResourceManager, process_pdf from pdfminer.converter import TextConverter from pdfminer.layout import LAParams from cStringIO import StringIO def convert_pdf(path): rsrcmgr = PDFResourceManager() retstr = StringIO() codec = 'utf-8' laparams = LAParams() device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams) fp = file(path, 'rb') process_pdf(rsrcmgr, device, fp) fp.close() device.close() str = retstr.getvalue() retstr.close() return str 

¿Alguien me puede decir: hay algún lugar específico donde colocar el archivo pdf?

Aquí hay una respuesta que funciona con pdfminer.six ejecutando python 3.6. Utiliza el módulo pdfminer.high_level que pdfminer.high_level gran parte de los detalles subyacentes si solo desea sacar el texto sin procesar de un archivo PDF simple.

 import pdfminer import io def extract_raw_text(pdf_filename): output = io.StringIO() laparams = pdfminer.layout.LAParams() # Using the defaults seems to work fine with open(pdf_filename, "rb") as pdffile: pdfminer.high_level.extract_text_to_fp(pdffile, output, laparams=laparams) return output.getvalue() 

Solo si alguien todavía lo necesita: cómo imprimir el HTML desde un PDF utilizando PDFMiner:

 import sys import getopt from Core.Interfaces.IReader import IReader from pdfminer.pdfparser import PDFDocument, PDFParser from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter, process_pdf from pdfminer.pdfdevice import PDFDevice, TagExtractor from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter from pdfminer.cmapdb import CMapDB from pdfminer.layout import LAParams from cStringIO import StringIO class PdfReader(object): def __init__(self): pass def readText(self,path, outtype='text', opts={}): outfile = path[:-3] + outtype outdir = '/'.join(path.split('/')[:-1]) # debug option debug = 0 # input option password = '' pagenos = set() maxpages = 0 # output option # ?outfile = None # ?outtype = None outdir = None #layoutmode = 'normal' codec = 'utf-8' pageno = 1 scale = 1 showpageno = True laparams = LAParams() for (k, v) in opts: if k == '-d': debug += 1 elif k == '-p': pagenos.update( int(x)-1 for x in v.split(',') ) elif k == '-m': maxpages = int(v) elif k == '-P': password = v elif k == '-o': outfile = v elif k == '-n': laparams = None elif k == '-A': laparams.all_texts = True elif k == '-V': laparams.detect_vertical = True elif k == '-M': laparams.char_margin = float(v) elif k == '-L': laparams.line_margin = float(v) elif k == '-W': laparams.word_margin = float(v) elif k == '-F': laparams.boxes_flow = float(v) elif k == '-Y': layoutmode = v elif k == '-O': outdir = v elif k == '-t': outtype = v elif k == '-c': codec = v elif k == '-s': scale = float(v) print laparams # #PDFDocument.debug = debug #PDFParser.debug = debug CMapDB.debug = debug PDFResourceManager.debug = debug PDFPageInterpreter.debug = debug PDFDevice.debug = debug # rsrcmgr = PDFResourceManager() #outtype = 'text' outfp = StringIO() device = HTMLConverter(rsrcmgr, outfp, codec=codec, laparams=laparams) fp = file(path, 'rb') process_pdf(rsrcmgr, device, fp, pagenos, maxpages=maxpages, password=password, check_extractable=True) fp.close() device.close() print outfp.getvalue() outfp.close() return reader = PdfReader() opt = map(None,['-W','-L','-t'],[0.5,0.4,'html']) reader.readText("/test_data/test.pdf","html",opt) 

Los siguientes fragmentos de código pueden extraer texto sin formato de documentos pdf utilizando la última versión de pdfminer (desde el 23 de marzo de 2016). Espero que esto ayude.

 from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter from pdfminer.converter import TextConverter from pdfminer.layout import LAParams from pdfminer.pdfpage import PDFPage from cStringIO import StringIO def convert_pdf_to_txt(path): rsrcmgr = PDFResourceManager() retstr = StringIO() codec = 'utf-8' laparams = LAParams() device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams) fp = file(path, 'rb') parser = PDFParser(fp) doc = PDFDocument(parser) parser.set_document(doc) interpreter = PDFPageInterpreter(rsrcmgr, device) password = "" maxpages = 0 caching = True pagenos=set() for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True): interpreter.process_page(page) text = retstr.getvalue() fp.close() device.close() retstr.close() print text return text convert_pdf_to_txt() 

Este me funcionó en Python 3. Requiere el paquete PDFMiner.six

 pip install pdfminer.six 

El código es el siguiente (el mismo código que todos, con correcciones menores):

 from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter from pdfminer.converter import TextConverter from pdfminer.layout import LAParams from pdfminer.pdfpage import PDFPage from six import StringIO def convert_pdf_to_txt(path): rsrcmgr = PDFResourceManager() retstr = StringIO() codec = 'utf-8' laparams = LAParams() device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams) fp = open(path, 'rb') interpreter = PDFPageInterpreter(rsrcmgr, device) password = "" maxpages = 0 caching = True pagenos=set() for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True): interpreter.process_page(page) fp.close() device.close() str = retstr.getvalue() retstr.close() return str.replace("\\n","\n")