Extraer datos de facturas de PDF con Python

Para extraer datos de facturas de un PDF con Python lees el texto del archivo, y luego extraes campos designados de ese texto. Dos pasos, tal vez cuarenta líneas de código, y funciona maravillosamente en la primera factura en la que lo pruebas. Luego el proveedor número siete mueve su número de factura tres líneas hacia arriba, y tu analizador comienza a devolver None a las dos de la mañana.

Esa segunda parte es el tema real de este artículo. La lectura es fácil. Mantenerse correcto es el trabajo.

Key takeaways

  • Python extrae el texto de la factura en unas pocas líneas. Mantenerlo correcto en cientos de diseños de proveedores es lo que realmente te cuesta.
  • Un PDF no es un formato de datos. Es una descripción tipográfica de una página impresa, que es la razón por la cual una expresión regular escrita contra el diseño de un proveedor es algo frágil.
  • Las expresiones regulares y las plantillas por proveedor se escalan linealmente con tu lista de proveedores. Los modelos de visión no lo hacen, porque leen la página en lugar de la cadena de texto.
  • Sea lo que sea que extraiga los datos, tu propio código tiene que comprobar la aritmética. Los artículos que no suman el subtotal son el detector de errores más barato que escribirás en tu vida.
  • La extracción rara vez es lo que hace que las personas dejen de construir. La cola de excepciones, la coincidencia de proveedores y la integración contable sí lo son.

El formato PDF

El formato PDF es versátil y permite representar con precisión documentos en papel, como facturas, sin limitar su diseño. Proviene del mundo de la impresión y está diseñado para ser una representación digital de una página impresa. Esta flexibilidad ofrece una libertad significativa, permitiendo a los creadores de PDF expresarse y cumplir con diferentes normas y regulaciones.

Sin embargo, el reto aparece cuando los datos están bloqueados dentro de un PDF. La naturaleza libre y compleja del formato puede entrar en conflicto con el enfoque estructurado y coherente necesario para gestionar la gran cantidad de datos que una empresa procesa a diario.

Una captura de pantalla de las capas del formato de archivo PDF
Capas del formato de archivo PDF

Un PDF almacena dónde se asienta cada glifo en la página. No almacena el hecho de que el número en la parte inferior derecha es el total. Esa relación vive en tu cabeza, y cada método de extracción en este artículo es un intento de codificarla.

¿Cuáles son los pasos para extraer datos de una factura?

Una factura es un documento que suele venir en formato PDF. Una factura formaliza una transacción entre un proveedor y un cliente, donde un producto o servicio se intercambia por una cantidad precisa de dinero. Estos son los pasos necesarios para extraer datos de este documento:

  1. Definir un esquema para los datos que deseas extraer de tus facturas
  2. Convertir tu factura de imagen a texto
  3. Extraer el texto de tu factura según tu esquema de datos
  4. Recopilar los datos extraídos

Una captura de pantalla del proceso de extracción de datos de la factura
Proceso de extracción de datos de la factura

Define un esquema para los datos de tu factura

Las facturas provienen de diferentes proveedores y cada proveedor suele personalizar el aspecto de sus facturas. A pesar de esta diversidad en la forma, la sustancia de todas las facturas es básicamente la misma: necesitas un proveedor, un cliente, una referencia de factura, una fecha y una lista de artículos con una cantidad, descripción y costo asociados. Una excelente manera de empezar a definir el formato de tu factura sería tu software de contabilidad, ya que probablemente sea donde almacenarás los datos extraídos de la factura al final, ¿verdad? Si solo quieres un formato de datos que pueda cubrir todos los casos, te recomiendo el sitio web schema.org, que define convenientemente una serie de formatos de datos estándar del sector para muchas cosas, incluidas las facturas. Parseur define un esquema de datos predeterminado para tus facturas, pero puedes cambiarlo para adaptarlo a tu caso de uso renombrando los campos en tu buzón de facturas, como se explica aquí. Una vez que tu formato de datos esté definido, puedes convertir tu factura de imagen a texto.

