web-dev-qa-db-fra.com

Comment utiliser pdfminer comme bibliothèque

J'essaie d'obtenir des données texte à partir d'un pdf en utilisant pdfminer . Je suis capable d'extraire ces données dans un fichier .txt avec succès avec l'outil de ligne de commande pdfminer pdf2txt.py. Je le fais actuellement, puis j'utilise un script python pour nettoyer le fichier .txt. Je voudrais incorporer le processus d'extraction de pdf dans le script et me sauver une étape.

Je pensais que j'étais sur quelque chose quand j'ai trouvé ce lien , mais je n'ai réussi avec aucune des solutions. Peut-être que la fonction qui y est répertoriée doit être mise à jour à nouveau car j'utilise une version plus récente de pdfminer.

J'ai également essayé la fonction présentée ici, mais elle n'a pas fonctionné non plus.

Une autre approche que j'ai essayée était d'appeler le script dans un script en utilisant os.system. Cela a également échoué.

J'utilise Python version 2.7.1 et pdfminer version 20110227.

65
jmeich

Voici une version nettoyée que j'ai finalement produite et qui a fonctionné pour moi. Ce qui suit renvoie simplement la chaîne dans un PDF, étant donné son nom de fichier. J'espère que cela fait gagner du temps à quelqu'un.

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

Cette solution était valable jusqu'au changements d'API en novembre 201 .

67
karpathy

Voici une nouvelle solution qui fonctionne avec la dernière version:

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
75
czw

Je sais que c'est un mauvais goût de répondre à votre propre question, mais je pense que j'ai peut-être compris cela et je ne veux pas que quelqu'un d'autre perde son temps à chercher une solution à mon problème.

J'ai suivi la suggestion dans l'un des liens publiés dans ma question et ré-proposé le script pdf2txt.py actuel inclus avec pdfminer. Voici la fonction au cas où elle serait utile à quelqu'un d'autre. Merci à l'utilisateur skyl d'avoir posté cette réponse, tout ce que j'avais à faire était de faire quelques changements pour le faire fonctionner avec la version actuelle de pdfminer.

Cette fonction prend un pdf et crée un fichier .txt dans le même répertoire avec le même nom.

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
12
jmeich

Cela a fonctionné pour moi en utilisant la version la plus récente de pdfminer (en septembre 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 __== '__main__':
    words = getPDFText(path)
11
Jorge

Voici ma solution

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

Par exemple, vous voulez simplement lire les 3 premières pages d'un fichier pdf:

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

pdfminer.six == 20160614

python: 3.x

6
user4079032

La modification suivante des réponses non-process_pdf extrait le texte directement d'un nom de chaîne URL et fonctionne avec la version 20140328 et 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
4
ds58

Le code suivant fonctionne pour moi avec la dernière version de PDFMiner, il prend le chemin du pdf et renvoie le texte au format .txt.

P.S: Il s'agit d'une modification de la réponse ci-dessus.

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
3
Waqas Javed

Si vous travaillez avec des données grattées via urllib2, essayez ceci (qui est développé et expliqué ici ):

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

Comme les autres réponses, le code ici adapte l'utilitaire pdf2txt que PDFMiner lui-même fournit. Vous pouvez donc également convertir en html ou xml - juste sous HTMLConverter ou XMLConverter pour TextConverter partout ci-dessus.

3
scharfmn

juste au cas où quelqu'un en aurait encore besoin, le faire fonctionner avec les requêtes et python 3.4. merci à @bahmait pour sa réponse ci-dessus :)

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 __== "__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)
3
djmm187

Voici une réponse qui fonctionne avec pdfminer.six en cours d'exécution python 3.6. Il utilise le pdfminer.high_level module qui résume une grande partie des détails sous-jacents si vous voulez simplement extraire le texte brut d'un simple fichier PDF.

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()
3
Dave Potts

Voici une version nettoyée que j'ai finalement produite et qui a fonctionné pour moi. Ce qui suit renvoie simplement la chaîne dans un PDF, étant donné son nom de fichier. J'espère que cela fait gagner du temps à quelqu'un.

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

quelqu'un peut-il me dire: y a-t-il un endroit spécifique où le fichier pdf doit être placé ??

2
Gourab Mahapatra

Celui-ci a fonctionné pour moi dans python 3. Il nécessite le package PDFMiner.six

pip install pdfminer.six

Le code est le suivant (même code que tout le monde, avec des corrections mineures):

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")
1
Carlos B

Seulement si quelqu'un en a encore besoin: Comment imprimer le HTML à partir d'un PDF en utilisant 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)
1
atGuz

Les extraits de code suivants sont capables d'extraire du texte brut à partir de documents pdf à l'aide de la dernière version de pdfminer (en date du 23 mars 2016). J'espère que cela t'aides.

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(<path_of_the_pdf_file>)
0
Abhishek Kumar