web-dev-qa-db-fra.com

Recherche de texte dans un PDF en utilisant Python?

Problème
. Tous les PDF sont consultables, mais je n'ai pas trouvé de solution pour l'analyser avec python et appliquer un script pour le rechercher (à moins de le convertir d'abord en fichier texte, mais cela pourrait être une ressource -intensif pour n documents).

Ce que j'ai fait jusqu'à présent
J'ai examiné la documentation de pypdf, pdfminer, Adobe pdf et toutes les questions que j'ai pu trouver ici (bien qu'aucune ne semble résoudre directement ce problème). PDFminer semble avoir le plus de potentiel, mais après avoir lu la documentation, je ne sais même pas par où commencer.

Existe-t-il une méthode simple et efficace pour lire le texte PDF, soit par page, ligne ou tout le document? Ou toute autre solution?

25
Insarov

Cela s'appelle PDF mining, et est très difficile car:

  • Le PDF est un format de document conçu pour être imprimé et non pour être analysé. Dans un document PDF document, le texte n'est pas dans un ordre particulier (sauf si l'ordre est important pour l'impression), la plupart du temps la structure de texte d'origine est perdue (les lettres ne peuvent pas être groupées comme des mots et des mots peuvent ne pas être regroupés en phrases, et l'ordre dans lequel ils sont placés dans le journal est souvent aléatoire).
  • Il existe des tonnes de logiciels générant des PDF, beaucoup sont défectueux.

Des outils comme PDFminer utilisent l'heuristique pour regrouper à nouveau les lettres et les mots en fonction de leur position dans la page. Je suis d'accord, l'interface est de niveau assez bas, mais cela a plus de sens lorsque vous savez quel problème ils essaient de résoudre (en fin de compte, ce qui importe est de choisir à quelle distance des voisins une lettre/un mot/une ligne doit être en ordre à considérer comme faisant partie d’un paragraphe).

Une alternative coûteuse (en termes de temps/puissance informatique) consiste à générer des images pour chaque page et à les alimenter en OCR, peut-être la peine d'essayer si vous avez une très bonne OCR.

Donc ma réponse est non, il n’existe pas de méthode simple et efficace pour extraire du texte à partir de fichiers PDF - si vos documents ont une structure connue, vous pouvez affiner les règles et obtenir de bons résultats, mais c'est toujours un jeu d'argent.

J'aimerais vraiment avoir tort.

[mise à jour]

La réponse n'a pas changé mais récemment j'ai été impliqué dans deux projets: l'un d'eux utilise la vision par ordinateur afin d'extraire des données de formulaires hospitaliers scannés. L'autre extrait des données des archives judiciaires. Ce que j'ai appris c'est:

  1. La vision par ordinateur est à la portée des simples mortels en 2018. Si vous avez un bon échantillon de documents déjà classés, vous pouvez utiliser OpenCV ou SciKit-Image afin d'extraire des fonctionnalités et de former un classificateur d'apprentissage automatique pour déterminer de quel type est un document.

  2. Si le PDF que vous analysez est "consultable", vous pouvez obtenir très loin l'extraction de tout le texte en utilisant un logiciel comme pdftotext et un filtre bayésien (même type d'algorithme) utilisé pour classer le SPAM).

Il n'y a donc pas de méthode fiable et efficace pour extraire du texte de PDF mais vous n'en aurez peut-être pas besoin pour résoudre le problème en question (classification des types de documents).

32
Paulo Scardine

J'ai écrit des systèmes complets pour l'entreprise pour laquelle je travaille pour convertir des PDF en données pour le traitement (factures, règlements, tickets numérisés, etc.), et @Paulo Scardine est correct - il n'y a pas de moyen complètement fiable et facile de le faire . Cela dit, le moyen le plus rapide, le plus fiable et le moins intensif est d'utiliser pdftotext, une partie de l'ensemble d'outils xpdf . Cet outil convertira rapidement les PDF consultables en un fichier texte, que vous pouvez lire et analyser avec Python. Astuce: utilisez le -layout argument. Et d'ailleurs, tous les PDF ne sont pas consultables, seulement ceux qui contiennent du texte. Certains PDF ne contiennent que des images sans aucun texte.

12
MikeHunter

Je suis totalement une main verte, mais en quelque sorte ce script fonctionne pour moi:

# import packages
import PyPDF2
import re

# open the pdf file
object = PyPDF2.PdfFileReader("test.pdf")

# get number of pages
NumPages = object.getNumPages()

# define keyterms
String = "Social"

# extract text and do the search
for i in range(0, NumPages):
    PageObj = object.getPage(i)
    print("this is page " + str(i)) 
    Text = PageObj.extractText() 
    # print(Text)
    ResSearch = re.search(String, Text)
    print(ResSearch)
11
Emma Yu

J'ai récemment commencé à utiliser ScraperWiki pour faire ce que vous avez décrit.

Voici un exemple d'utilisation de ScraperWiki pour extraire des données PDF.

La fonction scraperwiki.pdftoxml() renvoie une structure XML.

Vous pouvez ensuite utiliser BeautifulSoup pour analyser cela dans une arborescence navigable.

Voici mon code pour -

import scraperwiki, urllib2
from bs4 import BeautifulSoup

def send_Request(url):
#Get content, regardless of whether an HTML, XML or PDF file
    pageContent = urllib2.urlopen(url)
    return pageContent

def process_PDF(fileLocation):
#Use this to get PDF, covert to XML
    pdfToProcess = send_Request(fileLocation)
    pdfToObject = scraperwiki.pdftoxml(pdfToProcess.read())
    return pdfToObject

def parse_HTML_tree(contentToParse):
#returns a navigatibale tree, which you can iterate through
    soup = BeautifulSoup(contentToParse)
    return soup

pdf = process_PDF('http://greenteapress.com/thinkstats/thinkstats.pdf')
pdfToSoup = parse_HTML_tree(pdf)
soupToArray = pdfToSoup.findAll('text')
for line in soupToArray:
    print line

Ce code va imprimer toute une pile de balises <text>. Chaque page est séparée par un </page>, Si c'est une consolation.

Si vous souhaitez que le contenu se trouve dans les balises <text>, Qui peuvent inclure des en-têtes enveloppés dans <b> Par exemple, utilisez line.contents

Si vous ne voulez que chaque ligne de texte, sans les balises, utilisez line.getText()

C'est désordonné et douloureux, mais cela fonctionnera pour les documents consultables PDF docs. Jusqu'à présent, j'ai trouvé que c'était précis, mais douloureux.

6
JasTonAChair

Je suis d'accord avec @Paulo PDF l'exploration de données est une énorme douleur. Mais vous pourriez avoir du succès avec pdftotext qui fait partie de la suite Xpdf disponible gratuitement ici:

http://www.foolabs.com/xpdf/download.html

Cela devrait être suffisant pour votre objectif si vous recherchez uniquement des mots clés uniques.

pdftotext est un utilitaire de ligne de commande, mais très simple à utiliser. Il vous donnera des fichiers texte, que vous trouverez plus faciles à utiliser.

4
qwwqwwq

Voici la solution que j'ai trouvée confortable pour ce problème. Dans la variable texte, vous obtenez le texte de PDF afin de le rechercher. Mais j'ai aussi gardé l'idée de cracher le texte en mots-clés comme je l'ai trouvé sur ce site: https://medium.com/@rqaiserr/how-to-convert-pdfs-into-searchable-key-words-with-python-85aab86c544f d'où j'ai pris cette solution, bien que la création de nltk ne soit pas très simple, il pourrait être utile à d'autres fins:

import PyPDF2 
import textract

from nltk.tokenize import Word_tokenize
from nltk.corpus import stopwords

def searchInPDF(filename, key):
    occurrences = 0
    pdfFileObj = open(filename,'rb')
    pdfReader = PyPDF2.PdfFileReader(pdfFileObj)
    num_pages = pdfReader.numPages
    count = 0
    text = ""
    while count < num_pages:
        pageObj = pdfReader.getPage(count)
        count +=1
        text += pageObj.extractText()
    if text != "":
       text = text
    else:
       text = textract.process(filename, method='tesseract', language='eng')
    tokens = Word_tokenize(text)
    punctuation = ['(',')',';',':','[',']',',']
    stop_words = stopwords.words('english')
    keywords = [Word for Word in tokens if not Word in stop_words and  not Word in punctuation]
    for k in keywords:
        if key == k: occurrences+=1
    return occurrences 

pdf_filename = '/home/florin/Downloads/python.pdf'
search_for = 'string'
print searchInPDF (pdf_filename,search_for)
2
florin27