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 selectselect_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 cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.