Por ejemplo, puedes definir los siguientes campos para tu factura utilizando el formato JSON Swagger:

{
    "InvoiceNumber": {
        "type": "string",
        "description": "El número de factura"
    },
    "InvoiceIssueDate": {
        "type": "string",
        "description": "La fecha de la factura"
    },
    "Items": {
        "type": "array",
        "description": "La lista de artículos de la factura",
        "items": {
            "type": "object",
            "properties": {
                "quantity": {
                    "type": "number",
                    "description": "La cantidad del artículo"
                },
                "description": {
                    "type": "string",
                    "description": "La descripción del artículo"
                },
                "unit_price": {
                    "type": "number",
                    "description": "El precio unitario del artículo"
                },
                "price": {
                    "type": "number",
                    "description": "El precio total del artículo"
                }
            }
        }
    }
}

Anota esto antes de escribir cualquier código de análisis. Es el contrato que cada método a continuación debe satisfacer, y es lo que entregarás a un modelo de visión más adelante.

Convierte tu factura de imagen a texto

Una captura de pantalla de una factura tomada desde un smartphone
Imagen de una factura tomada desde un smartphone

Un archivo PDF puede contener una imagen. Por ejemplo, tu empleado puede hacer una foto rápida de una factura con la cámara de su smartphone. Luego la guarda como PDF y la envía a tu departamento de contabilidad. Tu equipo de contabilidad se encarga de extraer los datos de esta factura y, de alguna manera, ingresarlos en tu sistema de contabilidad sin ningún error. El siguiente paso es convertir esta imagen a texto utilizando un sistema de Reconocimiento Óptico de Caracteres. Uno de los sistemas OCR más populares es Tesseract. Tesseract está escrito en C y C++. Para utilizar Tesseract desde nuestro programa de Python, necesitamos emplear un binding como PyTesseract. Un binding es una manera de llamar a una biblioteca de software (en este caso, Tesseract) desde un lenguaje en el que no está escrita (en este caso, Python). Existen muchos sistemas de este tipo y sus resultados varían ampliamente dependiendo de la tecnología subyacente y la calidad del escaneo del documento. Parseur detecta de forma transparente si tu documento es una imagen y lo convierte automáticamente en texto, internamente. Una vez que los datos del documento están en forma de texto, están listos para ser extraídos.

Extrae el texto de tu factura según tu esquema de datos

Una vez que tu PDF está en formato de texto (o se puede buscar en él), puedes utilizar la biblioteca de Python pdftotext para obtener los datos del archivo PDF como texto. Aquí tienes un fragmento de código para extraer el texto de un archivo PDF:

import pdftotext

# Cargar tu factura
with open("invoice.pdf", "rb") as file_handle:
    pdf = pdftotext.PDF(file_handle)

# Iterar sobre todas las páginas
for page in pdf:
    print(page)

Nombra a este script convert_pdf_to_text.py y ejecútalo, obtendrás la factura como texto en la salida estándar. Si quieres redirigir la salida a un archivo, puedes ejecutar:

$ python convert_pdf_to_text.py > invoice.txt

pdftotext te da una cadena plana, lo cual está bien para los campos de encabezado pero es inútil para las tablas. Cuando necesitas los artículos, recurre a pdfplumber en su lugar, porque mantiene las coordenadas de cada palabra y puede intentar extraer la tabla por sí mismo:

import pdfplumber

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

    # Palabras con sus posiciones en la página
    for word in page.extract_words():
        print(word["text"], word["x0"], word["top"])

    # Y un intento en la tabla de artículos
    table = page.extract_table()
    if table:
        for row in table:
            print(row)

Ejecuta eso en una factura real de un proveedor y muy a menudo encontrarás que table es None. Eso no es un error. Es la primera señal honesta de que este problema es más difícil de lo que parece, y volveremos a ello más abajo.

