fix: drhider PDF→DOCX via pdfplumber (LibreOffice cant do it) v1.12
Deploy contracts-flask / validate (push) Successful in 0s

This commit is contained in:
2026-07-07 16:37:36 +04:00
parent 88b63733b1
commit f68597f680
3 changed files with 61 additions and 55 deletions
+30 -27
View File
@@ -252,8 +252,9 @@ class TwoPassObfuscator:
self._sorted_keys.clear() self._sorted_keys.clear()
def _convert_pdfs_to_docx(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]: def _convert_pdfs_to_docx(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]:
"""Конвертировать PDF в DOCX через LibreOffice. При совпадении имён — _из_pdf.""" """Конвертировать PDF в DOCX через pdfplumber. При совпадении имён — _из_pdf."""
import subprocess, tempfile import pdfplumber
from docx import Document as DocxDocument
result = [] result = []
existing_names = {f[0] for f in files} existing_names = {f[0] for f in files}
for fname, content, ctype in files: for fname, content, ctype in files:
@@ -261,34 +262,36 @@ class TwoPassObfuscator:
result.append((fname, content, ctype)) result.append((fname, content, ctype))
continue continue
try: try:
with tempfile.NamedTemporaryFile(suffix='.pdf', delete=False) as tmp: doc = DocxDocument()
tmp.write(content) with pdfplumber.open(io.BytesIO(content)) as pdf:
pdf_path = tmp.name for page in pdf.pages:
outdir = tempfile.mkdtemp() tables = page.extract_tables()
subprocess.run(['libreoffice', '--headless', '--convert-to', 'docx', for table in tables:
'--outdir', outdir, pdf_path], timeout=30, capture_output=True) if table:
docx_files = [f for f in os.listdir(outdir) if f.endswith('.docx')] rows = [[str(c or "").strip() for c in (row or [])] for row in table]
if docx_files: rows = [r for r in rows if any(r)]
with open(os.path.join(outdir, docx_files[0]), 'rb') as f: if rows:
docx_content = f.read() t = doc.add_table(rows=len(rows), cols=len(rows[0]))
new_name = fname[:-4] + '.docx' t.style = 'Table Grid'
if new_name in existing_names: for ri, row in enumerate(rows):
new_name = fname[:-4] + '_из_pdf.docx' for ci, cell_text in enumerate(row):
existing_names.add(new_name) t.rows[ri].cells[ci].text = cell_text
result.append((new_name, docx_content, ctype)) text = page.extract_text()
else: if text:
log.warning("PDF→DOCX failed for %s", fname) for line in text.split('\n'):
result.append((fname, content, ctype)) line = line.strip()
if line:
doc.add_paragraph(line)
buf = io.BytesIO()
doc.save(buf)
new_name = fname[:-4] + '.docx'
if new_name in existing_names:
new_name = fname[:-4] + '_из_pdf.docx'
existing_names.add(new_name)
result.append((new_name, buf.getvalue(), ctype))
except Exception as e: except Exception as e:
log.warning("PDF→DOCX error for %s: %s", fname, e) log.warning("PDF→DOCX error for %s: %s", fname, e)
result.append((fname, content, ctype)) result.append((fname, content, ctype))
finally:
if os.path.exists(pdf_path):
os.unlink(pdf_path)
if os.path.exists(outdir):
for f in os.listdir(outdir):
os.unlink(os.path.join(outdir, f))
os.rmdir(outdir)
return result return result
def _expand_zips(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]: def _expand_zips(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]:
+30 -27
View File
@@ -252,8 +252,9 @@ class TwoPassObfuscator:
self._sorted_keys.clear() self._sorted_keys.clear()
def _convert_pdfs_to_docx(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]: def _convert_pdfs_to_docx(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]:
"""Конвертировать PDF в DOCX через LibreOffice. При совпадении имён — _из_pdf.""" """Конвертировать PDF в DOCX через pdfplumber. При совпадении имён — _из_pdf."""
import subprocess, tempfile import pdfplumber
from docx import Document as DocxDocument
result = [] result = []
existing_names = {f[0] for f in files} existing_names = {f[0] for f in files}
for fname, content, ctype in files: for fname, content, ctype in files:
@@ -261,34 +262,36 @@ class TwoPassObfuscator:
result.append((fname, content, ctype)) result.append((fname, content, ctype))
continue continue
try: try:
with tempfile.NamedTemporaryFile(suffix='.pdf', delete=False) as tmp: doc = DocxDocument()
tmp.write(content) with pdfplumber.open(io.BytesIO(content)) as pdf:
pdf_path = tmp.name for page in pdf.pages:
outdir = tempfile.mkdtemp() tables = page.extract_tables()
subprocess.run(['libreoffice', '--headless', '--convert-to', 'docx', for table in tables:
'--outdir', outdir, pdf_path], timeout=30, capture_output=True) if table:
docx_files = [f for f in os.listdir(outdir) if f.endswith('.docx')] rows = [[str(c or "").strip() for c in (row or [])] for row in table]
if docx_files: rows = [r for r in rows if any(r)]
with open(os.path.join(outdir, docx_files[0]), 'rb') as f: if rows:
docx_content = f.read() t = doc.add_table(rows=len(rows), cols=len(rows[0]))
new_name = fname[:-4] + '.docx' t.style = 'Table Grid'
if new_name in existing_names: for ri, row in enumerate(rows):
new_name = fname[:-4] + '_из_pdf.docx' for ci, cell_text in enumerate(row):
existing_names.add(new_name) t.rows[ri].cells[ci].text = cell_text
result.append((new_name, docx_content, ctype)) text = page.extract_text()
else: if text:
log.warning("PDF→DOCX failed for %s", fname) for line in text.split('\n'):
result.append((fname, content, ctype)) line = line.strip()
if line:
doc.add_paragraph(line)
buf = io.BytesIO()
doc.save(buf)
new_name = fname[:-4] + '.docx'
if new_name in existing_names:
new_name = fname[:-4] + '_из_pdf.docx'
existing_names.add(new_name)
result.append((new_name, buf.getvalue(), ctype))
except Exception as e: except Exception as e:
log.warning("PDF→DOCX error for %s: %s", fname, e) log.warning("PDF→DOCX error for %s: %s", fname, e)
result.append((fname, content, ctype)) result.append((fname, content, ctype))
finally:
if os.path.exists(pdf_path):
os.unlink(pdf_path)
if os.path.exists(outdir):
for f in os.listdir(outdir):
os.unlink(os.path.join(outdir, f))
os.rmdir(outdir)
return result return result
def _expand_zips(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]: def _expand_zips(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]:
+1 -1
View File
@@ -84,7 +84,7 @@
<a href="https://contractor.pythonk8s.services.ngcloud.ru/">Сверка договоров</a> <a href="https://contractor.pythonk8s.services.ngcloud.ru/">Сверка договоров</a>
<span class="sep">|</span> <span class="sep">|</span>
<strong>DrHider</strong> <strong>DrHider</strong>
<span style="font-size:11px;color:var(--muted);">v1.11</span> <span style="font-size:11px;color:var(--muted);">v1.12</span>
<button class="help-btn" onclick="openModal()" title="О сервисе">?</button> <button class="help-btn" onclick="openModal()" title="О сервисе">?</button>
</header> </header>