Comment trouver des enfants de nœuds à l'aide de BeautifulSoup


115

Je veux obtenir toutes les <a>balises qui sont des enfants de <li>:

<div>
<li class="test">
    <a>link1</a>
    <ul> 
       <li>  
          <a>link2</a> 
       </li>
    </ul>
</li>
</div>

Je sais comment trouver un élément avec une classe particulière comme celle-ci:

soup.find("li", { "class" : "test" }) 

Mais je ne sais pas comment trouver tous ceux <a>qui sont enfants de <li class=test>mais pas d'autres.

Comme je veux sélectionner:

<a>link1</a>

Réponses:


124

Essaye ça

li = soup.find('li', {'class': 'text'})
children = li.findChildren("a" , recursive=False)
for child in children:
    print child

3
Ou, pour en extraire tout l'expression qui décrit ce que nous voulons: soup.find('li', {'class': 'text'}).findChildren().
Karl Knechtel

3
mais comment obtenir la première balise <a> seulement pas après les wards. quelque chose commefind(li).find(a).firstChild()
tej.tan

Merci pour le kwarg "récursif" :)
Swift

122

Il y a une très petite section dans les DOCs qui montre comment trouver / find_all enfants directs .

https://www.crummy.com/software/BeautifulSoup/bs4/doc/#the-recursive-argument

Dans votre cas, comme vous le souhaitez, link1 qui est le premier enfant direct:

# for only first direct child
soup.find("li", { "class" : "test" }).find("a", recursive=False)

Si vous voulez tous les enfants directs:

# for all direct children
soup.find("li", { "class" : "test" }).findAll("a", recursive=False)

12

Tu veux peut-être faire

soup.find("li", { "class" : "test" }).find('a')

1
Je pense que ça trouvera <a> link2 </a>aussi mais je ne veux pas ça
tej.tan

1
Cela répond à la question de savoir comment sélectionner <a>link1</a>dans le HTML donné dans la question, mais cela échouera lorsque le premier <li class="test">ne contiendra aucun <a>élément et qu'il y a d'autres liéléments avec la testclasse qui contient <a>.
radzak

11

essaye ça:

li = soup.find("li", { "class" : "test" })
children = li.find_all("a") # returns a list of all <a> children of li

autres rappels:

La méthode find obtient uniquement le premier élément enfant qui se produit. La méthode find_all récupère tous les éléments descendants et sont stockés dans une liste.


2
L'interlocuteur ne veut aucune des deux options ci-dessus. Il veut tous les liens qui ne sont que des enfants directs.
Ahsan Roy

9

"Comment trouver tous ceux aqui sont enfants <li class=test>mais pas d'autres?"

Compte tenu du HTML ci-dessous (j'en ai ajouté un autre <a>pour montrer la différence entre selectet select_one):

<div>
  <li class="test">
    <a>link1</a>
    <ul>
      <li>
        <a>link2</a>
      </li>
    </ul>
    <a>link3</a>
  </li>
</div>

La solution consiste à utiliser le combinateur enfant ( >) placé entre deux sélecteurs CSS:

>>> soup.select('li.test > a')
[<a>link1</a>, <a>link3</a>]

Au cas où vous souhaiteriez ne trouver que le premier enfant:

>>> soup.select_one('li.test > a')
<a>link1</a>

C'est celui que je cherchais. Je l'ai fourni à la mauvaise méthode. Forgot> est un sélecteur CSS. Merci!
LFMekz

7

Encore une autre méthode - créez une fonction de filtre qui renvoie Truepour toutes les balises souhaitées:

def my_filter(tag):
    return (tag.name == 'a' and
        tag.parent.name == 'li' and
        'test' in tag.parent['class'])

Ensuite, appelez simplement find_allavec l'argument:

for a in soup(my_filter): # or soup.find_all(my_filter)
    print a
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.