Python BeautifulSoup extrait du texte entre les éléments

j'essaie d'extraire "ceci est mon texte" du 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 j'obtiens tout le texte entre toutes les étiquettes imbriquées plus le commentaire.

est-ce que quelqu'un peut m'aider à sortir "ceci est mon texte" de là?

26
demandé sur Jon Clements 2013-05-30 15:54:36

7 réponses

apprenez plus sur la façon de naviguer à travers l'arbre de parse dans BeautifulSoup. Arbre d'analyse a tags et NavigableStrings (car C'EST UN TEXTE). 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 déplacer vers le bas de l'arbre d'analyse, vous avez contents et string.

  • table des matières est une liste ordonnée de la balise et des objets NavigableString contenu dans un élément de page

  • si une étiquette n'a qu'un enfant et ce nœud enfant est une chaîne, le nœud enfant est disponible en tag.chaîne, ainsi que balise.sommaire[0]

Pour le haut, c'est-à-dire que vous pouvez les obtenir

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

pour plusieurs noeuds enfants, vous pouvez avoir par exemple

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 que vous souhaitez.

vous pouvez aussi itérer sur une étiquette, ceci est 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>
27
répondu octoback 2013-05-30 13:13:51

Vous pouvez utiliser .contents:

>>> for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
...     print hit.contents[6].strip()
... 
THIS IS MY TEXT
12
répondu TerryA 2013-05-30 12:33:11

Utiliser .children au lieu de:

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 un pas de 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
10
répondu Martijn Pieters 2013-05-30 12:36:10

avec votre propre soupe objet:

soup.p.next_sibling.strip()
  1. vous saisissez le

    directement avec soup.p *(cela dépend du fait que c'est le premier

    dans l'arbre de parse)

  2. puis utilisez next_sibling sur le tag de l'objet que soup.p retourne puisque le texte désiré est imbriqué au même niveau de l'arbre d'analyse que le

  3. .strip() est juste une méthode de str de Python pour supprimer les blancs menant et traînant

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

dans l'interpréteur 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
9
répondu Gregory Kremler 2015-10-29 14:40:24

brève réponse: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 mentionnez dans votre commentaire à la réponse D'Haidro que le texte que vous voulez n'est pas toujours au même endroit. Trouver un sens dans lequel il est au même endroit par rapport à un élément quelconque. Ensuite, trouvez comment faire BeautifulSoup naviguer dans l'arbre des parses en suivant ce chemin invariant.

par exemple, dans le HTML que vous fournissez dans la chaîne cible apparaît Immédiatement après le premier élément de paragraphe, et ce paragraphe n'est pas vide. Depuis findAll('p') trouverez paragraphe les éléments soup.find('p')[0] sera le premier élément du paragraphe.

Vous pouvez dans ce cas utiliser soup.find('p') mais soup.findAll('p')[n] est plus général puisque peut-être votre scénario réel a besoin du 5ème paragraphe ou quelque chose comme ça.

next attribut field sera le prochain élément analysé dans l'arbre, y compris les enfants. Donc soup.findAll('p')[0].next contient le texte de ce paragraphe, et soup.findAll('p')[0].next.next retournera votre cible dans le HTML fourni.

6
répondu Bennett Brown 2013-05-31 03:46:28

BeautifulSoup documentation fournit un exemple de 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:

Supprimer Des Éléments

une Fois que vous avez une référence à un élément, vous pouvez déchirer de l' arbre avec la méthode d'extraction. Ce code supprime tous les commentaires à partir 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>
0
répondu alireza sanaee 2016-09-10 16:56:12
soup = BeautifulSoup(html)
for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
  hit = hit.text.strip()
  print hit

ceci s'affichera: ceci est mon texte Essayez ceci..

0
répondu Naiswita 2018-01-24 10:17:22