Comment extraire du texte d'un fichier PDF?

207

J'essaye d'extraire le texte inclus dans ce fichier PDF en utilisant Python.

J'utilise le module PyPDF2 et j'ai le script suivant:

import PyPDF2
pdf_file = open('sample.pdf')
read_pdf = PyPDF2.PdfFileReader(pdf_file)
number_of_pages = read_pdf.getNumPages()
page = read_pdf.getPage(0)
page_content = page.extractText()
print page_content

Lorsque j'exécute le code, j'obtiens la sortie suivante qui est différente de celle incluse dans le document PDF:

!"#$%#$%&%$&'()*%+,-%./01'*23%4
5'%1$#26%3/%7/))/8%&)/26%8#3"%3"*%313/9#&)
%

Comment extraire le texte tel quel dans le document PDF?

Simplicité
la source
9
Je ne l' ai jamais utilisé ce module, mais est - il une différence si vous ouvrez le fichier en mode binaire: pdf_file = open('sample.pdf', 'rb')?
PM 2Ring le
2
Merci pour votre réponse. J'ai essayé cela avec le mode binaire, mais rien n'a changé
Simplicité
3
Copiez le texte en utilisant une bonne visionneuse PDF - Acrobat Reader canonique d'Adobe, si possible. Obtenez-vous le même résultat? La différence n'est pas que le texte est différent, mais la police l' est - les codes de caractères correspondent à d'autres valeurs. Tous les PDF ne contiennent pas les données correctes pour restaurer cela.
usr2564301
2
Ce PDF contient une table CMap de caractères, donc les restrictions et les solutions de contournement décrites dans ce fil sont pertinentes - stackoverflow.com/questions/4203414/… .
dwarring le
2
Le PDF contient en effet un CMAP correct, il est donc trivial de convertir le mappage de caractères ad hoc en texte brut. Cependant, il faut un traitement supplémentaire pour récupérer l' ordre correct du texte. Le moteur de rendu Quartz PDF de Mac OS X est un vilain travail! Dans son ordre de rendu d'origine, j'obtiens "m T'h iuss iisn ga tosam fopllloew DalFo dnogc wumithe ntht eI tutorial" ... Ce n'est qu'après un tri par coordonnées x que j'obtiens un résultat beaucoup plus correct: "Ceci est un exemple de document PDF I J'utilise pour suivre le tutoriel ".
usr2564301

Réponses:

222

Je cherchais une solution simple à utiliser pour python 3.x et windows. Il ne semble pas y avoir de support de textract , ce qui est malheureux, mais si vous cherchez une solution simple pour windows / python 3, vérifiez le paquet tika , vraiment simple pour lire les fichiers PDF.

Tika-Python est une liaison Python aux services Apache Tika ™ REST permettant à Tika d'être appelé nativement dans la communauté Python.

from tika import parser # pip install tika

raw = parser.from_file('sample.pdf')
print(raw['content'])

Notez que Tika est écrit en Java donc vous aurez besoin d'un runtime Java installé

DJK
la source
18
J'ai testé pypdf2, tika et essayé et échoué d'installer textract et pdftotext. Pypdf2 a renvoyé 99 mots tandis que tika a renvoyé les 858 mots de ma facture de test. Alors j'ai fini par aller avec tika.
Stian
8
Mec, je t'aime. Je ne sais pas pourquoi une si bonne réponse est cachée dans StackOverflow. Tout le monde ne cesse de mentionner que nous devons utiliser PyPDF2 ou pdfminer, mais cela pue. Je suis amoureux de tika maintenant
jxpython
18
J'obtiens toujours une erreur "RuntimeError: Impossible de démarrer le serveur Tika".
Nav
4
Réponse J'ai cherché toute ma vie, pourquoi personne d'autre ne recommande Tika? Merci!
Jacob-Jan Mosselman
4
Si vous avez besoin d'exécuter ceci sur tous les fichiers PDF dans un répertoire (récursivement), prenez ce script
Hope
62

Utilisez textract.

Il prend en charge de nombreux types de fichiers, y compris les PDF

