Как прокомментировал Ивар, парсер HTML - действительно единственный способ правильно справиться с этим классом проблем:
from html.parser import HTMLParser
class MyHTMLParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.indent = -1
def handle_starttag(self, tag, attrs):
self.indent += 1
print(2 * self.indent * ' ', sep='', end='')
print(f'<{tag}', sep='', end='')
for attr in attrs:
print(f' {attr[0]}="{attr[1]}"', sep='', end='')
print('>', sep='')
def handle_endtag(self, tag):
print(2 * self.indent * ' ', sep='', end='')
print(f'</{tag}>')
self.indent -= 1
parser = MyHTMLParser()
parser.feed("""<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Heading!</h1>
<p style="font-weight: bold; color: red;">
Some text
<BR/>
Some more text
</p>
<ol>
<li>Item 1</li>
<li>Item 2</li>
</ol>
</body>
</html>
""")
Отпечатки:
<html>
<head>
<title>
</title>
</head>
<body>
<h1>
</h1>
<p style="font-weight: bold; color: red;">
<br>
</br>
</p>
<ol>
<li>
</li>
<li>
</li>
</ol>
</body>
</html>
См. Python Демо
Обновление
Если HTML не слишком большой файл, имеет смысл прочитать весь файл в памяти и передать парсеру таким образом:
parser = MyHTMLParser()
with open('test.html') as f:
html = f.read()
parser.feed(html)
Если входные данные находятся в очень большом файле, может иметь смысл «кормить» парсер построчно или кусками, а не пытаться прочитать все файл в память:
Строка за строкой:
parser = MyHTMLParser()
with open('test.html') as f:
for line in f:
parser.feed(line)
Или даже более эффективно:
Чтение в блоках 32K:
CHUNK_SIZE = 32 * 1024
parser = MyHTMLParser()
with open('test.html') as f:
while True:
chunk = f.read(CHUNK_SIZE)
if chunk == '':
break
parser.feed(chunk)
Вы, конечно, можете выбрать еще больший размер куска.