Як знайти дітей вузлів за допомогою BeautifulSoup


115

Я хочу отримати всі <a>теги, які є дітьми <li>:

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

Я знаю, як знайти елемент із таким класом, як це:

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

Але я не знаю, як знайти всіх <a>дітей, <li class=test>але не будь-яких інших.

Я хочу вибрати:

<a>link1</a>

Відповіді:


124

Спробуйте це

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

3
Або просто витягти вираз , яке описує те , що ми хочемо: soup.find('li', {'class': 'text'}).findChildren().
Карл Кнечтел

3
але як отримати тегу <a> тег лише після підопічних. щось на кшталтfind(li).find(a).firstChild()
tej.tan

Дякую за "рекурсивний" kwarg :)
Швидкий

121

У DOC є дуже невеликий розділ, який показує, як знайти / знайти_всіх прямих дітей.

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

У вашому випадку, як ви хочете link1, яка є першою безпосередньо дитиною:

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

Якщо ви хочете, щоб усі прямі діти:

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

12

Можливо, ти хочеш це зробити

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

1
Я думаю, що це також знайдеться <a> link2 </a>, але я цього не хочу
tej.tan

1
Це дає відповідь на питання, як вибрати <a>link1</a>в HTML, наведеному у запитанні, але це ЗНАЄТЬСЯ, коли перший не <li class="test">буде містити <a>елементів, а є інші liелементи з testкласом, який містить <a>.
radzak

11

спробуйте це:

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

інші нагадування:

Метод знаходження отримує лише перший дочірній елемент. Метод find_all отримує всі нащадкові елементи і зберігаються в списку.


2
Запитуючий не хоче жодного з двох варіантів, описаних вище. Він хоче, щоб усі зв'язки, які є лише прямим дитиною.
Ахсан Рой

8

"Як знайти всіх aдітей, <li class=test>але не будь-яких інших?"

Враховуючи HTML нижче (я додав ще один, <a>щоб показати різницю між selectі select_one):

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

Рішення полягає у використанні дочірнього комбінатора ( >), який розміщується між двома селекторами CSS:

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

Якщо ви хочете знайти лише першу дитину:

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

Це той, кого я шукав. Я постачав це неправильним методом. Забули> - це селектор CSS. Дякую!
LFMekz

7

Ще один метод - створити функцію фільтра, яка повертає Trueвсі бажані теги:

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

Тоді просто зателефонуйте find_allз аргументом:

for a in soup(my_filter): # or soup.find_all(my_filter)
    print a
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.