So finden Sie untergeordnete Elemente von Knoten mithilfe von BeautifulSoup

114

Ich möchte alle <a>Tags erhalten, die Kinder von <li>:

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

Ich weiß, wie man ein Element mit einer bestimmten Klasse wie dieser findet:

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

Aber ich weiß nicht, wie ich alle finden soll, von <a>denen Kinder sind, <li class=test>aber keine anderen.

Wie ich auswählen möchte:

<a>link1</a>
tej.tan
quelle

Antworten:

124

Versuche dies

li = soup.find('li', {'class': 'text'})
children = li.findChildren("a" , recursive=False)
for child in children:
    print child
cerberos
quelle
3
Oder um einfach den Ausdruck zu extrahieren, der beschreibt, was wir wollen : soup.find('li', {'class': 'text'}).findChildren().
Karl Knechtel
3
aber wie man frist <a> tag nur nicht nach Stationen bekommt. so etwas wiefind(li).find(a).firstChild()
tej.tan
Danke für das "rekursive" kwarg :)
Swift
121

Es gibt einen super kleinen Abschnitt in den DOCs, der zeigt, wie man / find_all direkte Kinder findet.

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

In Ihrem Fall, wie Sie möchten link1, das erste direkte Kind ist:

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

Wenn Sie alle direkten Kinder wollen:

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

Vielleicht willst du das tun

soup.find("li", { "class" : "test" }).find('a')
Bemmu
quelle
1
Ich denke, es wird auch finden, <a> link2 </a>aber ich will das nicht
tej.tan
1
Dies beantwortet die Frage, wie <a>link1</a>in dem in der Frage angegebenen HTML-Code ausgewählt werden soll. Dies schlägt jedoch fehl, wenn der erste <li class="test">keine <a>Elemente enthält und andere liElemente mit einer testKlasse enthalten sind <a>.
Radzak
11

Versuche dies:

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

andere Erinnerungen:

Die find-Methode ruft nur das erste vorkommende untergeordnete Element ab. Die find_all-Methode ruft alle untergeordneten Elemente ab und wird in einer Liste gespeichert.

Kiiru
quelle
2
Der Fragesteller möchte keine der beiden oben genannten Optionen. Er will alle Links, die nur direktes Kind sind.
Ahsan Roy
8

"Wie finde ich alle, von adenen Kinder sind, <li class=test>aber keine anderen?"

Angesichts des folgenden HTML-Codes (ich habe einen weiteren hinzugefügt <a>, um den Unterschied zwischen selectund zu zeigen select_one):

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

Die Lösung besteht darin, den untergeordneten Kombinator ( >) zu verwenden, der zwischen zwei CSS-Selektoren platziert wird:

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

Falls Sie nur das erste Kind finden möchten:

>>> soup.select_one('li.test > a')
<a>link1</a>
Radzak
quelle
Dies ist der, den ich gesucht habe. Ich habe es der falschen Methode geliefert. Vergessen> ist ein CSS-Selektor. Vielen Dank!
LFMekz
7

Noch eine andere Methode: Erstellen Sie eine Filterfunktion, die Truefür alle gewünschten Tags zurückgibt :

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

Dann rufen Sie einfach find_allmit dem Argument an:

for a in soup(my_filter): # or soup.find_all(my_filter)
    print a
Dedek Mraz
quelle