Como encontrar filhos de nós usando BeautifulSoup


114

Quero obter todas as <a>tags que são filhas de <li>:

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

Eu sei como encontrar um elemento com uma classe particular como este:

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

Mas não sei como encontrar todos <a>os filhos de, <li class=test>mas nenhum outro.

Como desejo selecionar:

<a>link1</a>

Respostas:


124

Tente isto

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

3
Ou, apenas para extrair a expressão que descreve o que queremos: soup.find('li', {'class': 'text'}).findChildren().
Karl Knechtel

3
mas como obter a tag frist <a> não depois de wards. algo comofind(li).find(a).firstChild()
tej.tan

Obrigado pelo kwarg "recursivo" :)
Swift

121

Há uma seção super pequena nos DOCs que mostra como localizar / localizar todos os filhos diretos .

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

No seu caso, como você deseja link1, que é o primeiro filho direto:

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

Se você quiser todos os filhos diretos:

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

12

Talvez você queira fazer

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

1
Acho que também encontrará <a> link2 </a>, mas não quero isso
tej.tan

1
Isso responde à questão de como selecionar <a>link1</a>no HTML fornecido na questão, mas irá FALHAR quando o primeiro <li class="test">não conter <a>elementos e houver outros lielementos com testclasse que contém <a>.
radzak de

11

tente isto:

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

outros lembretes:

O método find obtém apenas o primeiro elemento filho que ocorre. O método find_all obtém todos os elementos descendentes e são armazenados em uma lista.


2
O questionador não quer nenhuma das duas opções acima. Ele quer todos os links que são apenas filhos diretos.
Ahsan Roy

8

"Como descobrir todos os aque são filhos, <li class=test>mas nenhum outro?"

Dado o HTML abaixo (adicionei outro <a>para mostrar a diferença entre selecte select_one):

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

A solução é usar o combinador filho ( >) que é colocado entre dois seletores CSS:

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

Caso você queira encontrar apenas o primeiro filho:

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

Este é o que eu estava procurando. Eu estava usando o método errado. Esqueci> é um seletor CSS. Obrigado!
LFMekz

7

Ainda outro método - crie uma função de filtro que retorna Truepara todas as tags desejadas:

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

Em seguida, basta chamar find_allcom o argumento:

for a in soup(my_filter): # or soup.find_all(my_filter)
    print a
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.