Extraire les données d'une facture PDF avec Python

Pour extraire les données d'une facture à partir d'un PDF avec Python, vous lisez le texte du fichier, puis vous extrayez des champs nommés de ce texte. Deux étapes, peut-être quarante lignes de code, et cela fonctionne à merveille sur la première facture que vous essayez. Puis le fournisseur numéro sept déplace son numéro de facture de trois lignes vers le haut, et votre parseur commence à renvoyer None à deux heures du matin.

Cette deuxième partie est le véritable sujet de cet article. La lecture est facile. Rester correct est le vrai travail.

Points clés

  • Python extrait le texte des factures en quelques lignes. Le maintenir correct sur des centaines de mises en page de fournisseurs est ce qui vous coûte réellement.
  • Un PDF n'est pas un format de données. C'est une description typographique d'une page imprimée, c'est pourquoi une regex écrite pour la mise en page d'un fournisseur est une chose fragile.
  • Les expressions régulières et les modèles par fournisseur évoluent de manière linéaire avec votre liste de fournisseurs. Ce n'est pas le cas des modèles de vision, car ils lisent la page au lieu de la chaîne de caractères.
  • Quel que soit l'outil qui extrait les données, votre propre code doit vérifier l'arithmétique. Les articles dont la somme ne correspond pas au sous-total sont le détecteur de bugs le moins cher que vous n'écrirez jamais.
  • L'extraction est rarement ce qui pousse les gens à arrêter de construire eux-mêmes. La file d'attente des exceptions, la correspondance des fournisseurs et l'intégration comptable le sont.

Le format PDF

Le format PDF est polyvalent, permettant une représentation fidèle des documents papier, tels que les factures, sans limiter leur conception. Il provient de l’univers de l’impression et a été conçu pour être une représentation numérique d’une page imprimée. Cette flexibilité offre une grande liberté, permettant aux créateurs de PDF de s’exprimer et de se conformer à diverses réglementations et normes.

Cependant, le défi apparaît lorsque les données sont verrouillées au sein d’un PDF. La nature libre et parfois complexe du format s’accorde mal avec l’approche structurée et cohérente nécessaire au traitement des grandes quantités de données dans une entreprise.

A screen capture of PDF file format layers
PDF file format layers

Un PDF stocke l'emplacement de chaque glyphe sur la page. Il ne stocke pas le fait que le nombre en bas à droite est le total. Cette relation vit dans votre tête, et chaque méthode d'extraction de cet article est une tentative de l'encoder.

Quelles sont les étapes pour extraire des données d'une facture ?

Une facture est un document qui se présente généralement au format PDF. Une facture formalise une transaction entre un fournisseur et un client, où un produit ou un service est échangé contre un montant d’argent précis. Voici les étapes nécessaires pour extraire les données de ce document :

  1. Définir un schéma de données pour les données à extraire de vos factures
  2. Convertir votre facture de l’image au texte
  3. Extraire le texte de votre facture selon votre schéma de données
  4. Collecter les données extraites

A screen capture of Invoice data extraction process
Invoice data extraction process

Définir un schéma pour vos données de facture

Les factures proviennent de différents fournisseurs et chaque fournisseur personnalise généralement la présentation de ses documents. Malgré cette diversité des formes, le fond de toutes les factures reste le même : il vous faut un fournisseur, un client, une référence de facture, une date et une liste d’articles avec une quantité, une description et un coût associés. Un bon point de départ pour définir votre schéma de facture est votre logiciel de comptabilité, car c’est très probablement là que vous stockerez ces données extraites à la fin, n'est-ce pas ? Si vous recherchez simplement un format couvrant tous les cas possibles, je vous recommande le site schema.org, qui définit de manière pratique une série de formats de données conformes aux normes de l'industrie pour de nombreux domaines, y compris les factures. Parseur définit un schéma de données par défaut pour vos factures, mais vous pouvez l’adapter à votre cas d’usage en renommant les champs dans votre boîte de réception de factures, comme expliqué ici. Une fois votre format de données défini, vous pouvez passer à la conversion de votre facture de l’image au texte.

Par exemple, vous pouvez définir les champs suivants pour votre facture, à l’aide du format JSON Swagger :