import textract
text = textract.process("path/to/file.extension")
Jakobovski
la source
24
Textwrap semble être un bon wrapper, mais repose sur de nombreux utilitaires non-Python qui peuvent ne pas être facilement disponibles sur un système donné.
David Brown
1
Fonctionne pour les PDF, les epubs, etc. - traite les PDF sur lesquels même PDFMiner échoue.
Ulad Kasach
5
textractest un wrapper pour Poppler:pdftotext(entre autres).
onewhaleid
1
@ArunKumar: pour utiliser quoi que ce soit dans AWS Lambda qui n'est pas intégré, vous devez l'inclure, ainsi que toutes les dépendances supplémentaires, dans votre bundle.
Jeff Learman le
1
textractsemble être mort ( source ). Utilisez directement pdfminer.six ou pymupdf
Martin Thoma
52

Regardez ce code:

import PyPDF2
pdf_file = open('sample.pdf', 'rb')
read_pdf = PyPDF2.PdfFileReader(pdf_file)
number_of_pages = read_pdf.getNumPages()
page = read_pdf.getPage(0)
page_content = page.extractText()
print page_content.encode('utf-8')

La sortie est:

!"#$%#$%&%$&'()*%+,-%./01'*23%4
5'%1$#26%3/%7/))/8%&)/26%8#3"%3"*%313/9#&)
%

Utiliser le même code pour lire un pdf de 201308FCR.pdf . La sortie est normale.

Sa documentation explique pourquoi:

def extractText(self):
    """
    Locate all text drawing commands, in the order they are provided in the
    content stream, and extract the text.  This works well for some PDF
    files, but poorly for others, depending on the generator used.  This will
    be refined in the future.  Do not rely on the order of text coming out of
    this function, as it will change if this function is made more
    sophisticated.
    :return: a unicode string object.
    """
Quinn
la source
@VineeshTP: Obtenez-vous quelque chose pour page_content? Si oui, voyez si cela aide en utilisant un autre encodage que (utf-8)
Quinn
La meilleure bibliothèque que j'ai trouvée pour lire le pdf en utilisant python est 'tika'
Vineesh TP
201308FCR.pdf introuvable.
Chaitanya Bapat le
1
PyPDF2 / PyPDF3 / PyPDF4 sont tous morts. Utilisez pymupdf
Martin Thoma
35

