Как запретить BeautifulSoup4 добавлять дополнительные теги <html> <body> в суп?
В версиях BeautifulSoup до 3 я мог легко взять любой фрагмент HTML и получить строковое представление следующим образом:
from BeautifulSoup import BeautifulSoup
soup3 = BeautifulSoup('<div><b>soup 3</b></div>')
print unicode(soup3)
'<div><b>soup</b></div>'
Однако с помощью BeautifulSoup4 такая же операция создает дополнительные теги:
from bs4 import BeautifulSoup
soup4 = BeautifulSoup('<div><b>soup 4</b></div>')
print unicode(soup4)
'<html><body><div><b>soup 4</b></div></body></html>'
^^^^^^^^^^^^ ^^^^^^^^^^^^^^
Мне не нужны внешние теги <html><body>..</body></html>
, которые добавляет BS4. Я просмотрел документы BS4, а также искал внутри класса, но не смог найти никаких параметров для подавления дополнительных тегов в результатах. Как мне это сделать? Переход на v3 не является опцией, поскольку синтаксический анализатор SGML, используемый в BS3, не так хорош, как парсеры lxml
или html5lib
, доступные с BS4.
Ответы
Ответ 1
Если вы хотите, чтобы ваш код работал на всех машинах, независимо от того, какой он был установлен и т.д. (та же самая версия lxml
, построенная на libxml2
2.9 по сравнению с 2.8, действует совсем по-другому, stdlib html.parser
имел некоторые радикальные изменения между 2.7.2 и 2.7.3,...), вам в значительной степени нужно обрабатывать все законные результаты.
Если вы знаете, что у вас есть фрагмент, что-то вроде этого даст вам именно этот фрагмент:
soup4 = BeautifulSoup('<div><b>soup 4</b></div>')
if soup4.body:
return soup4.body.next
elif soup4.html:
return soup4.html.next
else:
return soup4
Конечно, если вы знаете, что ваш фрагмент - это один div
, он еще проще - но не так просто думать о прецеденте, где вы бы знали, что:
soup4 = BeautifulSoup('<div><b>soup 4</b></div>')
return soup4.div
Если вы хотите узнать, почему это происходит:
BeautifulSoup
предназначен для анализа HTML-документов. HTML-фрагмент не является допустимым документом. Это довольно близко к документу, но это недостаточно хорошо, чтобы гарантировать, что вы вернете именно то, что вы ему даете.
Как Различия между парсерами говорят:
Существуют также различия между анализаторами HTML. Если вы дадите Beautiful Soup идеальный HTML-документ, эти различия не имеют значения. Один парсер будет быстрее другого, но все они дают вам структуру данных, которая выглядит точно так же, как и исходный HTML-документ.
Но если документ не идеально сформирован, разные парсеры будут давать разные результаты.
Итак, хотя эта точная разница не документирована, это просто частный случай чего-то, что есть.
Ответ 2
Как было отмечено в старой документации BeautifulStoneSoup:
Класс BeautifulSoup полон эвристик, основанных на веб-браузере, для того, чтобы предсказать намерение авторов HTML. Но у XML нет фиксированного набора тегов, поэтому эти эвристики не применяются. Поэтому BeautifulSoup не очень хорошо выполняет XML.
Используйте класс BeautifulStoneSoup для анализа XML-документов. Это общий класс без каких-либо специальных знаний о любом диалекте XML и очень простых правилах о размещении тегов...
И в Документах BeautifulSoup4:
Для разбора XML не существует класса BeautifulStoneSoup. Для анализа XML вы передаете "xml" в качестве второго аргумента конструктору BeautifulSoup. По той же причине конструктор BeautifulSoup больше не распознает аргумент isHTML.
Возможно, это даст то, что вы хотите.