{
    "InvoiceNumber": {
        "type": "string",
        "description": "The invoice number"
    },
    "InvoiceIssueDate": {
        "type": "string",
        "description": "The invoice date"
    },
    "Items": {
        "type": "array",
        "description": "The list of items in the invoice",
        "items": {
            "type": "object",
            "properties": {
                "quantity": {
                    "type": "number",
                    "description": "The quantity of the item"
                },
                "description": {
                    "type": "string",
                    "description": "The description of the item"
                },
                "unit_price": {
                    "type": "number",
                    "description": "The unit price of the item"
                },
                "price": {
                    "type": "number",
                    "description": "The total price of the item"
                }
            }
        }
    }
}

Notez ceci avant d'écrire le moindre code de parsing. C'est le contrat que chaque méthode ci-dessous doit respecter, et c'est ce que vous fournirez plus tard à un modèle de vision.

Convertir votre facture de l'image au texte

A screen capture of an invoice taken from a smartphone
Picture of an invoice taken from a smartphone

Un fichier PDF peut contenir une image. Par exemple, votre employé peut prendre rapidement une photo d'une facture avec l'appareil photo de son smartphone. Il la sauvegarde ensuite sous forme de PDF et l’envoie à votre service comptable. Votre équipe comptable est chargée d’extraire les données de cette facture et de les introduire d'une manière ou d'une autre dans votre système comptable sans erreur. L’étape suivante consiste à convertir cette image en texte, à l’aide d’un système de Reconnaissance Optique de Caractères (OCR). L’un des systèmes OCR les plus populaires est Tesseract. Tesseract est écrit en C et C++. Pour utiliser Tesseract depuis notre programme Python, nous devrons utiliser une interface (binding) comme PyTesseract. Une interface est un moyen d'appeler une bibliothèque logicielle (ici, Tesseract) à partir d'un langage dans lequel elle n'est pas écrite (ici, Python). Il existe de nombreux systèmes de ce type et leurs résultats varient fortement selon la technologie sous-jacente et la qualité du scan du document sur lequel ils travaillent. Parseur détecte de manière transparente si votre document est une image et le convertit automatiquement en texte en interne. Une fois les données du document sous forme textuelle, elles sont prêtes à être extraites.

Extraire le texte de votre facture selon votre schéma de données

Une fois votre PDF en format texte (ou interrogeable), vous pouvez utiliser la bibliothèque Python pdftotext pour extraire les données du fichier PDF, sous forme de texte. Voici un extrait de code pour extraire le texte d'un fichier PDF :

import pdftotext

# Load your invoice
with open("invoice.pdf", "rb") as file_handle:
    pdf = pdftotext.PDF(file_handle)

# Iterate over all the pages
for page in pdf:
    print(page)

Nommez ce script convert_pdf_to_text.py et exécutez-le, vous obtiendrez la facture au format texte dans la sortie standard. Si vous souhaitez rediriger la sortie vers un fichier, vous pouvez exécuter :

$ python convert_pdf_to_text.py > invoice.txt

pdftotext vous donne une chaîne de caractères plate, ce qui est parfait pour les champs d'en-tête et sans espoir pour les tableaux. Lorsque vous avez besoin des articles, optez plutôt pour pdfplumber, car il conserve les coordonnées de chaque mot et peut tenter d'extraire le tableau lui-même :

import pdfplumber

with pdfplumber.open("invoice.pdf") as pdf:
    page = pdf.pages[0]

    # Words with their positions on the page
    for word in page.extract_words():
        print(word["text"], word["x0"], word["top"])

    # And an attempt at the line-item table
    table = page.extract_table()
    if table:
        for row in table:
            print(row)

Exécutez cela sur une vraie facture de fournisseur et vous constaterez très souvent que table est None. Ce n'est pas un bug. C'est le premier signal honnête que ce problème est plus difficile qu'il n'y paraît, et nous y reviendrons ci-dessous.

