Bagaimana menemukan anak node menggunakan BeautifulSoup

115

Saya ingin mendapatkan semua <a>tag yang merupakan anak dari <li>:

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

Saya tahu cara menemukan elemen dengan kelas tertentu seperti ini:

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

Tetapi saya tidak tahu bagaimana menemukan semua <a>yang merupakan anak-anak <li class=test>tetapi tidak yang lain.

Seperti saya ingin memilih:

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

Jawaban:

124

Coba ini

li = soup.find('li', {'class': 'text'})
children = li.findChildren("a" , recursive=False)
for child in children:
    print child
cerberos
sumber
3
Atau, hanya mengekstrak ekspresi yang menggambarkan apa yang kita inginkan: soup.find('li', {'class': 'text'}).findChildren().
Karl Knechtel
3
tapi bagaimana cara mendapatkan tag <a> pertama bukan setelah lingkungan. sesuatu sepertifind(li).find(a).firstChild()
tej.tan
Terima kasih atas kwarg "rekursif" :)
Swift
122

Ada bagian super kecil di DOC yang menunjukkan cara menemukan / find_all mengarahkan anak-anak.

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

Dalam kasus Anda karena Anda menginginkan link1 yang merupakan anak langsung pertama:

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

Jika Anda ingin semua anak langsung:

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

Mungkin Anda ingin melakukannya

soup.find("li", { "class" : "test" }).find('a')
Bemmu
sumber
1
saya pikir itu akan menemukan <a> link2 </a>juga tetapi saya tidak menginginkannya
tej.tan
1
Ini menjawab pertanyaan bagaimana memilih <a>link1</a>dalam HTML yang diberikan dalam pertanyaan, tetapi ini akan GAGAL ketika yang pertama tidak <li class="test">akan berisi <a>elemen dan ada lielemen lain dengan testkelas yang berisi <a>.
radzak
11

coba ini:

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

pengingat lainnya:

Metode find hanya mendapatkan elemen turunan pertama yang muncul. Metode find_all mendapatkan semua elemen turunan dan disimpan dalam daftar.

kiiru
sumber
2
Penanya tidak menginginkan satupun dari dua pilihan di atas. Dia ingin semua link yang hanya anak langsung.
Ahsan Roy
9

"Bagaimana menemukan semua ayang merupakan anak-anak <li class=test>tetapi tidak yang lain?"

Diberikan HTML di bawah ini (saya menambahkan yang lain <a>untuk menunjukkan perbedaan antara selectdan select_one):

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

Solusinya adalah dengan menggunakan kombinator anak ( >) yang ditempatkan di antara dua pemilih CSS:

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

Jika Anda hanya ingin menemukan anak pertama:

>>> soup.select_one('li.test > a')
<a>link1</a>
radzak
sumber
Ini yang saya cari. Saya memasoknya dengan metode yang salah. Lupa> adalah pemilih CSS. Terima kasih!
LFMekz
7

Metode lain - buat fungsi filter yang mengembalikan Truesemua tag yang diinginkan:

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

Kemudian panggil saja find_alldengan argumen:

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