#python #html #beautifulsoup
#python #HTML #beautifulsoup
Вопрос:
Я хочу получить все <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>
Ответ №1:
Попробуйте это
li = soup.find('li', {'class': 'text'})
children = li.findChildren("a" , recursive=False)
for child in children:
print(child)
Комментарии:
1. Или, чтобы просто извлечь выражение, которое описывает то, что мы хотим:
soup.find('li', {'class': 'text'}).findChildren()
.2. но как получить только первый тег <a>, а не после подопечных. что-то вроде
find(li).find(a).firstChild()
3. Спасибо за «рекурсивный» kwarg 🙂
4. с сайта bs4: «findChildren, findChild: эти методы остались от API Beautiful Soup 2. Они устарели с 2006 года и их вообще не следует использовать: »
Ответ №2:
В документах есть очень маленький раздел, который показывает, как найти / find_all прямых дочерних элементов.
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)
Ответ №3:
Возможно, вы хотите сделать
soup.find("li", { "class" : "test" }).find('a')
Комментарии:
1. я думаю, что он тоже найдет
<a> link2 </a>
, но я этого не хочу2. Это отвечает на вопрос, как выбрать
<a>link1</a>
в HTML, приведенном в вопросе, но это приведет к СБОЮ, когда первый<li class="test">
не будет содержать<a>
элементов, а есть другиеli
элементы сtest
классом, который содержит<a>
.3. Это не отвечает на вопрос, но это было то, что я искал.
Ответ №4:
попробуйте это:
li = soup.find("li", { "class" : "test" })
children = li.find_all("a") # returns a list of all <a> children of li
другие напоминания:
Метод find получает только первый встречающийся дочерний элемент. Метод find_all получает все элементы-потомки и сохраняется в виде списка.
Комментарии:
1. Спрашивающий не хочет ни одного из двух вариантов выше. Ему нужны все ссылки, которые являются только прямыми дочерними узлами.
Ответ №5:
«Как найти все, 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>
Комментарии:
1. Это то, что я искал. Я предоставлял его неправильному методу. Забыл> это CSS-селектор. Спасибо!
2. Как бы вы выбрали только первый <a>, если бы их было несколько в li.test?
Ответ №6:
Еще один метод — создайте функцию фильтра, которая возвращает 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
Ответ №7:
Только что наткнулся на этот ответ и проверил документацию, чтобы увидеть, что soup.findChildren
он устарел (BS 4.9). Вместо этого вы можете использовать soup.children
, который учитывает только прямых дочерних элементов элемента, а не его потомков.
li = soup.find('li', {'class': 'text'})
for child in li.children:
print(child)
Документация: https://www.crummy.com/software/BeautifulSoup/bs4/doc/#contents-and-children