Ahora que ya tienes la factura en formato de texto, puedes extraer los datos que desees de ella, utilizando cualquier combinación de las siguientes técnicas:

  • Puedes utilizar una expresión regular para extraer los datos que desees. Las expresiones regulares son una forma poderosa de extraer datos de un texto, pero también son muy frágiles. Si el formato de la factura cambia, tendrás que actualizar tu expresión regular. Además, las expresiones regulares no son muy buenas para extraer datos de tablas.
  • Puedes usar un sistema de plantillas visuales, idealmente aprovechando el OCR Dinámico y el OCR Zonal. Esta es una forma más avanzada de extraer datos del texto. Es más robusta que las expresiones regulares, pero también más compleja de implementar.
  • Puedes entregar la página a un modelo de visión con un esquema y dejar que lea el documento de la forma en que lo hace una persona. Este es el enfoque que cambió en los últimos dos años, y tiene su propia sección más abajo.

Vamos a extraer datos de tu factura con el módulo de expresiones regulares re de Python. Aquí tienes un fragmento de código para extraer el número de factura de tu factura:

import re

# Cargar tu factura
with open("invoice.txt", "r") as file_handle:
    invoice = file_handle.read()

# Extraer el número de factura
invoice_number = re.search(r"Invoice number: (\w+)", invoice).group(1)
print(invoice_number)

Nombra a este script extract.py y ejecútalo, obtendrás el número de factura en la salida estándar:

$ python extract.py

Y obtendrás algo como:

INV-1234

Por qué se rompe tu analizador de facturas con expresiones regulares

Una expresión regular coincide con una cadena. Una factura es una imagen. Todo lo que sale mal se deriva de ese desajuste, y sale mal en un pequeño número de formas predecibles:

  • La etiqueta se movió. Tu patrón está anclado a Invoice number: y la nueva plantilla dice Invoice #, o pone el valor en la línea siguiente en lugar de en la misma.
  • extract_table devuelve None. Los extractores de tablas buscan líneas de regla. La mayoría de las facturas de proveedores alinean sus columnas con espacios en blanco y no dibujan ningún borde en absoluto.
  • El texto sale en el orden incorrecto. Los diseños de dos columnas y los bloques de direcciones flotantes se intercalan cuando la página se aplana en una cadena, por lo que las filas de tus artículos llegan mezcladas.
  • La tabla abarca páginas. Las filas dos a nueve están en la página uno, diez a catorce en la página dos, con los encabezados de las columnas repetidos en el medio y una línea de subtotal pretendiendo ser un artículo.
  • Tres números se parecen al total. Subtotal, total, cantidad adeudada y saldo anterior. Elegir el más grande es incorrecto en cualquier factura que lleve un crédito.
  • El escaneo es una fotografía. El OCR lee un 8 manchado como un 3 y nada más adelante se da cuenta, porque 3 es un dígito perfectamente válido.
  • Celdas combinadas y descripciones de varias líneas. La descripción de un producto se divide en tres líneas y tu lógica de división de filas lo convierte en tres artículos sin precios.

Ninguno de estos problemas se puede solucionar con una mejor expresión regular. Todos son problemas de diseño disfrazados de problemas de cadenas de texto. Este es el punto en el que la mayoría de las personas o bien comienzan a escribir una plantilla por proveedor, que crece para siempre, o bien cambian de enfoque.

El enfoque de 2026: un modelo de visión y un esquema

El cambio útil es que ya no tienes que aplanar la página en texto antes de extraer de ella. Un modelo de visión analiza la factura renderizada, por lo que el hecho de que un proveedor mueva su número de factura ya no es un evento. Lo que proporcionas no es un patrón, es el esquema que escribiste al principio de este artículo.

Restringe la salida para obtener las mismas claves en todo momento. Pydantic junto con un modo de salida estructurada, como OpenAI's structured outputs, hace eso por ti:

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]