Maintenant que vous avez la facture sous forme de texte, vous pouvez en extraire les données souhaitées en utilisant n'importe quelle combinaison des techniques suivantes :

  • Vous pouvez utiliser une expression régulière pour extraire les données que vous souhaitez. Les expressions régulières sont un moyen puissant d'extraire des données à partir de texte, mais elles sont également très fragiles. Si le format de la facture change, vous devrez mettre à jour votre expression régulière. De plus, les expressions régulières ne sont pas très adaptées pour extraire des données à partir de tableaux.
  • Vous pouvez utiliser un système de modèles visuels, idéalement en tirant parti de l'OCR Dynamique et de l'OCR Zonal. Il s'agit d'une méthode plus avancée pour extraire des données à partir de texte. Elle est plus robuste que les expressions régulières, mais aussi plus complexe à mettre en œuvre.
  • Vous pouvez confier la page à un modèle de vision avec un schéma et le laisser lire le document comme le fait une personne. C'est l'approche qui a changé au cours des deux dernières années, et elle a sa propre section ci-dessous.

Extrayons les données de votre facture avec le module d'expressions régulières re de Python. Voici un extrait de code pour extraire le numéro de la facture de votre facture :

import re

# Load your invoice
with open("invoice.txt", "r") as file_handle:
    invoice = file_handle.read()

# Extract the invoice number
invoice_number = re.search(r"Invoice number: (\w+)", invoice).group(1)
print(invoice_number)

Nommez ce script extract.py et exécutez-le, vous obtiendrez le numéro de facture dans la sortie standard :

$ python extract.py

Et vous obtiendrez quelque chose comme :

INV-1234

Pourquoi votre parseur de factures par regex se casse

Une regex correspond à une chaîne de caractères. Une facture est une image. Tout ce qui tourne mal découle de cette inadéquation, et cela tourne mal d'un petit nombre de façons prévisibles :

  • L'étiquette a bougé. Votre modèle est ancré à Invoice number: et le nouveau modèle dit Invoice #, ou place la valeur sur la ligne suivante au lieu de la même.
  • extract_table renvoie None. Les extracteurs de tableaux recherchent des lignes de séparation. La plupart des factures de fournisseurs alignent leurs colonnes avec des espaces blancs et ne tracent aucune bordure.
  • Le texte sort dans le mauvais ordre. Les mises en page à deux colonnes et les blocs d'adresses flottants s'entremêlent lorsque la page est aplatie en une chaîne, de sorte que les lignes de vos articles arrivent mélangées.
  • Le tableau s'étend sur plusieurs pages. Les lignes deux à neuf sont sur la page un, dix à quatorze sur la page deux, avec les en-têtes de colonnes répétés entre les deux et une ligne de sous-total prétendant être un article.
  • Trois nombres ressemblent tous au total. Sous-total, total, montant dû et solde reporté. Choisir le plus grand est une erreur sur toute facture comportant un avoir.
  • Le scan est une photographie. L'OCR lit un 8 taché comme un 3 et rien en aval ne le remarque, car 3 est un chiffre parfaitement valide.
  • Cellules fusionnées et descriptions multilignes. La description d'un produit s'étend sur trois lignes et votre logique de séparation des lignes la transforme en trois articles sans prix.

Aucun de ces problèmes n'est réparable avec une meilleure expression régulière. Ce sont tous des problèmes de mise en page déguisés en problèmes de chaînes de caractères. C'est le point où la plupart des gens commencent soit à écrire un modèle par fournisseur, qui croît indéfiniment, soit à changer d'approche.

L'approche 2026 - un modèle de vision et un schéma

Le changement utile est que vous n'avez plus besoin d'aplatir la page en texte avant d'en extraire les données. Un modèle de vision regarde la facture rendue, donc un fournisseur déplaçant son numéro de facture n'est plus un événement. Ce que vous fournissez n'est pas un modèle, c'est le schéma que vous avez écrit au début de cet article.

Contraignez la sortie pour obtenir les mêmes clés à chaque fois. Pydantic associé à un mode de sortie structurée, tel que les OpenAI's structured outputs, le fait pour vous :

from typing import List
from pydantic import BaseModel

class LineItem(BaseModel):
    description: str
    quantity: float
    unit_price: float
    amount: float

class Invoice(BaseModel):
    vendor_name: str
    invoice_number: str
    invoice_date: str      # ISO 8601
    currency: str
    subtotal: float
    tax: float
    total: float
    line_items: List[LineItem]

# Render the PDF page to an image, send it to a vision model,
# and require the response to match the Invoice schema.
# The model fills the fields. It does not get to invent the shape.

