from html.parser import HTMLParser
bufer = '''<p>
<div>hi!
</p>'''
class MyHTMLParser(HTMLParser):
def __init__(self):
super().__init__()
self.open_tags = []
def handle_starttag(self, tag, attrs):
print("Start tag:", tag)
self.open_tags.append((tag, self.getpos()))
def handle_endtag(self, tag):
print("End tag :", tag)
unclosed_tags = []
# ищем, когда был открыт нужный тег
for i in range(len(self.open_tags)-1, -1, -1):
if self.open_tags[i][0] != tag:
unclosed_tags.append(self.open_tags[i])
else:
break
if len(unclosed_tags) == len(self.open_tags): # тег никогда и не был открыт
print(f"Closing tag {tag} has no matching opening tag!")
elif unclosed_tags: # тег был открыт, но он не последний
print("Following tags are not closed properly:\n", '\n'.join(f' {t} at line {line} pos {col+1}' for t,(line, col) in unclosed_tags))
del self.open_tags[-len(unclosed_tags)+1:] # сбрасываем незакрытые теги
else: # тег был открыт, и он последний - всё в порядке
del self.open_tags[-1]
def close(self):
super().close()
print('Processing done')
parser = MyHTMLParser()
parser.feed(bufer)
parser.close()
Вместо вывода текста можешь сразу выкидывать исключения, или накапливать сведения об ошибках, чтобы выкинуть одно исключение с полной информацией в методе close().