# Renderiza la página PDF a una imagen, envíala a un modelo de visión,
# y requiere que la respuesta coincida con el esquema Invoice.
# El modelo rellena los campos. No tiene que inventar la forma.

Esa es genuinamente la mayor parte del problema de extracción resuelta, y es por eso que este enfoque se extendió tan rápido. También introduce un nuevo modo de falla que las expresiones regulares nunca tuvieron: una expresión regular que no puede encontrar el número de factura devuelve None, mientras que un modelo que no puede encontrarlo a veces escribirá uno plausible. La regla que te mantiene a salvo es simple. El modelo propone y tu código verifica.

Si prefieres no ejecutar el modelo tú mismo, los proveedores de la nube venden la misma capacidad como un servicio administrado, en Azure AI Document Intelligence y Amazon Textract's AnalyzeExpense, que devuelven campos de encabezado y artículos por separado. Escribimos sobre cómo el enfoque subyacente difiere del análisis basado en reglas en IA frente a analizadores de PDF basados en reglas, y cómo se ve aplicado a facturas específicamente en procesamiento de facturas con IA de visión.

La capa de validación que tienes que escribir tú mismo

Sea lo que sea que haya producido tu JSON, estas comprobaciones pertenecen a tu código, no a la puntuación de confianza del extractor. Son baratas, son deterministas y detectan los errores que cuestan dinero:

  1. subtotal + impuestos + envío - descuento llega al total, con un margen de un centavo.
  2. Los importes de los artículos suman el subtotal. Si no es así, eliminaste una fila o inventaste una.
  3. Cada cantidad * precio_unitario equivale a su propio importe.
  4. La fecha se analiza y no está en el futuro.
  5. El número de factura no se ha pagado ya para ese proveedor. Los pagos duplicados son el error más caro en las cuentas por pagar.
  6. El nombre del proveedor se resuelve a un registro en tu maestro de proveedores.
  7. Los detalles bancarios de remisión coinciden con los que ya están registrados para ese proveedor. Un cambio aquí es una comprobación de fraude, no una comprobación de datos.
  8. La moneda es una con la que realmente operas.
  9. El número de orden de compra existe, y sus cantidades y precios coinciden si ejecutas una coincidencia de dos o tres vías.
  10. Cada campo requerido está presente y no está vacío.

Cualquier cosa que falle va a una persona, no al libro mayor:

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

Diez líneas de aritmética detectarán más problemas reales que cualquier cantidad de ajuste de prompts (instrucciones).

¿Qué hay de invoice2data y las otras bibliotecas?

invoice2data merece una mención honesta, porque es el primer resultado en el que mucha gente aterriza y es una pieza de software genuinamente buena. Es una herramienta de línea de comandos y una biblioteca de Python que empareja facturas con plantillas YAML que escribes por proveedor, con las reglas de coincidencia en el control de versiones en lugar de estar enterradas en tu código. Si tienes una docena de proveedores que nunca cambian su diseño, te servirá bien durante años.

El límite está en el diseño, no en la calidad. Una plantilla por proveedor significa que tu mantenimiento crece con tu lista de proveedores, y las plantillas se rompen exactamente por las razones enumeradas anteriormente. Entre unos veinte y treinta diseños activos, la persona que mantiene las plantillas hace más trabajo que la persona que solía volver a teclear las facturas.

El mismo razonamiento se aplica a la estantería más amplia de bibliotecas. pdfplumber, PyMuPDF, pdftotext y pytesseract son excelentes en sus trabajos reales, que es obtener caracteres y coordenadas de una página. Ninguna de ellas fue diseñada para saber qué número es el total. Comparamos el conjunto más amplio en nuestro resumen de los mejores analizadores de PDF y las mejores API de extracción de datos.

Recopila los datos extraídos

Con Python, puedes iterar sobre los archivos de facturas en una carpeta determinada y extraer los datos de ellos. Supongamos que extraemos el número de factura y el importe total, y mostramos el resultado en formato CSV:

import os
import re

import pdftotext

