web-dev-qa-db-fra.com

Python BeautifulSoup extrait le texte entre les éléments

J'essaie d'extraire "THIS IS MON TEXTE") du code HTML suivant:

<html>
<body>
<table>
   <td class="MYCLASS">
      <!-- a comment -->
      <a hef="xy">Text</a>
      <p>something</p>
      THIS IS MY TEXT
      <p>something else</p>
      </br>
   </td>
</table>
</body>
</html>

J'ai essayé de cette façon:

soup = BeautifulSoup(html)

for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
    print hit.text

Mais je reçois tout le texte entre toutes les balises imbriquées et le commentaire.

Quelqu'un peut-il m'aider à obtenir simplement "THIS IS MON TEXTE") "?

33

En savoir plus sur la navigation à travers l’arborescence d’analyse dans BeautifulSoup . L’arbre d’analyse possède tags et NavigableStrings (comme THIS IS A TEXT). Un exemple

from BeautifulSoup import BeautifulSoup 
doc = ['<html><head><title>Page title</title></head>',
       '<body><p id="firstpara" align="center">This is paragraph <b>one</b>.',
       '<p id="secondpara" align="blah">This is paragraph <b>two</b>.',
       '</html>']
soup = BeautifulSoup(''.join(doc))

print soup.prettify()
# <html>
#  <head>
#   <title>
#    Page title
#   </title>
#  </head>
#  <body>
#   <p id="firstpara" align="center">
#    This is paragraph
#    <b>
#     one
#    </b>
#    .
#   </p>
#   <p id="secondpara" align="blah">
#    This is paragraph
#    <b>
#     two
#    </b>
#    .
#   </p>
#  </body>
# </html>

Pour vous déplacer dans l'arbre d'analyse, vous avez contents et string.

  • contents est une liste ordonnée des objets Tag et NavigableString contenus dans un élément de page

  • si une balise n'a qu'un seul nœud enfant et que ce nœud est une chaîne, le nœud enfant est rendu disponible sous la forme tag.string, ainsi que tag.contents [0]

Pour ce qui précède, c'est-à-dire que vous pouvez obtenir

soup.b.string
# u'one'
soup.b.contents[0]
# u'one'

Pour plusieurs nœuds enfants, vous pouvez par exemple avoir

pTag = soup.p
pTag.contents
# [u'This is paragraph ', <b>one</b>, u'.']

donc ici vous pouvez jouer avec contents et obtenir le contenu à l’index souhaité.

Vous pouvez également parcourir une balise, il s’agit d’un raccourci. Par exemple,

for i in soup.body:
    print i
# <p id="firstpara" align="center">This is paragraph <b>one</b>.</p>
# <p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>
35
kiriloff

Vous pouvez utiliser .contents :

>>> for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
...     print hit.contents[6].strip()
... 
THIS IS MY TEXT
14
TerryA

Utilisation .children à la place:

from bs4 import NavigableString, Comment
print ''.join(unicode(child) for child in hit.children 
    if isinstance(child, NavigableString) and not isinstance(child, Comment))

Oui, c'est un peu une danse.

Sortie:

>>> for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
...     print ''.join(unicode(child) for child in hit.children 
...         if isinstance(child, NavigableString) and not isinstance(child, Comment))
... 




      THIS IS MY TEXT
12
Martijn Pieters

avec votre propre objet de soupe:

soup.p.next_sibling.strip()
  1. vous prenez le <p> directement avec soup.p * (cela dépend du fait qu'il soit le premier <p> de l'arbre d'analyse)
  2. utilisez ensuite next_sibling sur l’objet de balise que soup.p renvoie car le texte souhaité est imbriqué au même niveau de l’arbre d’analyse syntaxique que le <p>
  3. .strip() est juste une méthode Python str pour supprimer les espaces en début et en fin de chaîne

* sinon juste trouver l'élément en utilisant votre choix de filtre (s)

dans l'interprète, cela ressemble à quelque chose comme:

In [4]: soup.p
Out[4]: <p>something</p>

In [5]: type(soup.p)
Out[5]: bs4.element.Tag

In [6]: soup.p.next_sibling
Out[6]: u'\n      THIS IS MY TEXT\n      '

In [7]: type(soup.p.next_sibling)
Out[7]: bs4.element.NavigableString

In [8]: soup.p.next_sibling.strip()
Out[8]: u'THIS IS MY TEXT'

In [9]: type(soup.p.next_sibling.strip())
Out[9]: unicode
10
Gregory Kremler

Réponse courte: soup.findAll('p')[0].next

Réponse réelle: Vous avez besoin d'un point de référence invariant à partir duquel vous pouvez atteindre votre cible.

Vous avez mentionné dans votre commentaire à la réponse de Haidro que le texte que vous souhaitez ne se trouve pas toujours au même endroit. Trouvez un sens dans lequel il se trouve au même endroit par rapport à un élément. Trouvez ensuite comment faire fonctionner BeautifulSoup dans l’arborescence d’analyse suivant ce chemin invariant.

Par exemple, dans le code HTML que vous fournissez dans la publication d'origine, la chaîne cible apparaît immédiatement après le premier élément de paragraphe et ce paragraphe n'est pas vide. Puisque findAll('p') trouvera des éléments de paragraphe, soup.find('p')[0] sera le premier élément de paragraphe.

Vous pouvez dans ce cas utiliser soup.find('p') mais soup.findAll('p')[n] est plus général puisque votre scénario actuel nécessite peut-être le cinquième paragraphe ou quelque chose du genre.

L'attribut de champ next sera le prochain élément analysé dans l'arborescence, y compris les enfants. Donc, soup.findAll('p')[0].next contient le texte du paragraphe et soup.findAll('p')[0].next.next renverra votre cible dans le code HTML fourni.

6
Bennett Brown
soup = BeautifulSoup(html)
for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
  hit = hit.text.strip()
  print hit

Ceci imprimera: CECI IS MON TEXTE Essayez ceci ..

2
Naiswita

La documentation BeautifulSoup fournit un exemple sur la suppression d'objets d'un document à l'aide de la méthode d'extraction. Dans l'exemple suivant, l'objectif est de supprimer tous les commentaires du document:

Suppression d'éléments

Une fois que vous avez une référence à un élément, vous pouvez l'extraire de l'arbre avec la méthode extract. Ce code supprime tous les commentaires d'un document:

from BeautifulSoup import BeautifulSoup, Comment
soup = BeautifulSoup("""1<!--The loneliest number-->
                    <a>2<!--Can be as bad as one--><b>3""")
comments = soup.findAll(text=lambda text:isinstance(text, Comment))
[comment.extract() for comment in comments]
print soup
# 1
# <a>2<b>3</b></a>
1
alireza sanaee