From d4aa43755896a5e347333f4cd970984a23c79811 Mon Sep 17 00:00:00 2001 From: erjemin Date: Fri, 19 Dec 2025 14:48:55 +0300 Subject: [PATCH] =?UTF-8?q?mod:=20=D0=A1=D0=B0=D0=BD=D0=B8=D1=82=D0=B0?= =?UTF-8?q?=D0=B9=D0=B7=D0=B5=D1=80=20=D0=BE=D0=BF=D1=82=D0=B8=D0=BC=D0=B8?= =?UTF-8?q?=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=20=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=BB=D0=B6=D0=B5=D0=BD=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D0=B1=D1=8B=D1=81=D1=82=D1=80=D0=B5=D0=B5?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etpgrf/sanitizer.py | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/etpgrf/sanitizer.py b/etpgrf/sanitizer.py index 1f487cc..56cf45e 100644 --- a/etpgrf/sanitizer.py +++ b/etpgrf/sanitizer.py @@ -2,7 +2,7 @@ # Модуль для очистки и нормализации HTML-кода перед типографикой. import logging -from bs4 import BeautifulSoup, NavigableString +from bs4 import BeautifulSoup from .config import (SANITIZE_ALL_HTML, SANITIZE_ETPGRF, SANITIZE_NONE, HANGING_PUNCTUATION_CLASSES, PROTECTED_HTML_TAGS) @@ -24,7 +24,16 @@ class SanitizerProcessor: if mode is False: mode = SANITIZE_NONE self.mode = mode - self._etp_classes_to_clean = frozenset(HANGING_PUNCTUATION_CLASSES.values()) + + # Оптимизация: заранее готовим CSS-селектор для поиска висячей пунктуации + if self.mode == SANITIZE_ETPGRF: + # Собираем уникальные классы + unique_classes = sorted(list(frozenset(HANGING_PUNCTUATION_CLASSES.values()))) + # Формируем селектор вида: span.class1, span.class2, ... + # Это позволяет использовать нативный парсер (lxml) для поиска, что намного быстрее python-лямбд. + self._etp_selector = ", ".join(f"span.{cls}" for cls in unique_classes) + else: + self._etp_selector = None logger.debug(f"SanitizerProcessor `__init__`. Mode: {self.mode}") @@ -36,11 +45,11 @@ class SanitizerProcessor: :return: Обработанный объект BeautifulSoup или строка (в режиме 'html'). """ if self.mode == SANITIZE_ETPGRF: - # Находим все span'ы, у которых есть с хотя бы одним из наших классов висячей пунктуации - spans_to_clean = soup.find_all( - name='span', - class_=lambda c: c and any(etp_class in c.split() for etp_class in self._etp_classes_to_clean) - ) + if not self._etp_selector: + return soup + + # Используем CSS-селектор для быстрого поиска всех нужных элементов + spans_to_clean = soup.select(self._etp_selector) # "Агрессивная" очистка: просто "разворачиваем" все найденные теги, # заменяя их своим содержимым. @@ -50,13 +59,18 @@ class SanitizerProcessor: return soup elif self.mode == SANITIZE_ALL_HTML: - # Возвращаем только текст, удаляя все теги - # При этом уважаем защищенные теги, не извлекая текст из них. - text_parts = [ - str(node) for node in soup.descendants - if isinstance(node, NavigableString) and node.parent.name not in PROTECTED_HTML_TAGS - ] - return "".join(text_parts) + # Оптимизированный подход: + # 1. Удаляем защищенные теги (script, style и т.д.) вместе с содержимым. + # Используем select для поиска, так как это обычно быстрее. + if PROTECTED_HTML_TAGS: + # Формируем селектор: script, style, pre, ... + protected_selector = ", ".join(PROTECTED_HTML_TAGS) + for tag in soup.select(protected_selector): + tag.decompose() # Полное удаление тега из дерева + + # 2. Извлекаем чистый текст из оставшегося дерева. + # get_text() работает на уровне C (в lxml) и намного быстрее ручного обхода. + return soup.get_text() # Если режим не задан, ничего не делаем - return soup \ No newline at end of file + return soup