# Iterar sobre todos los archivos PDF de la carpeta
for filename in os.listdir("invoices/"):
    if not filename.endswith(".pdf"):
        continue

    # Cargar tu factura
    with open("invoices/" + filename, "rb") as file_handle:
        pdf = pdftotext.PDF(file_handle)

    # Imprimir la cabecera de la columna CSV
    print("InvoiceNumber,TotalAmount")

    # Iterar sobre todas las páginas
    for page in pdf:
        # Extraer el número de factura
        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=",")

Nombra a este script extract_to_csv.py y ejecútalo, obtendrás el número de factura y el importe total en la salida estándar, que puedes redirigir a un archivo CSV que luego podrás abrir con tu software de hoja de cálculo favorito, como Excel:

$ python extract_to_csv.py > invoices.csv

Una carpeta de archivos CSV es donde se detienen la mayoría de los scripts de facturas, y también es donde comienza la contabilidad honesta. Alguien todavía tiene que importarlos, hacer coincidir los proveedores, perseguir las filas que el sistema contable rechazó y averiguar qué hacer con la factura que falló la validación a las 2 a.m. Ese trabajo no aparece en tu script y no aparece en tu factura de tokens.

Cuándo dejar de construir

Esta es la parte que la mayoría de los proveedores se saltan, así que lo diremos primero. Si tienes un puñado de proveedores estables, un ingeniero que pueda vigilar un flujo (pipeline) y nadie esperando por los datos, entonces escribe el script. Un modelo de visión más un esquema más las diez líneas de validación anteriores te llevarán muy lejos por muy poco dinero, y entenderás cada parte del mismo.

La factura de la construcción llega más tarde, y nunca en la extracción. Llega en las partes que nadie prototipa:

  • La cola de excepciones. Tu equipo de cuentas por pagar (AP) necesita una pantalla donde al hacer clic en un campo se resalte en la factura para que puedan solucionarlo en cuatro segundos en lugar de cuarenta. Eso es un producto, no un script.
  • Coincidencia de proveedores. "ACME Ltd", "Acme Limited" y "ACME LTD." son un solo proveedor, y el libro mayor no aceptará tres.
  • Detección de duplicados. La misma factura llega como archivo adjunto de correo electrónico el martes y como PDF de estado de cuenta el viernes.
  • La máquina de estados. Colas, reintentos, fallos parciales y saber cuáles de las 300 facturas de anoche realmente pasaron.
  • El registro de auditoría. Qué se extrajo, qué cambió un humano, quién lo aprobó y cuándo. Finanzas preguntará, por lo general durante una auditoría.
  • Todo después del JSON. Mapeo de campos en el sistema contable, codificación del libro mayor (GL), coincidencia de órdenes de compra y las filas que rechaza.

Las señales claras de que es hora de comprar en lugar de construir son estas. Has superado aproximadamente de veinte a treinta diseños activos de proveedores. Necesitas artículos (líneas de pedido), no solo campos de encabezado. Más de un puñado de tus facturas llegan como escaneos. Tu equipo de AP, no tu equipo de ingeniería, necesita solucionar los errores. Las extracciones fallidas están retrasando los pagos. O, lo que es más común, la persona que mantiene el analizador ha dejado de enviar cualquier otra cosa.

Cómo lo maneja Parseur

Parseur es un analizador de documentos que hace todo el bucle, no solo el paso de extracción. Las facturas llegan a una dirección de buzón de correo dedicada, a través de la API, o desde una carpeta supervisada. El Motor de IA de Visión lee PDFs, escaneos y fotografías, y el Motor de IA de Texto lee correos electrónicos y documentos de texto. Los campos salen con nombre y tipo, y los artículos salen como filas. No hay plantillas que escribir y nada que mantener cuando un proveedor rediseña su factura.