C'est véritablement la majeure partie du problème d'extraction résolue, et c'est pourquoi cette approche s'est répandue si vite. Elle introduit également un nouveau mode d'échec que les regex n'ont jamais eu : une regex qui ne trouve pas le numéro de facture renvoie None, tandis qu'un modèle qui ne le trouve pas en écrira parfois un plausible. La règle qui vous protège est simple. Le modèle propose et votre code vérifie.

Si vous préférez ne pas exécuter le modèle vous-même, la même capacité est vendue en tant que service géré par les fournisseurs de cloud, dans Azure AI Document Intelligence et Amazon Textract's AnalyzeExpense, qui renvoient tous deux les champs d'en-tête et les articles séparément. Nous avons décrit en quoi l'approche sous-jacente diffère du parsing basé sur des règles dans AI versus rule-based PDF parsers, et à quoi elle ressemble appliquée aux factures spécifiquement dans vision AI invoice processing.

La couche de validation que vous devez écrire vous-même

Quel que soit l'outil qui a produit votre JSON, ces vérifications ont leur place dans votre code, pas dans le score de confiance de l'extracteur. Elles sont peu coûteuses, déterministes et détectent les erreurs qui coûtent de l'argent :

  1. subtotal + tax + shipping - discount tombe sur total, au centime près.
  2. La somme des montants des articles correspond au sous-total. Si ce n'est pas le cas, vous avez oublié une ligne ou en avez inventé une.
  3. Chaque quantity * unit_price est égal à son propre amount.
  4. La date est parsée correctement, et elle n'est pas dans le futur.
  5. Le numéro de facture n'a pas déjà été payé pour ce fournisseur. Les paiements en double sont le bug le plus coûteux de la comptabilité fournisseurs.
  6. Le nom du fournisseur correspond à un enregistrement dans votre fichier principal des fournisseurs.
  7. Les coordonnées bancaires pour le paiement correspondent à celles déjà enregistrées pour ce fournisseur. Un changement ici est un contrôle de fraude, pas un contrôle de données.
  8. La devise est celle dans laquelle vous négociez réellement.
  9. Le numéro de bon de commande existe, et ses quantités et prix correspondent si vous effectuez un rapprochement à deux ou trois voies.
  10. Chaque champ requis est présent et non vide.

Tout ce qui échoue est envoyé à une personne, pas dans la comptabilité :

def validate(invoice):
    errors = []

    if abs(invoice.subtotal + invoice.tax - invoice.total) > 0.01:
        errors.append("totals_do_not_add_up")

    line_sum = sum(item.amount for item in invoice.line_items)
    if invoice.line_items and abs(line_sum - invoice.subtotal) > 0.01:
        errors.append("line_items_do_not_sum_to_subtotal")

    if not invoice.invoice_number:
        errors.append("missing_invoice_number")

    return errors

Dix lignes d'arithmétique détecteront plus de vrais problèmes que n'importe quelle quantité d'ajustement de prompt.

Qu'en est-il de invoice2data et des autres bibliothèques ?

invoice2data mérite une mention honnête, car c'est le premier résultat sur lequel beaucoup de gens atterrissent et c'est un très bon logiciel. C'est un outil en ligne de commande et une bibliothèque Python qui fait correspondre les factures à des modèles YAML que vous écrivez par fournisseur, avec les règles de correspondance dans le contrôle de version plutôt qu'enfouies dans votre code. Si vous avez une douzaine de fournisseurs qui ne modifient jamais leur mise en page, il vous servira bien pendant des années.

La limite réside dans la conception, pas dans la qualité. Un modèle par fournisseur signifie que votre maintenance croît avec votre liste de fournisseurs, et les modèles se cassent exactement pour les raisons énumérées ci-dessus. Quelque part entre vingt et trente mises en page actives, la personne qui maintient les modèles fait plus de travail que la personne qui retapait les factures.

Le même raisonnement s'applique à l'ensemble des bibliothèques plus larges. pdfplumber, PyMuPDF, pdftotext et pytesseract excellent tous dans leur travail réel, qui consiste à extraire des caractères et des coordonnées d'une page. Aucune d'entre elles n'a jamais été conçue pour savoir quel nombre est le total. Nous comparons cet ensemble plus large dans notre sélection des best PDF parsers et des best data extraction APIs.

Collecter les données extraites

Avec Python, vous pouvez itérer sur les fichiers de factures dans un dossier donné et en extraire les données. Disons que nous extrayons le numéro de facture et le montant total, et que nous affichons le résultat au format CSV :

import os
import re

import pdftotext

# Iterate over all the PDF files in the folder
for filename in os.listdir("invoices/"):
    if not filename.endswith(".pdf"):
        continue

    # Load your invoice
    with open("invoices/" + filename, "rb") as file_handle:
        pdf = pdftotext.PDF(file_handle)

    # Print the CSV column header
    print("InvoiceNumber,TotalAmount")

    # Iterate over all the pages
    for page in pdf:
        # Extract the invoice number
        invoice_number = re.search(r"Invoice number: (\w+)", page).group(1)
        total_amount = re.search(r"Total amount: (\w+)", page).group(1)
        print(invoice_number, total_amount, sep=",")

Nommez ce script extract_to_csv.py et exécutez-le, vous obtiendrez le numéro de facture et le montant total dans la sortie standard, que vous pourrez rediriger vers un fichier CSV que vous pourrez ouvrir plus tard avec votre tableur préféré, comme Excel :

$ python extract_to_csv.py > invoices.csv

Un dossier de fichiers CSV est là où s'arrêtent la plupart des scripts de facturation, et c'est aussi là que commence l'honnête comptabilité. Quelqu'un doit encore les importer, faire correspondre les fournisseurs, rechercher les lignes que le système comptable a rejetées et déterminer quoi faire avec la facture dont la validation a échoué à 2h du matin. Ce travail n'apparaît pas dans votre script et il n'apparaît pas dans votre facture de jetons d'IA.

Quand s'arrêter de construire

Voici la partie que la plupart des vendeurs sautent, alors nous la dirons en premier. Si vous avez une poignée de fournisseurs réguliers, un ingénieur qui peut surveiller un pipeline, et personne qui attend les données, alors écrivez le script. Un modèle de vision plus un schéma plus les dix lignes de validation ci-dessus vous mèneront loin pour très peu d'argent, et vous comprendrez chaque partie.

La facture de la construction arrive plus tard, et jamais dans l'extraction. Elle arrive dans les parties que personne ne prototype :

  • La file d'attente des exceptions. Votre équipe comptable a besoin d'un écran où cliquer sur un champ le met en évidence sur la facture afin qu'ils puissent le corriger en quatre secondes au lieu de quarante. C'est un produit, pas un script.
  • La correspondance des fournisseurs. "ACME Ltd", "Acme Limited" et "ACME LTD." sont un seul fournisseur, et le grand livre n'en acceptera pas trois.
  • La détection des doublons. La même facture arrive en pièce jointe d'un e-mail le mardi et en relevé PDF le vendredi.
  • La machine à états. Files d'attente, nouvelles tentatives, échecs partiels et savoir lesquelles des 300 factures de la nuit dernière sont réellement passées.
  • La piste d'audit. Ce qui a été extrait, ce qu'un humain a changé, qui l'a approuvé et quand. La finance posera la question, généralement lors d'un audit.
  • Tout après le JSON. Le mappage des champs dans le système comptable, le codage analytique, le rapprochement des bons de commande et les lignes qu'il rejette.

Les signaux clairs qu'il est temps d'acheter plutôt que de construire sont les suivants. Vous avez dépassé environ vingt à trente mises en page de fournisseurs actives. Vous avez besoin des articles, pas seulement des champs d'en-tête. Plus qu'une poignée de vos factures arrivent sous forme de scans. Votre équipe comptable, et non votre équipe d'ingénierie, doit corriger les erreurs. Les échecs d'extraction retardent les paiements. Ou, plus couramment, la personne qui maintient le parseur a cessé de livrer quoi que ce soit d'autre.

Comment Parseur gère cela

Parseur est un parseur de documents qui fait toute la boucle, pas seulement l'étape d'extraction. Les factures arrivent à une adresse de messagerie dédiée, via l'API, ou depuis un dossier surveillé. Le moteur Vision AI lit les PDF, les scans et les photographies, et le moteur Text AI lit les e-mails et les documents textuels. Les champs ressortent nommés et typés, et les articles ressortent sous forme de lignes. Il n'y a aucun modèle à écrire et rien à maintenir lorsqu'un fournisseur modifie le design de sa facture.