Après avoir essayé textract (qui semblait avoir trop de dépendances) et pypdf2 (qui ne pouvait pas extraire le texte des pdfs avec lesquels j'ai testé) et tika (qui était trop lent), j'ai fini par utiliser pdftotextde xpdf (comme déjà suggéré dans une autre réponse) et vient d'appeler directement le binaire de python (vous devrez peut-être adapter le chemin à pdftotext):

import os, subprocess
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
args = ["/usr/local/bin/pdftotext",
        '-enc',
        'UTF-8',
        "{}/my-pdf.pdf".format(SCRIPT_DIR),
        '-']
res = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = res.stdout.decode('utf-8')

Il y a pdftotext qui fait fondamentalement la même chose, mais cela suppose pdftotext dans / usr / local / bin alors que je l'utilise dans AWS lambda et que je voulais l'utiliser à partir du répertoire actuel.

Btw: Pour utiliser ceci sur lambda, vous devez placer le binaire et la dépendance libstdc++.sodans votre fonction lambda. J'avais personnellement besoin de compiler xpdf. Comme les instructions pour cela feraient exploser cette réponse, je les ai mises sur mon blog personnel .

hansaplast
la source
5
Oh mon dieu, ça marche !! Enfin, une solution qui extrait le texte dans le bon ordre! Je veux te serrer dans mes bras pour cette réponse! (Ou si vous n'aimez pas les câlins, voici un café / bière / ...)
DonQuiKong
7
heureux que cela ait aidé! Le vote positif donne la même sensation que les câlins, donc je vais bien!
hansaplast
simple ... gr8 pensée hors de la boîte!
shantanu pathak
10

Vous voudrez peut-être utiliser à la place du xPDF éprouvé et des outils dérivés pour extraire du texte car pyPDF2 semble avoir encore divers problèmes avec l'extraction de texte.

La réponse longue est qu'il existe de nombreuses variations dans la manière dont un texte est encodé dans un PDF et qu'il peut nécessiter de décoder la chaîne PDF elle-même, puis peut avoir besoin de mapper avec CMAP, puis peut-être besoin d'analyser la distance entre les mots et les lettres, etc.

Dans le cas où le PDF est endommagé (c'est-à-dire afficher le texte correct mais lorsque la copie donne des déchets) et que vous avez vraiment besoin d'extraire du texte, vous pouvez envisager de convertir le PDF en image (en utilisant ImageMagik ), puis utiliser Tesseract pour obtenir le texte de l'image en utilisant l'OCR.

Eugène
la source
-1 parce que l'OP demande la lecture de pdfs en Python, et bien qu'il existe un wrapper xpdf pour python, il est mal entretenu.
cduguet
10

J'ai essayé de nombreux convertisseurs PDF Python et j'aime mettre à jour cette revue. Tika est l'un des meilleurs. Mais PyMuPDF est une bonne nouvelle de l'utilisateur @ehsaneha.

J'ai fait un code pour les comparer dans: https://github.com/erfelipe/PDFtextExtraction J'espère vous aider.

Tika-Python est une liaison Python aux services Apache Tika ™ REST permettant à Tika d'être appelé nativement dans la communauté Python.

from tika import parser

raw = parser.from_file("///Users/Documents/Textos/Texto1.pdf")
raw = str(raw)

safe_text = raw.encode('utf-8', errors='ignore')

safe_text = str(safe_text).replace("\n", "").replace("\\", "")
print('--- safe text ---' )
print( safe_text )
Erfelipe
la source
3
merci spécial pour.encode('utf-8', errors='ignore')
Evgeny
AttributeError: le module 'os' n'a pas d'attribut 'setsid'
keramat
7

Je recommande d'utiliser pymupdf ou pdfminer.six.

Ces packages ne sont pas maintenus:

  • PyPDF2, PyPDF3, PyPDF4
  • pdfminer (sans .six)

Comment lire du texte pur avec pymupdf

Il existe différentes options qui donneront des résultats différents, mais la plus élémentaire est:

import fitz  # this is pymupdf

with fitz.open("my.pdf") as doc:
    text = ""
    for page in doc:
        text += page.getText()

print(text)
Martin Thoma
la source
6

Le code ci-dessous est une solution à la question dans Python 3 . Avant d'exécuter le code, assurez-vous d'avoir installé la PyPDF2bibliothèque dans votre environnement. S'il n'est pas installé, ouvrez l'invite de commande et exécutez la commande suivante:

pip3 install PyPDF2

Code de la solution:

import PyPDF2
pdfFileObject = open('sample.pdf', 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFileObject)
count = pdfReader.numPages
for i in range(count):
    page = pdfReader.getPage(i)
    print(page.extractText())
Steffi Keran Rani J
la source
2
Comment pourriez-vous enregistrer tout le contenu dans un fichier texte et l'utiliser pour une analyse plus approfondie
Rahul Agarwal
1
PyPDF2 / PyPDF3 / PyPDF4 sont tous morts. Utilisez pymupdf
Martin Thoma
6

PyPDF2 dans certains cas ignore les espaces blancs et rend le texte du résultat un désordre, mais j'utilise PyMuPDF et je suis vraiment satisfait que vous puissiez utiliser ce lien pour plus d'informations

ehsaneha
la source
pymupdf est la meilleure solution que j'ai observée, ne nécessite pas de bibliothèques C ++ supplémentaires comme pdftotext ou java comme tika
Kay
pymypdf est vraiment la meilleure solution, pas de serveur ou de bibliothèques supplémentaires, et il fonctionne avec un fichier où PyPDF2 PypDF3 PyPDF4 récupère une chaîne de texte vide. Merci beaucoup!
Andrea Bisello le
pour installer pymupdf, exécutez pip install pymupdf==1.16.16. Utiliser cette version spécifique car aujourd'hui la dernière version (17) ne fonctionne pas. J'ai opté pour pymupdf car il extrait les champs d'habillage de texte dans le caractère de nouvelle ligne \n. J'extrais donc le texte du pdf dans une chaîne avec pymupdf et j'utilise ensuite my_extracted_text.splitlines()pour obtenir le texte divisé en lignes, dans une liste.
erickfis le
PyMuPDF était vraiment surprenant. Merci.
erfelipe
La page n'existe pas
Black Thunder le
6

pdftotext est le meilleur et le plus simple! pdftotext réserve également la structure.

J'ai essayé PyPDF2, PDFMiner et quelques autres mais aucun d'entre eux n'a donné un résultat satisfaisant.

Dharam
la source
Message comme suit lors de l'installation de pdf2text, Collecting PDFMiner (from pdf2text)donc je ne comprends pas cette réponse maintenant.
zhy le
1
pdf2text et pdftotext sont différents. Vous pouvez utiliser le lien de la réponse.
Dharam
D'ACCORD. C'est un peu déroutant.
zhy
5

Le pdf de plusieurs pages peut être extrait sous forme de texte en un seul tronçon au lieu de donner un numéro de page individuel comme argument en utilisant le code ci-dessous

import PyPDF2
import collections
pdf_file = open('samples.pdf', 'rb')
read_pdf = PyPDF2.PdfFileReader(pdf_file)
number_of_pages = read_pdf.getNumPages()
c = collections.Counter(range(number_of_pages))
for i in c:
   page = read_pdf.getPage(i)
   page_content = page.extractText()
   print page_content.encode('utf-8')
Yogi
la source
Seul problème ici le contenu de la nouvelle page écrase la dernière
Rahul Agarwal
1
PyPDF2 / PyPDF3 / PyPDF4 sont tous morts. Utilisez pymupdf
Martin Thoma
4

Vous pouvez utiliser PDFtoText https://github.com/jalan/pdftotext

PDF en texte conserve l'indentation du format texte, peu importe si vous avez des tableaux.

Máxima Alekz
la source
4

J'ai un meilleur travail que l'OCR et pour maintenir l'alignement de la page tout en extrayant le texte d'un PDF. Devrait être utile:

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

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)


    text = retstr.getvalue()

    fp.close()
    device.close()
    retstr.close()
    return text

text= convert_pdf_to_txt('test.pdf')
print(text)
Strayhorn
la source
Nb. La dernière version n'utilise plus l' codecargument . J'ai corrigé cela en le supprimant iedevice = TextConverter(rsrcmgr, retstr, laparams=laparams)
atomh33ls
4

En 2020, les solutions ci-dessus ne fonctionnaient pas pour le pdf particulier avec lequel je travaillais. Voici ce qui a fait le tour. Je suis sous Windows 10 et Python 3.8

Fichier pdf de test: https://drive.google.com/file/d/1aUfQAlvq5hA9kz2c9CyJADiY3KpY3-Vn/view?usp=sharing

#pip install pdfminer.six
import io

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage


def convert_pdf_to_txt(path):
    '''Convert pdf content from a file path to text

    :path the file path
    '''
    rsrcmgr = PDFResourceManager()
    codec = 'utf-8'
    laparams = LAParams()

    with io.StringIO() as retstr:
        with TextConverter(rsrcmgr, retstr, codec=codec,
                           laparams=laparams) as device:
            with open(path, 'rb') as fp:
                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)

                return retstr.getvalue()


if __name__ == "__main__":
    print(convert_pdf_to_txt('C:\\Path\\To\\Test_PDF.pdf')) 
Jortega
la source
Excellente réponse. Il existe également une installation anaconda. J'étais installé et j'avais extrait du texte en moins de 5 minutes. [note: tika a également fonctionné, mais pdfminer.six était beaucoup plus rapide)
CreekGeek
Tu es un sauveur!
Sandeep
3

Voici le code le plus simple pour extraire du texte

code:

# importing required modules
import PyPDF2

# creating a pdf file object
pdfFileObj = open('filename.pdf', 'rb')

# creating a pdf reader object
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)

