Подтвердить что ты не робот

Как запретить 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.

4b9b3361

Ответ 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.

Возможно, это даст то, что вы хотите.