Perfiles de extracción — ajusta la detección de espacios por tipo de documento
Cada PDF esconde sus espacios de manera distinta. Un paper de arXiv usa columnas justificadas y apretadas. Un formulario del IRS depende de una alineación rígida de celdas. Una política GDPR se despliega como párrafos densos y justificados con un kerning mínimo. Un único tj_offset_threshold que funciona para uno de esos casos va a meter espacios basura en los otros.
ExtractionProfile trae nueve conjuntos de parámetros preajustados que encajan con clases reales de documento. Pasa el perfil a extract_text() o extract_words() y PDF Oxide aplica la proporción de margen de palabra correcta, el umbral de offset TJ correcto y el interruptor de umbral adaptativo correcto para ese estilo de documento.
Cobertura por binding. Los perfiles de extracción están disponibles actualmente en Python (
pdf_oxide.ExtractionProfile) y Rust (pdf_oxide::config::ExtractionProfile). Los bindings de Node, WASM, Go y C# usan internamente el valor por defectoCONSERVATIVE; para aplicar otro perfil desde esos runtimes, invoca la CLI de Rust (pdf-oxide extract --profile academic doc.pdf) o puentea a través de un paso en Python o Rust.
Ejemplo rápido
Python
from pdf_oxide import PdfDocument, ExtractionProfile
doc = PdfDocument("paper.pdf")
# Papers académicos: espaciado compacto, detección de citas activa
text = doc.extract_text(0, profile=ExtractionProfile.academic())
print(text)
Rust
use pdf_oxide::PdfDocument;
use pdf_oxide::config::ExtractionProfile;
let mut doc = PdfDocument::open("paper.pdf")?;
let text = doc.extract_text_with_profile(0, ExtractionProfile::ACADEMIC)?;
println!("{}", text);
Perfiles disponibles
| Perfil | Ideal para | Umbral TJ | Margen de palabra | Adaptativo |
|---|---|---|---|---|
conservative() |
Default — texto general, mínimos falsos espacios | −120 | 0,10 | off |
aggressive() |
PDFs que omiten espacios; une palabras pegadas | −80 | 0,20 | off |
balanced() |
Contenido mixto | −100 | 0,15 | off |
academic() |
Papers arXiv, actas de conferencia, reportes técnicos | −105 | 0,12 | on + detección de citas / correos |
policy() |
Legal, GDPR, regulaciones gubernamentales | −110 | 0,18 | on |
form() |
Formularios IRS, solicitudes, cuestionarios | −120 | 0,08 | off |
government() |
Reportes gubernamentales mixtos con tablas | −105 | 0,14 | off |
scanned_ocr() |
Salida OCR con coordenadas ruidosas | depende | depende | on |
adaptive() |
Deja que el extractor se autoconfigure con las estadísticas de fuente | depende | depende | on |
Cuándo ayuda cada perfil
Papers académicos / conferencias — academic()
Composición apretada, dos columnas, citas embebidas. Los valores por defecto suelen meter espacios de más dentro de ligaduras (fi, ff) o de menos entre palabras donde el kerning es agresivo.
doc = PdfDocument("neurips-paper.pdf")
text = doc.extract_text(0, profile=ExtractionProfile.academic())
El perfil académico activa el umbral adaptativo y la detección de citas y correos, de modo que referencias en línea como [1,2,3] y correos como author@lab.edu quedan intactos.
Formularios IRS, solicitudes — form()
Los PDFs de formularios se preocupan por la alineación de columnas más que por los límites de palabra. El perfil form() usa una proporción de margen de palabra muy ajustada (0,08) para que las etiquetas de campo rígidamente alineadas no se fundan con sus valores.
doc = PdfDocument("w2.pdf")
text = doc.extract_text(0, profile=ExtractionProfile.form())
GDPR / políticas / regulación — policy()
Los párrafos justificados insertan espacios variables que rompen el umbral por defecto. policy() usa un margen de palabra más generoso (0,18) junto con umbral adaptativo para leer correctamente la prosa legal densa.
doc = PdfDocument("gdpr.pdf")
text = doc.extract_text(0, profile=ExtractionProfile.policy())
Salida OCR escaneada — scanned_ocr()
Cuando la página viene de OCR (Tesseract, PaddleOCR, Azure), las posiciones de los caracteres son ruidosas y faltan las pistas de kerning. scanned_ocr() compensa con un umbral adaptativo que relee las estadísticas de fuente por página.
doc = PdfDocument("scanned.pdf")
text = doc.extract_text(0, profile=ExtractionProfile.scanned_ocr())
Dejar que la biblioteca elija — adaptive()
Si no sabes de antemano la clase del documento, adaptive() muestrea las estadísticas de fuente en la primera pasada y elige umbrales antes de extraer. Es un poco más lento que un perfil fijo pero aguanta bien los corpus mixtos.
for pdf_path in Path("mixed_corpus/").glob("*.pdf"):
doc = PdfDocument(str(pdf_path))
text = doc.extract_text(0, profile=ExtractionProfile.adaptive())
Campos del perfil
Cada perfil expone sus perillas de ajuste para que puedas leerlas o clonarlas:
Python
from pdf_oxide import ExtractionProfile
p = ExtractionProfile.academic()
print(p.name) # "Academic"
print(p.word_margin_ratio) # 0.12
print(p.tj_offset_threshold) # -105.0
# Inspecciona todos los presets
for profile in ExtractionProfile.all_profiles():
print(profile.name, profile.word_margin_ratio)
Rust
use pdf_oxide::config::ExtractionProfile;
let p = ExtractionProfile::ACADEMIC;
println!("{} margin={} tj={}",
p.name, p.word_margin_ratio, p.tj_offset_threshold);
Elegir un perfil en pipelines de producción
Si ingieres un corpus mixto — papers académicos junto a formularios del IRS junto a HTML exportado de la web — elige adaptive() como default. Cuesta un pequeño porcentaje por página, pero elimina los peores fallos (palabras pegadas, espacios perdidos entre columnas).
Si tu corpus es homogéneo — un pipeline de ingesta Title IX, una herramienta de revisión de contratos o un crawler de arXiv — elige el perfil que corresponda de forma explícita: vas a conseguir la mejor calidad de extracción y te ahorras el costo de muestreo por página de adaptive().
Páginas relacionadas
- Extracción de texto — API de extracción completa
- Orden de lectura (XY-cut) — orden de lectura consciente de columnas
- PDFs escaneados con OCR — cuando un perfil no alcanza
- Referencia de la API de Python