# printing number of pages in pdf file
print(pdfReader.numPages)

# creating a page object
pageObj = pdfReader.getPage(5)

# extracting text from page
print(pageObj.extractText())

# closing the pdf file object
pdfFileObj.close()
Infini
la source
1
Recomending 'tika'
Vineesh TP
1
PyPDF2 / PyPDF3 / PyPDF4 sont tous morts. Utilisez pymupdf
Martin Thoma
2

J'ai trouvé une solution ici PDFLayoutTextStripper

C'est bien car il peut conserver la mise en page du PDF d'origine .

Il est écrit en Java mais j'ai ajouté une passerelle pour prendre en charge Python.

Exemple de code:

from py4j.java_gateway import JavaGateway

gw = JavaGateway()
result = gw.entry_point.strip('samples/bus.pdf')

# result is a dict of {
#   'success': 'true' or 'false',
#   'payload': pdf file content if 'success' is 'true'
#   'error': error message if 'success' is 'false'
# }

print result['payload']

Exemple de sortie de PDFLayoutTextStripper : entrez la description de l'image ici

Vous pouvez voir plus de détails ici Stripper avec Python

Tho
la source
1

Pour extraire le texte du PDF, utilisez le code ci-dessous

import PyPDF2
pdfFileObj = open('mypdf.pdf', 'rb')

