Cách tìm con của các nút bằng BeautifulSoup


115

Tôi muốn nhận tất cả các <a>thẻ là con của <li>:

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

Tôi biết cách tìm phần tử với lớp cụ thể như thế này:

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

Nhưng tôi không biết làm thế nào để tìm ra tất cả <a>những đứa trẻ là con của <li class=test>nó mà không phải của bất kỳ đứa nào khác.

Giống như tôi muốn chọn:

<a>link1</a>

Câu trả lời:


124

Thử cái này

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

3
Hoặc, để chỉ trích xuất các biểu hiện mô tả những gì chúng ta muốn: soup.find('li', {'class': 'text'}).findChildren().
— Karl Knechtel

3
nhưng làm thế nào để nhận được thẻ frist <a> không chỉ sau phường. một cái gì đó giống nhưfind(li).find(a).firstChild()
— tej.tan

Cảm ơn vì kwarg "đệ quy" :)
— Swift

122

Có một phần siêu nhỏ trong DOC cho thấy cách tìm / find_all con trực tiếp .

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

Trong trường hợp của bạn như bạn muốn link1 là con trực tiếp đầu tiên:

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

Nếu bạn muốn tất cả những người con trực hệ:

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

12

Có lẽ bạn muốn làm

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

1
tôi nghĩ rằng nó cũng sẽ tìm thấy <a> link2 </a>nhưng tôi không muốn điều đó
— tej.tan.

1
Điều này trả lời câu hỏi làm thế nào để chọn <a>link1</a>trong HTML được đưa ra trong câu hỏi, nhưng điều này sẽ KHÔNG PHẢI khi đầu tiên <li class="test">sẽ không chứa <a>phần tử và có các liphần tử khác có testlớp chứa <a>.
— radzak

11

thử cái này:

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

nhắc nhở khác:

Phương thức find chỉ nhận phần tử con xuất hiện đầu tiên. Phương thức find_all nhận tất cả các phần tử con và được lưu trữ trong một danh sách.


2
Người hỏi không muốn có tùy chọn nào trong hai tùy chọn trên. Anh ta muốn tất cả các liên kết chỉ là con trực tiếp.
— Ahsan Roy

9

"Làm thế nào để tìm thấy tất cả anhững người là con của họ <li class=test>mà không phải của bất kỳ người nào khác?"

Với HTML bên dưới (tôi đã thêm một HTML khác <a>để hiển thị sự khác biệt giữa selectvà select_one):

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

Giải pháp là sử dụng tổ hợp con ( >) được đặt giữa hai bộ chọn CSS:

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

Trong trường hợp bạn chỉ muốn tìm con đầu tiên:

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

Đây là một trong những tôi đã tìm kiếm. Tôi đã cung cấp nó sai phương pháp. Quên> là một bộ chọn CSS. Cảm ơn!
— LFMekz

7

Tuy nhiên, một phương pháp khác - tạo một hàm bộ lọc trả về Truecho tất cả các thẻ mong muốn:

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

Sau đó, chỉ cần gọi find_allvới đối số:

for a in soup(my_filter): # or soup.find_all(my_filter)
    print a
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.