Перетворення HTML на звичайний текст, як запобігти злипанню двох абзаців тексту
Ця стаття присвячена проблемі злипання тексту під час перетворення HTML у звичайний текст і детально пояснює комбіноване використання параметрів роздільника та смуги get_text у Beautiful Soup. Надає синтетичні тестові випадки DOM і повні коди твердження Python, включаючи межі на рівні блоків/вбудовані межі, обробку пробілів, чіткі методи підготовки введення та критерії прийняття, а також забезпечує додаткові входи в OmniDoc у складних сценаріях документів.
Під час перетворення HTML на звичайний текст два абзаци тексту злипаються, здебільшого тому, що get_text() викликається безпосередньо без визначення стратегії поділу. За замовчуванням Beautiful Soup плавно зшиває всі текстові вузли, а межі між елементами на рівні блоку зникають. Ця проблема часто виникає під час використання Beautiful Soup для видобування веб-вмісту.
Замість того, щоб використовувати регулярні вирази, щоб вгадати, де розірвати після вилучення, ви можете правильно поєднати параметри separator і strip під час вилучення. У цій статті використовуються синтетичні зразки для демонстрації цього методу, наведено придатний для виконання код твердження та пояснено, які ситуації потребують перевірки вручну.
Прочитавши цю статтю, ви зможете визначити, чи застрягли ваші результати вилучення, використовувати сценарії підтвердження для перевірки виводу та з’ясувати, які проблеми можна вирішити за допомогою параметрів, а які потрібно змінити.
Що мені робити, якщо я конвертую HTML у звичайний текст? Висновок одним реченням
Спочатку використовуйте комбінацію separator='\n' і strip=True для виклику get_text(), а потім обробіть нерелевантні теги та структурні проблеми відповідно до ситуації на сторінці.
| ваша ситуація | Рекомендовані практики | причина |
|---|---|---|
| Текст між абзацами або елементами списку злипається | Встановіть як separator='\n', так і strip=True | сепаратор відповідає за поділ, смуга видаляє початкові та кінцеві пробіли |
| Встановлюється лише роздільник | Плюс strip=True | Інакше будуть збережені безглузді пробіли з відступами |
| Встановлюється лише смужка | Також додайте роздільник | Ряди все ще можуть злипатися один з одним |
| Сторінка містить нерелевантні теги, наприклад script | Видаліть ці теги перед викликом | Параметри get_text вирішують лише форматування, а не очищення вмісту. |
| Містить таблицю, полотно або тінь DOM | Змініть план збору або прийміть відсутню інформацію | Цей тип вмісту не можна вирішити шляхом налаштування параметрів |
Пастки та семантика параметрів поведінки за замовчуванням
Чому це прилипає?
Метод get_text() приймає два ключові параметри: separator і strip. Якщо параметри не передано, він напряму з’єднає всі текстові вузли в дереві тегів.
Така поведінка за замовчуванням є дуже проблематичною для елементів рівня блоку, таких як div, p і li. Розриви рядків і відступи у вихідному коді HTML часто перетворюються на порожні рядки або ігноруються після аналізу, а семантичні межі зникають.
Що роблять роздільник і смуга?
- роздільник: визначає вставку між текстовими вузлами. Встановлення
'\n'є звичайною практикою, але не ідеальною. Якщо HTML глибоко вкладений, глобальне обгортання може призвести до великої кількості порожніх рядків. - strip: керуйте видаленням пробілу на початку та в кінці кожного фрагмента тексту. Коли
strip=True, Beautiful Soup спочатку виконає.strip()для кожного незалежного NavigableString, а потім використає роздільник, щоб з’єднати їх.
Наприклад, <p> Hello </p> отримає чистий Hello замість \n Hello \n із брудним виведенням даних.
Обидва повинні використовуватися разом:
- Використання лише роздільника без смуги збереже безглузді відступи.
- За наявності лише смужки без роздільника одна лінія буде чистою, але між лініями все одно може залишатися злипання.
Щоб отримати додаткові описи параметрів, зверніться до Офіційна документація Beautiful Soup: get_text().
Синтетичні граничні тести DOM
Щоб перевірити логіку вилучення, слід створювати синтетичні зразки HTML, що містять типові граничні проблеми, а не покладатися на нестабільні реальні веб-сторінки. Наступні тестові приклади охоплюють три ситуації: зчеплення елементів на рівні блоку, міжрядковий інтервал між елементами та надлишок білого простору.
Вхідний зразок (синтетичний приклад):
<div>
<p>第一段文字</p>
<p>第二段文字<span>内联补充</span></p>
<ul>
<li> 列表项A </li>
<li>列表项B</li>
</ul>
</div>
Очікуваний правильний результат:
第一段文字
第二段文字
内联补充
列表项A
列表项B
Слід зазначити, що separator='\n' діє на витягнуті текстові вузли та не буде автоматично генерувати подвійні розриви рядків на основі тегів рівня блоку. Між абзацами та елементами списку повинні бути чіткі розриви рядків, а зайві пробіли перед і після елементів списку повинні бути видалені. «Другий текст» і «Вбудоване доповнення» розташовані в різних мітках і є текстовими вузлами, тому вони будуть розділені роздільниками.
Помилки та введення меж
Якщо введенням стає <p>End</p><script>alert(1)</script><p>Start</p>, а тег сценарію не відфільтровано, вихід міститиме alert(1). Це вірно, навіть якщо встановлено роздільник. Чи будуть вузли сценарію включені в текст, залежить від аналізатора та типу вузла.
Правильний спосіб впоратися з цим — використовувати soup.find_all('script') для видалення нерелевантних тегів перед викликом get_text або пропускати певні типи тегів під час обходу. Параметри get_text вирішують лише проблему форматування, а не проблему очищення вмісту.
Реалізація Python і перевірка тверджень
Наведений нижче код створює наведений вище зразок у пам’яті та виконує детерміновану перевірку. Приклад залежить від beautifulsoup4, рекомендована версія 4.9.0 і вище.
Щоб перевірити зовнішні файли, спершу збережіть HTML у кодуванні UTF-8, а потім скористайтеся open('file.html', encoding='utf-8'), щоб прочитати його, щоб уникнути помилок кодування, що спричиняють винятки аналізу. Код не містить мережевих запитів і є повністю самодостатнім.
from bs4 import BeautifulSoup
# 合成示例:模拟常见的HTML文本边界问题
html_content = """
<div>
<p>第一段文字</p>
<p>第二段文字<span>内联补充</span></p>
<ul>
<li> 列表项A </li>
<li>列表项B</li>
</ul>
</div>
"""
soup = BeautifulSoup(html_content, 'html.parser')
# 关键配置:separator定义边界,strip清理碎片空白
text_result = soup.get_text(separator='\n', strip=True)
# 过滤空行以获得干净的语义行
lines = [line for line in text_result.split('\n') if line]
# 验收断言:确保边界清晰且无脏数据
assert lines[0] == '第一段文字', f"段落粘连或内容错误: {lines[0]}"
assert lines[1] == '第二段文字', "块级元素间未正确分隔"
assert lines[2] == '内联补充', "内联元素文本节点被错误合并"
assert lines[3] == '列表项A', f"列表项前置空格未清除: '{lines[3]}'"
assert lines[4] == '列表项B', "列表项间边界丢失"
print("提取结果预览:")
for i, line in enumerate(lines):
print(f"{i}: [{line}]")
Очікуваний вихід цього коду – п’ять рядків чистого тексту. Якщо ваше середовище виводить більше порожніх рядків, це означає, що в DOM є чисті порожні вузли NavigableString, які не були видалені. Це нормальна поведінка html.parser і може бути відфільтровано за допомогою розуміння списку після розділення.
Цей код використовується лише для демонстрації принципу поєднання параметрів і не повинен використовуватися безпосередньо на складних сторінках у робочому середовищі.
📊 Основне порівняння
| планувати | Ефект | обмеження |
|---|---|---|
Використовуйте лише separator='\n' | Між блоками є розриви рядків | Зберігайте відступи, велика кількість порожніх рядків може з’явитися, якщо вкладення глибоке |
Використовуйте лише strip=True | Чисті початок і кінець кожного абзацу | Ряди все ще можуть злипатися один з одним |
| Використовуйте обидва одночасно | Беручи до уваги як поділ, так і видалення пробілів | Нерелевантні теги все одно потрібно видалити перед вилученням |
| Використовуйте регулярні вирази, щоб вгадати новий рядок після вилучення | Здавалося б, гнучкий | Не рекомендується, пріоритет слід віддавати правильному поєднанню параметрів під час вилучення |
Критерії прийняття та межі перевірки вручну
Автоматизоване видалення не може досягти 100% відновлення зору. У наведеній нижче таблиці наведено, як розрізнити ситуації, що «виправляються кодом», і «потрібне втручання людини». Судження ґрунтується на структурі DOM, а не на суб’єктивних відчуттях.
| спостерігати | що робити | не слід робити висновок |
|---|---|---|
| Вбудоване розділення вузлів | Перевірте, чи не розділене речення | Роздільник діє на текстові вузли |
| Плющення таблиці | Зберігайте структуру рядків і стовпців для окремої обробки | Ви не можете покладатися просто на get_text |
| Динамічно малюйте вміст | Визначте прогалини в колекції | Статичний аналіз не дорівнює візуалізації браузера |
Явний обсяг незастосовності: Beautiful Soup не може отримати дійсну інформацію, якщо HTML містить велику кількість тексту, згенерованого псевдоелементами CSS, вмістом, відтвореним Canvas, або Shadow DOM. У цей час не слід продовжувати налагодження параметрів, але слід змінити схему отримання даних або прийняти відсутню інформацію.
🎯 Який спосіб вам підходить?
якщо ви...
Потрібно витягти звичайний текст абзаців і елементів списку
Встановіть як separator='\n', так і strip=True і перевірте результат за допомогою сценарію твердження.
На сторінці є багато тегів сценарію або стилю
Видаліть ці теги перед викликом get_text і не очікуйте, що параметри вирішать проблеми з вмістом.
Необхідно зберегти структуру рядків і стовпців таблиці
Не покладайтеся лише на get_text, обробляйте структуру таблиці окремо.
Сторінка покладається на візуалізацію браузера або Shadow DOM
Змініть план збору або чітко зафіксуйте пропуски збору під час приймання.
❓ Часті запитання (FAQ)
1. Чи достатньо просто встановити роздільник?
недостатньо. Встановлення лише роздільника збереже безглузді пробіли відступів і вимагає додавання strip=True.
2. Чому у вихідних даних є порожні рядки?
У DOM можуть бути звичайні порожні вузли NavigableString, які не були видалені. Це нормальна поведінка html.parser, і її можна відфільтрувати за допомогою розуміння списку після розділення.
3. Чому в результатах відображається тег сценарію?
Параметри get_text вирішують лише проблему формату. Його слід видалити за допомогою soup.find_all('script') перед викликом або пропустити під час обходу.
4. Як перевірити, чи правильний результат вилучення?
Створіть синтетичний тестовий набір із 5–10 типових граничних випадків і запустіть сценарії твердження. Якщо швидкість проходження нижча за очікувану, перевірте, чи потрібно попередньо обробляти DOM перед її видобуванням.
📝 Підсумок
Суть проблеми адгезії полягає в комбінації параметрів під час вилучення, а не в ремонті струни після вилучення. Спочатку пропустіть синтетичні зразки та твердження, а потім розберіться з невідповідними тегами та структурними проблемами на реальній сторінці.
Спробуйте зараз: завантажте документ, щоб розпочати переклад, зберігаючи вихідний макет