pdfReader = PyPDF2.PdfFileReader(pdfFileObj)

print(pdfReader.numPages)

pageObj = pdfReader.getPage(0)

a = pageObj.extractText()

print(a)
Elavarasan r
la source
1
PyPDF2 / PyPDF3 / PyPDF4 sont tous morts. Utilisez pymupdf
Martin Thoma
1

Une manière plus robuste, en supposant qu'il y ait plusieurs PDF ou un seul!

import os
from PyPDF2 import PdfFileWriter, PdfFileReader
from io import BytesIO

mydir = # specify path to your directory where PDF or PDF's are

for arch in os.listdir(mydir): 
    buffer = io.BytesIO()
    archpath = os.path.join(mydir, arch)
    with open(archpath) as f:
            pdfFileObj = open(archpath, 'rb')
            pdfReader = PyPDF2.PdfFileReader(pdfFileObj)
            pdfReader.numPages
            pageObj = pdfReader.getPage(0) 
            ley = pageObj.extractText()
            file1 = open("myfile.txt","w")
            file1.writelines(ley)
            file1.close()
            
Andres Ordorica
la source
1

Si vous souhaitez extraire du texte d'un tableau, j'ai trouvé que le tabula était facilement implémenté, précis et rapide:

pour obtenir un dataframe pandas:

import tabula

df = tabula.read_pdf('your.pdf')

df

Par défaut, il ignore le contenu de la page en dehors du tableau. Jusqu'à présent, je n'ai testé que sur un fichier d'une seule page et d'une seule table, mais il existe des kwargs pour accueillir plusieurs pages et / ou plusieurs tables.

installer via:

pip install tabula-py
# or
conda install -c conda-forge tabula-py 

En termes d'extraction de texte directe, voir: https://stackoverflow.com/a/63190886/9249533

CreekGeek
la source
0

J'ajoute du code pour accomplir ceci: cela fonctionne bien pour moi:

# This works in python 3
# required python packages
# tabula-py==1.0.0
# PyPDF2==1.26.0
# Pillow==4.0.0
# pdfminer.six==20170720

import os
import shutil
import warnings
from io import StringIO

import requests
import tabula
from PIL import Image
from PyPDF2 import PdfFileWriter, PdfFileReader
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage

warnings.filterwarnings("ignore")


def download_file(url):
    local_filename = url.split('/')[-1]
    local_filename = local_filename.replace("%20", "_")
    r = requests.get(url, stream=True)
    print(r)
    with open(local_filename, 'wb') as f:
        shutil.copyfileobj(r.raw, f)

    return local_filename


