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à?
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>
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
avec votre propre soupe objet:
soup.p.next_sibling.strip()
- vous saisissez le
directement avec
soup.p
*(cela dépend du fait que c'est le premierdans l'arbre de parse)
- puis utilisez
next_sibling
sur le tag de l'objet quesoup.p
retourne puisque le texte désiré est imbriqué au même niveau de l'arbre d'analyse que le .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
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.
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>
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..