Jak znaleźć elementy podrzędne węzłów za pomocą BeautifulSoup

115

Chcę uzyskać wszystkie <a>tagi, które są elementami podrzędnymi <li>:

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

Wiem, jak znaleźć element z taką klasą:

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

Ale nie wiem, jak znaleźć wszystkie <a>dzieci, <li class=test>ale nie inne.

Tak jak chcę wybrać:

<a>link1</a>
tej.tan
źródło

Odpowiedzi:

124

Spróbuj tego

li = soup.find('li', {'class': 'text'})
children = li.findChildren("a" , recursive=False)
for child in children:
    print child
cerberos
źródło
3
Albo po prostu wyodrębnić wyrażenie opisujące to, co chcemy: soup.find('li', {'class': 'text'}).findChildren().
Karl Knechtel
3
ale jak zdobyć pierwszy tag <a> tylko nie po totemach. coś w stylufind(li).find(a).firstChild()
tej.tan
Dzięki za "rekurencyjne" kwarg :)
Swift
122

W DOCs znajduje się bardzo mała sekcja, która pokazuje, jak znaleźć / find_all bezpośrednie dzieci.

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

W twoim przypadku, jak chcesz, link1, który jest pierwszym bezpośrednim dzieckiem:

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

Jeśli chcesz, aby wszystkie bezpośrednie dzieci:

# for all direct children
soup.find("li", { "class" : "test" }).findAll("a", recursive=False)
Strider
źródło
12

Być może chcesz to zrobić

soup.find("li", { "class" : "test" }).find('a')
Bemmu
źródło
1
Myślę, że to też znajdzie, <a> link2 </a>ale nie chcę tego
tej.tan
1
Odpowiada to na pytanie, jak wybrać <a>link1</a>w HTML podanym w pytaniu, ale to się nie powiedzie, gdy pierwszy nie <li class="test">będzie zawierał żadnych <a>elementów i są inne lielementy z testklasą, która zawiera <a>.
radzak
11

Spróbuj tego:

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

inne przypomnienia:

Metoda find pobiera tylko pierwszy występujący element potomny. Metoda find_all pobiera wszystkie elementy podrzędne i są przechowywane na liście.

kiiru
źródło
2
Pytający nie chce żadnej z dwóch powyższych opcji. Chce wszystkich linków, które są tylko bezpośrednim dzieckiem.
Ahsan Roy
9

"Jak znaleźć wszystkie adzieci, <li class=test>ale innych nie?"

Biorąc pod uwagę poniższy kod HTML (dodałem kolejny, <a>aby pokazać różnicę między selecti select_one):

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

Rozwiązaniem jest użycie kombinatora potomnego ( >), który jest umieszczony między dwoma selektorami CSS:

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

Jeśli chcesz znaleźć tylko pierwsze dziecko:

>>> soup.select_one('li.test > a')
<a>link1</a>
radzak
źródło
To jest ten, którego szukałem. Dostarczałem go złą metodą. Forgot> to selektor CSS. Dzięki!
LFMekz
7

Jeszcze inna metoda - utwórz funkcję filtrującą, która zwraca Truedla wszystkich pożądanych tagów:

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

Następnie po prostu zadzwoń find_allz argumentem:

for a in soup(my_filter): # or soup.find_all(my_filter)
    print a
Dedek Mraz
źródło