class PDFExtractor():
    def __init__(self, url):
        self.url = url

    # Downloading File in local
    def break_pdf(self, filename, start_page=-1, end_page=-1):
        pdf_reader = PdfFileReader(open(filename, "rb"))
        # Reading each pdf one by one
        total_pages = pdf_reader.numPages
        if start_page == -1:
            start_page = 0
        elif start_page < 1 or start_page > total_pages:
            return "Start Page Selection Is Wrong"
        else:
            start_page = start_page - 1

        if end_page == -1:
            end_page = total_pages
        elif end_page < 1 or end_page > total_pages - 1:
            return "End Page Selection Is Wrong"
        else:
            end_page = end_page

        for i in range(start_page, end_page):
            output = PdfFileWriter()
            output.addPage(pdf_reader.getPage(i))
            with open(str(i + 1) + "_" + filename, "wb") as outputStream:
                output.write(outputStream)

    def extract_text_algo_1(self, file):
        pdf_reader = PdfFileReader(open(file, 'rb'))
        # creating a page object
        pageObj = pdf_reader.getPage(0)

        # extracting extract_text from page
        text = pageObj.extractText()
        text = text.replace("\n", "").replace("\t", "")
        return text

    def extract_text_algo_2(self, file):
        pdfResourceManager = PDFResourceManager()
        retstr = StringIO()
        la_params = LAParams()
        device = TextConverter(pdfResourceManager, retstr, codec='utf-8', laparams=la_params)
        fp = open(file, 'rb')
        interpreter = PDFPageInterpreter(pdfResourceManager, device)
        password = ""
        max_pages = 0
        caching = True
        page_num = set()

        for page in PDFPage.get_pages(fp, page_num, maxpages=max_pages, password=password, caching=caching,
                                      check_extractable=True):
            interpreter.process_page(page)

        text = retstr.getvalue()
        text = text.replace("\t", "").replace("\n", "")

        fp.close()
        device.close()
        retstr.close()
        return text

    def extract_text(self, file):
        text1 = self.extract_text_algo_1(file)
        text2 = self.extract_text_algo_2(file)

        if len(text2) > len(str(text1)):
            return text2
        else:
            return text1

    def extarct_table(self, file):

        # Read pdf into DataFrame
        try:
            df = tabula.read_pdf(file, output_format="csv")
        except:
            print("Error Reading Table")
            return

        print("\nPrinting Table Content: \n", df)
        print("\nDone Printing Table Content\n")

    def tiff_header_for_CCITT(self, width, height, img_size, CCITT_group=4):
        tiff_header_struct = '<' + '2s' + 'h' + 'l' + 'h' + 'hhll' * 8 + 'h'
        return struct.pack(tiff_header_struct,
                           b'II',  # Byte order indication: Little indian
                           42,  # Version number (always 42)
                           8,  # Offset to first IFD
                           8,  # Number of tags in IFD
                           256, 4, 1, width,  # ImageWidth, LONG, 1, width
                           257, 4, 1, height,  # ImageLength, LONG, 1, lenght
                           258, 3, 1, 1,  # BitsPerSample, SHORT, 1, 1
                           259, 3, 1, CCITT_group,  # Compression, SHORT, 1, 4 = CCITT Group 4 fax encoding
                           262, 3, 1, 0,  # Threshholding, SHORT, 1, 0 = WhiteIsZero
                           273, 4, 1, struct.calcsize(tiff_header_struct),  # StripOffsets, LONG, 1, len of header
                           278, 4, 1, height,  # RowsPerStrip, LONG, 1, lenght
                           279, 4, 1, img_size,  # StripByteCounts, LONG, 1, size of extract_image
                           0  # last IFD
                           )

    def extract_image(self, filename):
        number = 1
        pdf_reader = PdfFileReader(open(filename, 'rb'))

        for i in range(0, pdf_reader.numPages):

            page = pdf_reader.getPage(i)

            try:
                xObject = page['/Resources']['/XObject'].getObject()
            except:
                print("No XObject Found")
                return

            for obj in xObject:

                try:

                    if xObject[obj]['/Subtype'] == '/Image':
                        size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
                        data = xObject[obj]._data
                        if xObject[obj]['/ColorSpace'] == '/DeviceRGB':
                            mode = "RGB"
                        else:
                            mode = "P"

                        image_name = filename.split(".")[0] + str(number)

                        print(xObject[obj]['/Filter'])

                        if xObject[obj]['/Filter'] == '/FlateDecode':
                            data = xObject[obj].getData()
                            img = Image.frombytes(mode, size, data)
                            img.save(image_name + "_Flate.png")
                            # save_to_s3(imagename + "_Flate.png")
                            print("Image_Saved")

                            number += 1
                        elif xObject[obj]['/Filter'] == '/DCTDecode':
                            img = open(image_name + "_DCT.jpg", "wb")
                            img.write(data)
                            # save_to_s3(imagename + "_DCT.jpg")
                            img.close()
                            number += 1
                        elif xObject[obj]['/Filter'] == '/JPXDecode':
                            img = open(image_name + "_JPX.jp2", "wb")
                            img.write(data)
                            # save_to_s3(imagename + "_JPX.jp2")
                            img.close()
                            number += 1
                        elif xObject[obj]['/Filter'] == '/CCITTFaxDecode':
                            if xObject[obj]['/DecodeParms']['/K'] == -1:
                                CCITT_group = 4
                            else:
                                CCITT_group = 3
                            width = xObject[obj]['/Width']
                            height = xObject[obj]['/Height']
                            data = xObject[obj]._data  # sorry, getData() does not work for CCITTFaxDecode
                            img_size = len(data)
                            tiff_header = self.tiff_header_for_CCITT(width, height, img_size, CCITT_group)
                            img_name = image_name + '_CCITT.tiff'
                            with open(img_name, 'wb') as img_file:
                                img_file.write(tiff_header + data)

                            # save_to_s3(img_name)
                            number += 1
                except:
                    continue

        return number

    def read_pages(self, start_page=-1, end_page=-1):

        # Downloading file locally
        downloaded_file = download_file(self.url)
        print(downloaded_file)

        # breaking PDF into number of pages in diff pdf files
        self.break_pdf(downloaded_file, start_page, end_page)

        # creating a pdf reader object
        pdf_reader = PdfFileReader(open(downloaded_file, 'rb'))

        # Reading each pdf one by one
        total_pages = pdf_reader.numPages

        if start_page == -1:
            start_page = 0
        elif start_page < 1 or start_page > total_pages:
            return "Start Page Selection Is Wrong"
        else:
            start_page = start_page - 1

        if end_page == -1:
            end_page = total_pages
        elif end_page < 1 or end_page > total_pages - 1:
            return "End Page Selection Is Wrong"
        else:
            end_page = end_page

        for i in range(start_page, end_page):
            # creating a page based filename
            file = str(i + 1) + "_" + downloaded_file

            print("\nStarting to Read Page: ", i + 1, "\n -----------===-------------")

            file_text = self.extract_text(file)
            print(file_text)
            self.extract_image(file)

            self.extarct_table(file)
            os.remove(file)
            print("Stopped Reading Page: ", i + 1, "\n -----------===-------------")

        os.remove(downloaded_file)