Ce que vous obtenez en plus du JSON est la moitié contre laquelle cet article vous met en garde. Les données extraites sont révisables et corrigeables sur place, de sorte qu'une personne de la comptabilité fournisseurs corrige un total mal lu sans ouvrir de ticket. Les corrections remontent dans l'extraction. Et les données vont là où elles doivent aller grâce à l'intégration directe par webhook, Make, Zapier ou Microsoft Power Automate, ou directement de l'API sous forme de JSON.

Si vous souhaitez voir l'ensemble des champs que nous extrayons des factures par défaut, cela est documenté sur notre page sur l'OCR des factures, et le flux de travail plus large est couvert dans la capture de données de factures.

Créer mon compte gratuit
Traitez vos documents automatiquement avec Parseur. Simple, puissant, gratuit.

Conclusion

Extraire les données d'une facture à partir d'un PDF avec Python est un problème résolu pour environ cent factures et un problème non résolu pour dix mille. Le code n'est pas ce qui change entre ces deux nombres. Ce qui change, c'est le nombre de mises en page de fournisseurs que vous vous engagez discrètement à maintenir, et qui est appelé lorsque l'une d'entre elles change.

Écrivez le script. Cela vaut vraiment la peine de le faire une fois, ne serait-ce que pour découvrir exactement lequel des sept modes d'échec ci-dessus vous frappe en premier. Ensuite, décidez honnêtement si vos six prochains mois de temps sont mieux dépensés sur le huitième. Si la réponse est non, Parseur fait cela depuis 2016 et vous déchargera du dossier.

Dernière mise à jour le

Passez à l’action

Prêt à automatiser votre
extraction de données ?

Commencez gratuitement en quelques minutes et voyez comment Parseur s'intègre à votre workflow.

Aucun entraînement de modèle requis
Conçu pour de vrais workflows, pas des expérimentations
Passe du point & clic à l'API

Foire aux questions

Les questions que les développeurs posent réellement une fois que le premier script de facture fonctionne et que le deuxième fournisseur l'a cassé.

Lisez le texte du PDF avec une bibliothèque comme pdfplumber ou pdftotext, puis extrayez les champs nommés de ce texte. Pour les PDF natifs, c'est un travail en deux étapes. Pour les scans, vous avez d'abord besoin d'une passe OCR pour transformer l'image en texte. La partie qui détermine si cela fonctionne en production n'est pas la lecture, c'est la façon dont vous passez d'un mur de texte au numéro de facture, à la date, au fournisseur et aux articles quand chaque fournisseur les dispose différemment.

invoice2data est un outil en ligne de commande open-source et une bibliothèque Python qui extrait des champs de factures en utilisant des modèles YAML que vous écrivez par fournisseur. C'est un bon choix quand vous avez un petit ensemble stable de fournisseurs et que vous voulez la logique de correspondance dans le contrôle de version plutôt que dans votre code. Cela cesse d'être un bon choix au moment où l'écriture et la maintenance d'un modèle par fournisseur coûtent plus cher que la saisie manuelle qu'il a remplacée.

Traitez le tableau des articles comme une extraction séparée des champs d'en-tête, et reconstruisez-le sur plusieurs pages avant de le parser. L'extract_table de pdfplumber fonctionne sur des tableaux lignés propres et ne renvoie rien sur ceux sans bordure, ce qui est le cas de la plupart des factures de fournisseurs. Le modèle fiable consiste à détecter les limites des colonnes une fois par mise en page de fournisseur, à les conserver d'une page à l'autre, à supprimer les lignes d'en-tête répétées, puis à vérifier que la somme des lignes extraites correspond au sous-total. Si ce n'est pas le cas, vous avez manqué une ligne.

Avec des vérifications déterministes dans votre propre code, jamais avec le seul indice de confiance de l'extracteur. L'ensemble de base concerne l'arithmétique et l'identité. Confirmez que le sous-total plus les taxes plus les frais de port moins la remise correspond au total, que la somme des articles correspond au sous-total, que la date est parsée correctement et n'est pas dans le futur, que le numéro de facture n'a pas déjà été payé pour ce fournisseur, que le fournisseur existe dans votre base de fournisseurs et que la devise est celle attendue. Tout ce qui échoue est envoyé à un humain plutôt que dans la comptabilité.

