Используя BeautifulSoup, можно ли перейти к родительскому тегу при использовании функции поиска текста?

#python #beautifulsoup

#python #beautifulsoup

Вопрос:

Можно ли перемещаться из текущей позиции в DOM вверх и вниз, когда общим идентификатором является только текст?

 <div>changing text</div>
    <div>fixed text</div>
  

Как получить текст changing text при поиске fixed text и переходе к родительскому div?

Что я пробовал:

 x = soup.body.findAll(text=re.compile('fixed text')).parent

AttributeError: 'ResultSet' object has no attribute 'parent'
  

Комментарии:

1. Что произошло с вашей попыткой?

2. Я получаю сообщение об ошибке: AttributeError: у объекта ‘ResultSet’ нет атрибута ‘parent’ …. извините, я добавлю его к вопросу

3. findAll возвращает ResultSet — список элементов. Вы хотите выполнить операцию с элементами внутри результирующего набора.

4. @BitByBit проверьте мой отредактированный ответ

5. @ TalesPadua Это не работает, потому что, даже если они все еще только братья и сестры, вам все равно придется сначала перейти к родителям. Я не знаю почему!

Ответ №1:

Эта программа может делать то, что вы хотите:

 from bs4 import BeautifulSoup
import re

html = '<body><div>changing text</div><div>fixed text</div><body>'

soup = BeautifulSoup(html)

x = soup.body.findAll(text=re.compile('fixed text'))[0].parent.previous_sibling

assert x.text == 'changing text'
  

Комментарии:

1. Мне нравится, но, учитывая это find_all , понимание списка может быть в порядке divs = [elem.previous_sibling for elem in soup.body.findAll(text=re.compile('fixed text'))]

2. Это работает, но я не совсем понимаю. Как упоминал Tales, на самом деле это братья и сестры, так почему мы привлекаем сюда родителей?

3. @BitByBit — это не должно работать, если они являются братьями и сестрами. Но у нас недостаточно вашего документа, чтобы разобраться в этом. Я опубликовал пример для составления списка divs … это работает?

4. .parent требуется, потому findAll что возвращает строковый узел, а не <div> узел. Если вы хотите findAll вернуть <div> узел, попробуйте: x = soup.body.findAll('div', text=re.compile('fixed text'))[0].previous_sibling

5. @tdelaney Вы были близки, Роб прав. divs = [elem.parent.previous_sibling for elem in soup.body.findAll(text=re.compile('fixed text'))]

Ответ №2:

Ошибка, с которой вы сталкиваетесь, связана с вызовом parent результирующего набора, списка результатов. Если вам нужно получить несколько результатов, попробуйте:

 x = soup.body.find_all(text=re.compile('fixed text'))
for i in x:
    previous_div = i.previous_sibling
  

Если вы не хотите находить несколько результатов, просто измените find_all на find:

 x = soup.body.find(text=re.compile('fixed text')).previous_sibling
  

Обратите внимание, что я заменяю parent на previous_sibling, поскольку divs находятся на одном уровне

Комментарии:

1. Вы изменили это, чтобы найти только один элемент. OP использует findAll и, предположительно, хочет выполнить обработку на нескольких узлах.

2. Да, но ошибка, с которой сталкивается OP, связана с использованием parent в результирующем наборе. Я отредактирую, чтобы уточнить