Lo que obtienes por encima del JSON es la mitad de la que este artículo te ha estado advirtiendo. Los datos extraídos son revisables y corregibles in situ, por lo que una persona de AP soluciona un total mal leído sin abrir un ticket. Las correcciones se retroalimentan a la extracción. Y los datos van a donde necesitan ir a través de integración directa con webhook, Make, Zapier o Microsoft Power Automate, o directamente desde la API como JSON.

Si quieres ver el conjunto de campos que extraemos de las facturas por defecto, está documentado en nuestra página de OCR de facturas, y el flujo de trabajo más amplio está cubierto en captura de datos de facturas.

Crea tu cuenta gratuita
Ahorra tiempo y esfuerzo con Parseur. Automatiza tus documentos.

Conclusión

Extraer datos de facturas de un PDF con Python es un problema resuelto para unas cien facturas y uno no resuelto para diez mil. El código no es lo que cambia entre esos dos números. Lo que cambia es a cuántos diseños de proveedores te estás inscribiendo silenciosamente para mantener, y a quién se le avisa cuando uno de ellos se mueve.

Escribe el script. Genuinamente vale la pena hacerlo una vez, aunque solo sea para descubrir exactamente cuál de los siete modos de falla anteriores te golpea primero. Luego decide honestamente si es mejor pasar los próximos seis meses de tu tiempo en el octavo. Si la respuesta es no, Parseur ha estado haciendo esto desde 2016 y te quitará la carpeta de las manos.

Última actualización el

Deja de meter datos a mano

¿Listo para automatizar la
extracción de datos de tus documentos?

Empieza gratis en minutos y descubre cómo Parseur encaja en tu flujo de trabajo.

Funciona desde el primer documento, sin configuraciones complicadas
Automatiza la extracción de datos de cualquier documento
Tan fácil como un clic, tan potente como una API

Preguntas Frecuentes

Las preguntas que los desarrolladores hacen realmente una vez que el primer script de facturas está funcionando y el segundo proveedor lo ha roto.

Lee el texto del PDF con una biblioteca como pdfplumber o pdftotext, luego extrae los campos designados de ese texto. Para los PDF digitales de origen, es un trabajo de dos pasos. Para los escaneos, primero necesitas un paso de OCR para convertir la imagen en texto. La parte que decide si funciona en producción no es la lectura, sino cómo pasas de un muro de texto al número de factura, fecha, proveedor y artículos cuando cada proveedor los diseña de manera diferente.

invoice2data es una herramienta de línea de comandos de código abierto y una biblioteca de Python que extrae campos de facturas utilizando plantillas YAML que escribes por proveedor. Es una buena opción cuando tienes un conjunto pequeño y estable de proveedores y quieres la lógica de coincidencia en el control de versiones en lugar de en tu código. Deja de ser una buena opción en el punto en que escribir y mantener una plantilla por proveedor cuesta más que volver a teclear a mano lo que reemplazó.

Trata la tabla de artículos como una extracción separada de los campos de encabezado, y reconstrúyela a través de las páginas antes de analizarla. extract_table de pdfplumber funciona en tablas con líneas limpias y no devuelve nada en las que no tienen bordes, que es la mayoría de las facturas de proveedores. El patrón confiable es detectar los límites de las columnas una vez por diseño de proveedor, llevarlos a través de los saltos de página, eliminar las filas de encabezado repetidas y luego verificar que las filas que extrajiste sumen el subtotal. Si no es así, te faltó una fila.

Con comprobaciones deterministas en tu propio código, nunca solo con la confianza del extractor. El conjunto central es aritmética e identidad. Confirma que el subtotal más los impuestos más el envío menos el descuento llega al total, que los artículos suman el subtotal, que la fecha se analiza y no está en el futuro, que el número de factura no se ha pagado ya para ese proveedor, que el proveedor existe en tu maestro de proveedores y que la moneda es la que esperabas. Cualquier cosa que falle va a un humano en lugar de al libro mayor.

