beautifulsoup: получение текста (включая html-теги) между двумя разными тегами ( и )

#beautifulsoup

#beautifulsoup

Вопрос:

Я пытаюсь создать html-файл, структурированный следующим образом, используя beautifulsoup. По сути, каждый блок состоит из:

  • один <h2></h2>

  • один <h3></h3>

  • более одного <p></p>

Что-то вроде follow:

 <h2>January, 2020</h2>
<h3>facility</h3>
<p>text1-1</p>
<p>text1-2</p>

<h2>April, 2020</h2>
<h3>scientists</h3>
<p>text2-1</p>
<p>text2-2</p>

<h2>June, 2020</h2>
<h3>lawyers</h3>
<p>text3-1</p>

<h2>.....
  

Я хочу получить текст, включающий <p> теги между </h3> и следующим <h2> . Результат должен быть:

для строки #1:

 <p>text1-1</p>
<p>text1-2</p>
  

для строки #2:

 <p>text2-1</p>
<p>text2-2</p>
  

для строки #3:

 <p>text3-1</p>
  

Вот что я пробовал до сих пор:

 num_h2 = len(soup.find_all('h2'))

for i in range(0,num_h2):
    print('---------')
    print(i) 

    p_string = ''
    sibling = soup.find_all('h3')[i].find_next_sibling('p').getText()

    if sibling:
        p_string  = sibling
    else:
        break

    print(p_string)
  

Проблема с этим решением заключается в том, что оно показывает только содержимое первого <p> под каждым блоком. Я не знаю, как определить, сколько <p> их существует для создания цикла for . Кроме того, есть ли лучший способ сделать это, чем использовать find_next_silibing() ?

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

1. Уверен, что есть способ. Какие-либо попытки с вашей стороны?

2. @baduker спасибо. Я обновил свою попытку.

Ответ №1:

Возможно, селекторы css могут помочь:

 for s in soup.select('h3'):
    for ns in (s.fetchNextSiblings()):        
        if ns.name == "h2":
            break
        else:
            if ns.name == "p":
                print(ns)
  

Вывод:

 <p>text1-1</p>
<p>text1-2</p>
<p>text2-1</p>
<p>text2-2</p>
<p>text3-1</p>