BeautifulSoup innerhtml?

#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 Прошло некоторое время, и я забыл.