Cuando la extracción deja de ser la parte difícil. Llamar a un modelo de visión es barato y rápido de prototipar, así que si tienes un puñado de proveedores estables y alguien que puede vigilar el flujo (pipeline), constrúyelo. La factura llega más tarde, en la lógica de cola y reintentos, la pantalla de revisión de excepciones que necesita tu equipo de cuentas por pagar, la detección de duplicados, la coincidencia de proveedores, el registro de auditoría y la integración contable. Cuenta todo eso antes de comparar los precios por página.

Sí, pero un escaneo necesita un paso de OCR antes de que cualquiera de las bibliotecas de texto pueda ver algo. Una factura fotografiada o escaneada es una imagen envuelta en un PDF, por lo que pdfplumber y pdftotext devuelven una cadena vacía en ella. La ruta habitual de código abierto es Tesseract a través del binding de pytesseract, después de enderezar y limpiar la imagen. Los modelos de visión modernos omiten ese paso por completo y leen la imagen directamente.

No hay una biblioteca de facturas, solo bibliotecas de PDF más tu propia lógica. pdfplumber es la primera opción habitual porque expone las palabras con sus coordenadas y tiene un extractor de tablas. PyMuPDF es más rápido en lotes grandes. pdftotext es lo más pequeño que funciona cuando solo necesitas el texto sin formato. pytesseract maneja escaneos. Cada uno te da texto o cuadros. Ninguno de ellos te dice qué número es el total.

Porque una expresión regular coincide con una cadena y una factura es una imagen. Tu patrón está anclado a una etiqueta, un salto de línea o una posición de columna que la nueva plantilla del proveedor ha movido. Las facturas son documentos visuales semiestructurados, por lo que las cosas que te rompen son problemas de diseño en lugar de problemas de cadenas de texto. Las tablas que se dividen en varias páginas, los encabezados repetidos, las celdas combinadas y la diferencia entre subtotal, total y cantidad adeudada no se pueden solucionar con una mejor expresión regular.

Sí, y ahora es el camino más corto desde un PDF hasta un JSON estructurado, pero solo con un esquema y un validador a su alrededor. Un modelo de visión lee la factura como lo hace un humano, por lo que el hecho de que un proveedor cambie su diseño deja de ser un evento. Restringe la salida con un esquema JSON, utilizando algo como OpenAI structured outputs o un modelo Pydantic, para obtener las mismas claves en todo momento. Luego comprueba la aritmética tú mismo. Un modelo que no puede encontrar el número de factura a veces producirá uno plausible.

La precisión depende del campo y del escaneo, no del producto, así que trata cualquier porcentaje en titulares como marketing. Los totales impresos y los números de factura en un PDF digital de origen limpio se devuelven de forma casi perfecta. Los mismos campos en un escaneo fotografiado, sesgado y de bajo contraste es donde los dígitos se confunden y donde un carácter incorrecto cuesta dinero real. El número que vale la pena medir no es la precisión de los caracteres, sino cuántas facturas llegan a tu sistema contable sin que un humano las toque.

Dejas de escribir algo por cada proveedor. Cualquier enfoque que necesite una plantilla, un conjunto de expresiones regulares o un mapa de coordenadas para cada proveedor crece linealmente con tu lista de proveedores y no reduce la carga de trabajo de nadie después de aproximadamente veinte a treinta diseños activos. Un modelo que lee el documento visualmente es independiente del formato por diseño, que es la razón por la cual la deriva del diseño deja de ser un evento de mantenimiento. Lo que aún requiere tu atención es la cola de excepciones, y ese es un problema de flujo de trabajo más que de extracción.

Escribir un CSV requiere de unas pocas líneas de Python y es la mitad fácil. La mitad difícil es introducir los datos en el sistema que paga la factura, lo que significa mapear los nombres de tus campos a su esquema, hacer coincidir los proveedores con los registros existentes, manejar las filas que rechaza y reintentar las llamadas que fallan. Planifica esa mitad desde el principio, porque una carpeta de archivos CSV que alguien todavía importa a mano no le ha ahorrado una tarde a nadie.