#python #html #beautifulsoup #innerhtml
#python #HTML #beautifulsoup #innerhtml
Вопрос:
Допустим, у меня есть страница с div
. Я могу легко получить этот div с помощью soup.find()
.
Теперь, когда у меня есть результат, я хотел бы напечатать ВЕСЬ innerhtml
этот div
текст ЦЕЛИКОМ: я имею в виду, мне нужна строка со ВСЕМИ html-тегами и текстом по отдельности, точно такая же, как строка, которую я получил бы с помощью javascript obj.innerHTML
. Возможно ли это?
Ответ №1:
TL; DR
Используйте BeautifulSoup 4, element.encode_contents()
если вам нужна байтовая строка в кодировке UTF-8, или используйте element.decode_contents()
, если вам нужна строка Python в Юникоде. Например, метод DOM innerHTML может выглядеть примерно так:
def innerHTML(element):
"""Returns the inner HTML of an element as a UTF-8 encoded bytestring"""
return element.encode_contents()
В настоящее время этих функций нет в онлайн-документации, поэтому я приведу текущие определения функций и строку doc из кода.
encode_contents
— начиная с 4.0.4
def encode_contents(
self, indent_level=None, encoding=DEFAULT_OUTPUT_ENCODING,
formatter="minimal"):
"""Renders the contents of this tag as a bytestring.
:param indent_level: Each line of the rendering will be
indented this many spaces.
:param encoding: The bytestring will be in this encoding.
:param formatter: The output formatter responsible for converting
entities to Unicode characters.
"""
Смотрите также документацию по форматерам; скорее всего, вы будете использовать formatter="minimal"
(по умолчанию) или formatter="html"
(для html-объектов), если вы не хотите каким-либо образом обрабатывать текст вручную.
encode_contents
возвращает закодированную байтовую строку. Если вам нужна строка Python в Юникоде, используйте decode_contents
вместо этого.
decode_contents
— начиная с 4.0.1
decode_contents
делает то же самое, что encode_contents
но возвращает строку Python в Юникоде вместо закодированной байтовой строки.
def decode_contents(self, indent_level=None,
eventual_encoding=DEFAULT_OUTPUT_ENCODING,
formatter="minimal"):
"""Renders the contents of this tag as a Unicode string.
:param indent_level: Each line of the rendering will be
indented this many spaces.
:param eventual_encoding: The tag is destined to be
encoded into this encoding. This method is _not_
responsible for performing that encoding. This information
is passed in so that it can be substituted in if the
document contains a <META> tag that mentions the document's
encoding.
:param formatter: The output formatter responsible for converting
entities to Unicode characters.
"""
BeautifulSoup 3
BeautifulSoup 3 не имеет вышеуказанных функций, вместо этого он имеет renderContents
def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
prettyPrint=False, indentLevel=0):
"""Renders the contents of this tag as a string in the given
encoding. If encoding is None, returns a Unicode string.."""
Эта функция была добавлена обратно в BeautifulSoup 4 (в версии 4.0.4) для совместимости с BS3.
Комментарии:
1. Это правильный ответ. ответ @peewhy не работает по причинам, изложенным Крисом.
2. Кто-нибудь знает, почему это недокументировано? Похоже, это был бы распространенный вариант использования.
Ответ №2:
Одним из вариантов может быть использование чего-то подобного:
innerhtml = "".join([str(x) for x in div_element.contents])
Комментарии:
1. С этим связано несколько других проблем. Во-первых, он не экранирует html-объекты (такие как больше, чем и меньше, чем) внутри строковых элементов. Во-вторых, он будет записывать содержимое комментариев, но не сами теги комментариев.
2. Добавление еще одной причины не использовать это в комментариях @ChrisD: это приведет к ошибке UnicodeDecodeError для содержимого, которое содержит символы, отличные от ASCII.
Ответ №3:
Учитывая элемент BS4 soup, подобный <div id="outer"><div id="inner">foobar</div></div>
, вот несколько различных методов и атрибутов, которые можно использовать для извлечения его HTML и текста различными способами, а также пример того, что они вернут.
innerHTML:
inner_html = element.encode_contents()
'<div id="inner">foobar</div>'
outerHTML:
outer_html = str(element)
'<div id="outer"><div id="inner">foobar</div></div>'
outerHTML (приукрашенный):
pretty_outer_html = element.prettify()
'''<div id="outer">
<div id="inner">
foobar
</div>
</div>'''
Только текст (используя .text):
element_text = element.text
'foobar'
Только текст (используя .string):
element_string = element.string
'foobar'
Ответ №4:
str(element)
помогает получить outerHTML, а затем удалить внешний тег из внешней HTML-строки.
Комментарии:
1. Как удалить внешний тег из внешней HTML-строки?
Ответ №5:
Как насчет просто unicode(x)
? Кажется, у меня работает.
Редактировать: Это даст вам внешний HTML, а не внутренний.
Комментарии:
1. Это вернет div, включающий внешний элемент, а не только содержимое.
2. Вы правы. Пока оставляем это здесь на случай, если это поможет кому-то еще.
Ответ №6:
Самый простой способ — использовать свойство children.
inner_html = soup.find('body').children
он вернет список. Итак, вы можете получить полный код, используя простой цикл for .
for html in inner_html:
print(html)
Комментарии:
1. чтобы вернуть содержимое :
"".join(map(str,soup.find('body').children)).strip()
Ответ №7:
Если я правильно понимаю, вы имеете в виду, что для примера, подобного этому:
<div class="test">
text in body
<p>Hello World!</p>
</div>
вывод должен de выглядеть следующим образом:
text in body
<p>Hello World!</p>
Итак, вот ваш ответ:
''.join(map(str,tag.contents))
Ответ №8:
Для простого текста, красивый суп 4 get_text()
Если вам нужен только читаемый человеком текст внутри документа или тега, вы можете использовать get_text()
метод. Он возвращает весь текст в документе или под тегом в виде одной строки в Юникоде:
markup = '<a href="http://example.com/">nI linked to <i>example.com</i>n</a>'
soup = BeautifulSoup(markup, 'html.parser')
soup.get_text()
'nI linked to example.comn'
soup.i.get_text()
'example.com'
Вы можете указать строку, которая будет использоваться для соединения фрагментов текста вместе:
soup.get_text("|")
'nI linked to |example.com|n'
Вы можете указать Beautiful Soup удалять пробелы из начала и конца каждого бита текста:
soup.get_text("|", strip=True)
'I linked to|example.com'
Но в этот момент вы можете захотеть вместо этого использовать .stripped_strings
генератор и обработать текст самостоятельно:
[text for text in soup.stripped_strings]
# ['I linked to', 'example.com']
Начиная с версии Beautiful Soup 4.9.0, когда используются lxml
или html.parser
, содержимое тегов <script>
, <style>
и <template>
не считается ‘text’
, поскольку эти теги не являются частью видимого пользователем содержимого страницы.
Смотрите здесь:https://www.crummy.com/software/BeautifulSoup/bs4/doc/#get-text
Комментарии:
1. …был ли вопрос другим вопросом в какой-то момент?
2. @Driftr95 Прошло некоторое время, и я забыл.