# I have tested on these 3 pdf files
# url = "http://s3.amazonaws.com/NLP_Project/Original_Documents/Healthcare-January-2017.pdf"
url = "http://s3.amazonaws.com/NLP_Project/Original_Documents/Sample_Test.pdf"
# url = "http://s3.amazonaws.com/NLP_Project/Original_Documents/Sazerac_FS_2017_06_30%20Annual.pdf"
# creating the instance of class
pdf_extractor = PDFExtractor(url)

# Getting desired data out
pdf_extractor.read_pages(15, 23)
Ritesh Shanker
la source
0

Vous pouvez télécharger tika-app-xxx.jar (dernier) à partir d' ici .

Ensuite, placez ce fichier .jar dans le même dossier que votre fichier de script python.

puis insérez le code suivant dans le script:

import os
import os.path

tika_dir=os.path.join(os.path.dirname(__file__),'<tika-app-xxx>.jar')

def extract_pdf(source_pdf:str,target_txt:str):
    os.system('java -jar '+tika_dir+' -t {} > {}'.format(source_pdf,target_txt))

L'avantage de cette méthode:

moins de dépendance. Un fichier .jar unique est plus facile à gérer qu'un package python.

support multi-format. La position source_pdfpeut être le répertoire de tout type de document. (.doc, .html, .odt, etc.)

à jour. tika-app.jar est toujours publié avant la version appropriée du paquet tika python.

stable. Il est beaucoup plus stable et bien entretenu (Powered by Apache) que PyPDF.

désavantage:

Un jre-headless est nécessaire.