Quand l'extraction cesse d'être la partie difficile. Appeler un modèle de vision est bon marché et rapide à prototyper, donc si vous avez une poignée de fournisseurs réguliers et quelqu'un qui peut surveiller le pipeline, construisez-le. La facture arrive plus tard, dans la logique de file d'attente et de nouvelle tentative, l'écran de révision des exceptions dont votre équipe comptable a besoin, la détection des doublons, la correspondance des fournisseurs, la piste d'audit et l'intégration comptable. Comptez tout cela avant de comparer les prix par page.

Oui, mais un scan nécessite une passe OCR avant que les bibliothèques de texte ne puissent voir quoi que ce soit. Une facture photographiée ou scannée est une image enveloppée dans un PDF, donc pdfplumber et pdftotext renvoient une chaîne vide dessus. La voie open-source habituelle est Tesseract via la liaison pytesseract, après le redressement et le nettoyage de l'image. Les modèles de vision modernes sautent entièrement cette étape et lisent l'image directement.

Il n'y a pas de bibliothèque de factures, seulement des bibliothèques PDF plus votre propre logique. pdfplumber est le premier choix habituel car il expose les mots avec leurs coordonnées et possède un extracteur de tableaux. PyMuPDF est plus rapide sur de gros lots. pdftotext est la solution la plus légère qui fonctionne quand vous avez juste besoin du texte brut. pytesseract gère les scans. Chacune vous donne du texte ou des boîtes. Aucune ne vous dit quel nombre est le total.

Parce qu'une regex correspond à une chaîne de caractères et qu'une facture est une image. Votre modèle est ancré à une étiquette, un saut de ligne ou une position de colonne que le nouveau modèle du fournisseur a déplacé. Les factures sont des documents visuels semi-structurés, donc ce qui vous bloque ce sont des problèmes de mise en page plutôt que des problèmes de chaînes de caractères. Les tableaux qui s'étendent sur plusieurs pages, les en-têtes répétés, les cellules fusionnées et la différence entre le sous-total, le total et le montant dû ne sont pas réparables avec une meilleure expression régulière.

Oui, et c'est maintenant le chemin le plus court d'un PDF à un JSON structuré, mais seulement avec un schéma et un validateur autour. Un modèle de vision lit la facture comme le fait un humain, donc un fournisseur qui modifie sa mise en page cesse d'être un événement. Contraignez la sortie avec un schéma JSON, en utilisant quelque chose comme les OpenAI structured outputs ou un modèle Pydantic, pour obtenir les mêmes clés à chaque fois. Ensuite, vérifiez l'arithmétique vous-même. Un modèle qui ne trouve pas le numéro de facture en produira parfois un plausible.

La précision dépend du champ et du scan, pas du produit, traitez donc tout pourcentage mis en avant comme du marketing. Les totaux imprimés et les numéros de factures sur un PDF natif propre reviennent presque parfaitement. Les mêmes champs sur un scan photographié, incliné et peu contrasté sont là où les chiffres se confondent et où un caractère erroné coûte de l'argent réel. Le chiffre qui vaut la peine d'être mesuré n'est pas la précision des caractères mais combien de factures atteignent votre système comptable sans qu'un humain n'y touche.

Vous arrêtez d'écrire quoi que ce soit par fournisseur. Toute approche qui nécessite un modèle, un ensemble de regex ou une carte de coordonnées pour chaque fournisseur croît de façon linéaire avec votre liste de fournisseurs et ne réduit la charge de travail de personne après environ vingt à trente mises en page actives. Un modèle qui lit le document visuellement est indépendant du format par conception, c'est pourquoi la dérive de mise en page cesse d'être un événement de maintenance. Ce qui nécessite encore votre attention, c'est la file d'attente des exceptions, et c'est un problème de flux de travail plutôt que d'extraction.

Écrire un CSV prend quelques lignes de Python et c'est la moitié facile. La moitié difficile consiste à introduire les données dans le système qui paie la facture, ce qui signifie mapper vos noms de champs à son schéma, faire correspondre les fournisseurs aux enregistrements existants, gérer les lignes qu'il rejette et réessayer les appels qui échouent. Planifiez cette moitié dès le départ, car un dossier de fichiers CSV que quelqu'un importe encore à la main n'a fait gagner un après-midi à personne.