diff --git a/site/parser.py b/site/parser.py index e6a9053..5c2beab 100644 --- a/site/parser.py +++ b/site/parser.py @@ -122,12 +122,21 @@ def _parse_doc(file_bytes: bytes) -> dict: # ── PDF ── def _parse_pdf(file_bytes: bytes) -> dict: + """ + Извлечь текст и таблицы из PDF через pdfplumber. + + Таблицы: пробуем два режима — с рамками (lines) и без (text). + Отбрасываем полностью пустые таблицы. + Текст: извлекаем построчно, сохраняем номера страниц. + """ result = {"elements": [], "errors": []} try: import pdfplumber with pdfplumber.open(io.BytesIO(file_bytes)) as pdf: for page in pdf.pages: pn = page.page_number + + # ── Текст: каждая непустая строка → paragraph ── text = page.extract_text() if text: for line in text.split("\n"): @@ -139,19 +148,51 @@ def _parse_pdf(file_bytes: bytes) -> dict: "text": line, "page": pn, }) + + # ── Таблицы: с рамками (lines) ── tables = page.extract_tables() - for tbl in tables: - if tbl: - result["elements"].append({ - "type": "table", - "rows": tbl, - "page": pn, - }) + if tables: + for tbl in tables: + if tbl and _table_has_content(tbl): + 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({ + "type": "table", + "rows": tbl, + "page": pn, + }) + except Exception as e: result["errors"].append(f"pdfplumber: {e}") return result +def _table_has_content(tbl: list) -> bool: + """ + Проверить что в таблице есть хоть одна непустая ячейка. + Игнорирует None и пустые строки. + """ + for row in tbl: + if row: + for cell in row: + if cell and str(cell).strip(): + return True + return False + + # ── ZIP ── def _parse_zip(file_bytes: bytes) -> dict: