kia-command-center / scraper /pdf_extractor.py
kiafa's picture
Premium UI/UX Overhaul & Optimization Update
b96f3a5 verified
Raw
History Blame Contribute Delete
3.87 kB
"""
PDF Text Extractor - Extracts text from PDF documents.
Handles scanned PDFs, multi-column layouts, and tables.
"""
import os
import json
import time
import logging
from typing import Optional
import pdfplumber
from scraper.config import RAW_SUBDIRS
logger = logging.getLogger("PDFExtractor")
class PDFExtractor:
"""Extracts text from PDF files using pdfplumber."""
def __init__(self, output_dir: Optional[str] = None):
self.pdf_dir = RAW_SUBDIRS["pdfs"]
self.output_dir = output_dir or RAW_SUBDIRS["pdfs"]
self.results = []
os.makedirs(self.output_dir, exist_ok=True)
def extract_from_file(self, filepath: str) -> dict:
"""Extract text from a single PDF file."""
logger.info(f"πŸ“„ Extracting: {os.path.basename(filepath)}")
try:
text_parts = []
metadata = {}
with pdfplumber.open(filepath) as pdf:
metadata = {
"num_pages": len(pdf.pages),
"pdf_info": pdf.metadata or {},
}
for i, page in enumerate(pdf.pages):
page_text = page.extract_text()
if page_text:
text_parts.append(page_text)
# Also try to extract tables
tables = page.extract_tables()
for table in tables:
if table:
table_text = "\n".join(
" | ".join(str(cell or "") for cell in row)
for row in table
)
text_parts.append(f"\n[Tabela]:\n{table_text}\n")
full_text = "\n\n".join(text_parts)
result = {
"url": f"file://{filepath}",
"title": os.path.basename(filepath).replace(".pdf", ""),
"text": full_text,
"text_length": len(full_text),
"source": "PDF Document",
"num_pages": metadata.get("num_pages", 0),
"pdf_metadata": metadata.get("pdf_info", {}),
"crawled_at": time.strftime("%Y-%m-%dT%H:%M:%S"),
}
return result
except Exception as e:
logger.error(f"Error extracting {filepath}: {e}")
return {}
def extract_all(self) -> list:
"""Extract text from all PDFs in the pdfs directory."""
logger.info(f"πŸš€ Extracting all PDFs from: {self.pdf_dir}")
pdf_files = [
os.path.join(self.pdf_dir, f)
for f in os.listdir(self.pdf_dir)
if f.lower().endswith(".pdf")
]
if not pdf_files:
logger.info("No PDF files found.")
return []
for filepath in pdf_files:
result = self.extract_from_file(filepath)
if result and result.get("text_length", 0) > 50:
# Save JSON alongside PDF
json_path = filepath.replace(".pdf", ".json")
with open(json_path, "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=2)
self.results.append(result)
logger.info(f" βœ… {result['title']} ({result['num_pages']} pages, {result['text_length']} chars)")
else:
logger.info(f" ⏭️ Skipped (no text): {os.path.basename(filepath)}")
logger.info(f"βœ… PDF extraction complete: {len(self.results)} documents")
return self.results
def get_stats(self) -> dict:
return {
"source": "PDFs",
"documents": len(self.results),
"total_pages": sum(r.get("num_pages", 0) for r in self.results),
"total_chars": sum(r.get("text_length", 0) for r in self.results),
}