Чтобы получить весь текст «между» двумя элементами, например, между двумя заголовками, нет другого способа, кроме этого:
- пройти весь
tree
(мы будем использовать .iterwalk()
потому что мы должны различать начало и конец элементов) - создать элемент данных для каждого встречаемого заголовка (назовем его
current_heading
) - собрать в список всех отдельныхтекстовые биты любого другого элемента, которые встречаются
- каждый раз, когда встречается новый заголовок, сохраните собранные данные и начните новый элемент данных
Каждый элемент в элементе ElementTree можетиметь .text
и .tail
:
<b>This will be the .text</b> and this will be the .tail
Мы должны собрать оба, иначе текст будет отсутствовать в выводе.
Следующее отслеживает, где мы находимся вДерево HTML использует стек, поэтому .head
и .tail
вложенных элементов собираются в правильном порядке.
collected_text = []
data = []
stack = []
current_heading = {
'title': '',
'text': []
}
html_headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
def normalize(strings):
return ''.join(strings)
for event, elem in ET.iterwalk(tree, events=('start', 'end')):
# when an element starts, collect its .text
if event == 'start':
stack.append(elem)
if elem.tag in html_headings:
# reset any collected text, b/c now we're starting to collect
# the heading's text. There might be nested elements in it.
collected_text = []
if elem.text:
collected_text.append(elem.text)
# ...and when it ends, collect its .tail
elif event == 'end' and elem == stack[-1]:
# headings mark the border between data items
if elem.tag in html_headings:
# normalize text in the previous data item
current_heading['text'] = normalize(current_heading['text'])
# start new data item
current_heading = {
'title': normalize(collected_text),
'text': []
}
data.append(current_heading)
# reset any collected text, b/c now we're starting to collect
# the text after the the heading
collected_text = []
if elem.tail:
collected_text.append(elem.tail)
current_heading['text'] = collected_text
stack.pop()
# normalize text in final data item
current_heading['text'] = normalize(current_heading['text'])
Когда я запускаю это для вашего примера HTML, я получаю этот вывод (в формате JSON):
[
{
"text" : "\n Some text with other tags.\n More text.\n More text[2].\n\n ",
"title" : "Title"
},
{
"text" : "\n Description.\n\n ",
"title" : "Title[2]"
},
{
"text" : "\n Description[1].\n Description[2].\n\n ***\n and so on...\n ***\n",
"title" : "Title[3]"
}
]
My * 103Функция 1 * очень проста и сохраняет все новые строки и другие пробелы, которые являются частью исходного кода HTML.Напишите более сложную функцию, если вы хотите более хороший результат.