Красивый суп - Как найти теги после определенного элемента в HTML? - PullRequest
0 голосов
/ 02 ноября 2019

Мне нужно найти теги после определенного элемента на веб-сайте. Итак, есть ли способ пропустить объекты тега до этого конкретного, а затем найти подходящие для данного критерия? Мне нужно все p с классом XYZ после div с классом ABC.

response = requests.get(url).text
soup = BeautifulSoup(response)
items = soup.find_all('p', {'class': 'MessageTextSize  js-message-text message-text'})  # only return the ones after the div with class of "Text 2"

Редактировать: Вы можете увидеть пример кода блока ниже, который является частьюresponse. Цель состоит в том, чтобы найти два последних абзаца (Text 3 & Text 4), несмотря на то, что у первого (Text 1) также есть тот же p class с ними. Итак, мне нужно искать параметр функции find_all после Text 2 (класс MessageTextSize js-message-text message-text).

<div class="js-message-text-container">
    <p class="MessageTextSize  js-message-text message-text" data-aria-label-part="0">Text 1</p>
</div>


<div class="js-message-text-container">
    <p class="MessageTextSize MessageTextSize--jumbo js-message-text message-text" data-aria-label-part="0">Text 2</p>
</div>


<div class="js-message-text-container">
    <p class="MessageTextSize  js-message-text message-text" data-aria-label-part="0">Text 3</p>
</div>

<div class="js-message-text-container">
    <p class="MessageTextSize  js-message-text message-text" data-aria-label-part="0">Text 4</p>
</div>

ps bs4 версия - 4.8.1, которая является последней версией.

Ответы [ 2 ]

0 голосов
/ 03 ноября 2019

Вы всегда можете использовать пользовательскую функцию (или лямбда-выражение) внутри find_all. Следующее не требует пояснений (IMO).

result = soup.find_all(
    lambda x: x.name == 'p' and
    'XYZ' in x.get('class', '') and
    x.find_previous('div', class_='ABC')
)

Пример

from bs4 import BeautifulSoup
html = """
<p class="XYZ">Text 1</p>
<p class="XYZ">Text 2</p>
<div class="ABC"></div>
<p class="XYZ">Text 3</p>
<p class="XYZ">Text 4</p>
"""
soup = BeautifulSoup(html, 'html.parser')
result = soup.find_all(
    lambda x: x.name == 'p' and
    'XYZ' in x.get('class', '') and
    x.find_previous('div', class_='ABC')
)
print(result)

Вывод

[<p class="XYZ">Text 3</p>, <p class="XYZ">Text 4</p>]

РЕДАКТИРОВАНИЕ

  • MessageTextSize js-message-text message-text представляет три класса, а не один.

  • x.get('class', '') возвращает список классов -

    ['MessageTextSize', 'js-message-text', 'message-text']

  • В вашем конкретном случае вы должны нацелить тег p, а не div, если я правильно понял.

Итак, вы должны использовать

result = soup.find_all( 
    lambda x: x.name == 'p' and 
    'MessageTextSize js-message-text message-text' in ' '.join(x.get('class', ''))
    and x.find_previous('p', class_='MessageTextSize MessageTextSize--jumbo js-message-text message-text') 
)

Ссылка:

0 голосов
/ 03 ноября 2019

Если я правильно вас понимаю, это должно работать:

item = soup.select_one('p[class*="MessageTextSize--jumbo"]')
sibs = item.parent.find_next_siblings()
for sib in sibs:
   print(sib.text.strip())

Вывод:

Текст 3

Текст 4

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...