v3.1.3: pdfplumber — только рамки, фильтр 30% заполнения

This commit is contained in:
2026-06-18 08:21:42 +04:00
parent 2b851505c3
commit 0151a380ea
+37 -28
View File
@@ -125,9 +125,10 @@ def _parse_pdf(file_bytes: bytes) -> dict:
""" """
Извлечь текст и таблицы из PDF через pdfplumber. Извлечь текст и таблицы из PDF через pdfplumber.
Таблицы: пробуем два режима — с рамками (lines) и без (text). Таблицы: только с видимыми рамками (lines). Безрамковые (text)
Отбрасываем полностью пустые таблицы. дают слишком много ложных срабатываний — не используем.
Текст: извлекаем построчно, сохраняем номера страниц. Отбрасываем таблицы где >50% ячеек пусты или где все ячейки
содержат фрагменты одной строки текста.
""" """
result = {"elements": [], "errors": []} result = {"elements": [], "errors": []}
try: try:
@@ -149,26 +150,11 @@ def _parse_pdf(file_bytes: bytes) -> dict:
"page": pn, "page": pn,
}) })
# ── Таблицы: с рамками (lines) ── # ── Таблицы: только с рамками ──
tables = page.extract_tables() tables = page.extract_tables()
if tables: if tables:
for tbl in tables: for tbl in tables:
if tbl and _table_has_content(tbl): if tbl and _table_has_content(tbl, min_fill_ratio=0.3):
result["elements"].append({
"type": "table",
"rows": tbl,
"page": pn,
})
# ── Таблицы: без рамок (text) — если lines ничего не дал ──
if not tables:
tbl_text = page.extract_tables({
"vertical_strategy": "text",
"horizontal_strategy": "text",
})
if tbl_text:
for tbl in tbl_text:
if tbl and _table_has_content(tbl):
result["elements"].append({ result["elements"].append({
"type": "table", "type": "table",
"rows": tbl, "rows": tbl,
@@ -180,18 +166,41 @@ def _parse_pdf(file_bytes: bytes) -> dict:
return result return result
def _table_has_content(tbl: list) -> bool: def _table_has_content(tbl: list, min_fill_ratio: float = 0.0) -> bool:
""" """
Проверить что в таблице есть хоть одна непустая ячейка. Проверить что таблица содержит осмысленные данные.
Игнорирует None и пустые строки.
Фильтры:
- Хотя бы одна непустая ячейка
- Не менее min_fill_ratio ячеек заполнены (по умолчанию 0 — без фильтра)
""" """
for row in tbl: if not tbl or not tbl[0]:
if row:
for cell in row:
if cell and str(cell).strip():
return True
return False return False
total = 0
filled = 0
all_text = ""
for row in tbl:
if not row:
continue
for cell in row:
total += 1
cell_str = str(cell).strip() if cell else ""
if cell_str:
filled += 1
all_text += " " + cell_str
if filled == 0:
return False
# Фильтр по доле заполненных ячеек
if min_fill_ratio > 0 and total > 0:
if filled / total < min_fill_ratio:
return False
return True
# ── ZIP ── # ── ZIP ──