pah8J
la source
solution totalement non pythonique. Si vous le recommandez, vous devez créer un package python et demander aux gens de l'importer. Ne recommande pas d'utiliser des exécutions de ligne de commande de code java en python.
Michael Tamillow
@MichaelTamillow, si vous écrivez un code qui va être téléchargé dans pypi, j'avoue que ce n'est pas une bonne idée. Cependant, s'il ne s'agit que d'un script python avec shebang pour un usage temporaire, ce n'est pas mal, n'est-ce pas?
pah8J
Eh bien, la question n'est pas intitulée "python" - donc je pense qu'indiquer "voici comment le faire en Java" est plus acceptable que cela. Techniquement, vous pouvez faire ce que vous voulez en Python. C'est pourquoi c'est à la fois génial et terrible. L'utilisation temporaire est une mauvaise habitude.
Michael Tamillow
0

Si vous l'essayez dans Anaconda sous Windows, PyPDF2 peut ne pas gérer certains des PDF avec une structure non standard ou des caractères Unicode. Je recommande d'utiliser le code suivant si vous avez besoin d'ouvrir et de lire beaucoup de fichiers pdf - le texte de tous les fichiers pdf dans le dossier avec le chemin relatif .//pdfs//sera stocké dans la liste pdf_text_list.

from tika import parser
import glob

def read_pdf(filename):
    text = parser.from_file(filename)
    return(text)


all_files = glob.glob(".\\pdfs\\*.pdf")
pdf_text_list=[]
for i,file in enumerate(all_files):
    text=read_pdf(file)
    pdf_text_list.append(text['content'])

print(pdf_text_list)
DovaX
la source
-1

PyPDF2 fonctionne, mais les résultats peuvent varier. Je vois des résultats assez incohérents lors de l'extraction des résultats.

reader=PyPDF2.pdf.PdfFileReader(self._path)
eachPageText=[]
for i in range(0,reader.getNumPages()):
    pageText=reader.getPage(i).extractText()
    print(pageText)
    eachPageText.append(pageText)
bmc
la source
1
PyPDF2 / PyPDF3 / PyPDF4 sont tous morts. Utilisez pymupdf
Martin Thoma
-2

Comment extraire du texte d'un fichier PDF?

La première chose à comprendre est le format PDF . Il a une spécification publique écrite en anglais, voir ISO 32000-2: 2017 et lire les plus de 700 pages de la spécification PDF 1.7 . Vous avez certainement au moins besoin de lire la page wikipedia sur PDF

Une fois que vous avez compris les détails du format PDF, extraire du texte est plus ou moins facile (mais qu'en est-il du texte apparaissant en figures ou en images; sa figure 1)? Ne vous attendez pas à écrire seul un extracteur de texte logiciel parfait en quelques semaines ...

Sous Linux, vous pouvez également utiliser pdf2text que vous pouvez extraire de votre code Python.

En général, l'extraction de texte à partir d'un fichier PDF est un problème mal défini. Pour un lecteur humain, un texte pourrait être fait (sous forme de figure) à partir de différents points, ou d'une photo, etc.

Le moteur de recherche Google est capable d'extraire du texte à partir de PDF, mais il aurait besoin de plus d'un demi-milliard de lignes de code source. Avez-vous les ressources nécessaires (en personnel, en budget) pour développer un concurrent?

Une possibilité pourrait être d'imprimer le PDF sur une imprimante virtuelle (par exemple en utilisant GhostScript ou Firefox ), puis d'utiliser des techniques OCR pour extraire du texte.

Je recommanderais plutôt de travailler sur la représentation des données qui a généré ce fichier PDF, par exemple sur le code LaTeX original (ou le code Lout ) ou sur le code OOXML .

Dans tous les cas, vous devez prévoir au moins plusieurs années-personnes de développement logiciel.

Basile Starynkevitch
la source
1
Ce n'est pas une réponse. Il dit de lire ce document de 700 pages et ne donne pas une approche pour répondre réellement à la question.
xcski
@xcski: J'ai amélioré ma réponse. N'hésitez pas à me contacter par mail pour [email protected]mentionner l'URL de cette question
Basile Starynkevitch