66 votes

BeatifulSoup innerhtml?

Disons que j'ai une page avec une balise div. Je peux facilement obtenir cette div avec soup.find().

Maintenant que j'ai le résultat, j'aimerais imprimer le innerhtml COMPLET de cette div : je veux dire, j'aurais besoin d'une chaîne avec TOUS les balises html et le texte tous réunis, exactement comme la chaîne que je pourrais obtenir en javascript avec obj.innerHTML. Est-ce possible ?

105voto

ChrisD Points 537

TL;DR

Avec BeautifulSoup 4, utilisez element.encode_contents() si vous voulez une chaîne d'octets encodée en UTF-8, ou utilisez element.decode_contents() si vous voulez une chaîne Unicode Python. Par exemple, la méthode innerHTML du DOM ressemblerait à ceci :

def innerHTML(element):
    """Retourne le HTML interne d'un élément en tant que chaîne d'octets encodée en UTF-8."""
    return element.encode_contents()

Ces fonctions ne sont actuellement pas dans la documentation en ligne, je vais donc citer les définitions actuelles des fonctions et la chaîne de documentation du code.

encode_contents - depuis la version 4.0.4

def encode_contents(
    self, indent_level=None, encoding=DEFAULT_OUTPUT_ENCODING,
    formatter="minimal"):
    """Rend le contenu de cette balise en tant que chaîne d'octets.

    :param indent_level: Chaque ligne du rendu sera
       indentée de ce nombre d'espaces.

    :param encoding: La chaîne d'octets sera dans cet encodage.

    :param formatter: Le formateur de sortie responsable de la conversion
       des entités en caractères Unicode.
    """

Voir aussi la documentation sur les formateurs ; vous utiliserez probablement formatter="minimal" (le défaut) ou formatter="html" (pour les entités html) à moins que vous ne vouliez traiter le texte manuellement de quelque manière.

encode_contents renvoie une chaîne d'octets encodée. Si vous voulez une chaîne Unicode Python, utilisez plutôt decode_contents.


decode_contents - depuis la version 4.0.1

decode_contents fait la même chose que encode_contents mais renvoie une chaîne Unicode Python au lieu d'une chaîne d'octets encodée.

def decode_contents(self, indent_level=None,
                   eventual_encoding=DEFAULT_OUTPUT_ENCODING,
                   formatter="minimal"):
    """Rend le contenu de cette balise en tant que chaîne Unicode.

    :param indent_level: Chaque ligne du rendu sera
       indentée de ce nombre d'espaces.

    :param eventual_encoding: La balise est destinée à être
       encodée dans cet encodage. Cette méthode n'est _pas_
       responsable de réaliser cette encodage. Ces informations
       sont passées pour qu'elles puissent être substituées si le
       document contient une balise  mentionnant l'encodage du document.

    :param formatter: Le formateur de sortie responsable de la conversion
       des entités en caractères Unicode.
    """

BeautifulSoup 3

BeautifulSoup 3 n'a pas les fonctions mentionnées ci-dessus, à la place, il a renderContents

def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
                   prettyPrint=False, indentLevel=0):
    """Rend le contenu de cette balise en tant que chaîne dans l'encodage donné.
    Si l'encodage est None, renvoie une chaîne Unicode."""

Cette fonction a été ajoutée à BeautifulSoup 4 (dans la version 4.0.4) pour la compatibilité avec BS3.

16voto

peewhy Points 400

Une des options pourrait être d'utiliser quelque chose comme ça :

 innerhtml = "".join([str(x) for x in div_element.contents])

2 votes

Il y a quelques autres problèmes avec cela. Tout d'abord, il n'échappe pas les entités html (comme supérieur à et inférieur à) dans les éléments de chaîne. Deuxièmement, il écrira le contenu des commentaires mais pas les balises de commentaire elles-mêmes.

0 votes

Ajout d'une autre raison de ne pas utiliser cela pour les commentaires de @ChrisD : Cela générera une UnicodeDecodeError sur le contenu qui inclut des caractères non-ASCII.

9voto

Pikamander2 Points 2060

Étant donné un élément BS4 soup comme

foobar

, voici quelques méthodes et attributs différents qui peuvent être utilisés pour récupérer son HTML et son texte de différentes manières, ainsi qu'un exemple de ce qu'ils renverront.


InnerHTML:

inner_html = element.encode_contents()

'foobar'

OuterHTML:

outer_html = str(element)

'foobar'

OuterHTML (pré-formaté):

pretty_outer_html = element.prettify()

'''

  foobar

'''

Texte uniquement (en utilisant .text):

element_text = element.text

'foobar'

Texte uniquement (en utilisant .string):

element_string = element.string

'foobar'

4 votes

Cela supprime les balises internes.

0 votes

Peut-être avez-vous manqué la partie où la question dit "J'aurais besoin d'une chaîne avec TOUS les balises html"

3voto

Amir Saniyan Points 2406

str(element) vous aide à obtenir outerHTML, puis supprimez la balise extérieure de la chaîne HTML extérieure.

0 votes

Comment supprimer la balise extérieure de la chaîne HTML extérieure?

1voto

Michael Litvin Points 524

Que diriez-vous simplement de unicode(x)? Cela semble fonctionner pour moi.

Édition : Cela vous donnera le HTML extérieur et non l'intérieur.

1 votes

Cela renverra la div comprenant l'élément extérieur, pas seulement le contenu.

0 votes

Vous avez raison. Laissez ceci ici pour l'instant au cas où cela pourrait aider quelqu'un d'autre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X