html.parser — Простой синтаксический анализатор HTML и XHTML

Исходный код: Lib/html/parser.py


Этот модуль определяет класс HTMLParser, который служит основой для синтаксического анализа текстовых файлов, отформатированных в HTML (HyperText Markup Language) и XHTML.

class html.parser.HTMLParser(*, convert_charrefs=True)

Создайте экземпляр синтаксического анализатора, способный анализировать недопустимую разметку.

Если значение convert_charrefs равно True (по умолчанию), все символьные ссылки (за исключением ссылок в элементах script/style) автоматически преобразуются в соответствующие символы Юникода.

Экземпляру HTMLParser передаются HTML-данные, и он вызывает методы обработчика при обнаружении начальных и конечных тегов, текста, комментариев и других элементов разметки. Пользователь должен создать подкласс HTMLParser и переопределить его методы для реализации желаемого поведения.

Этот синтаксический анализатор не проверяет соответствие конечных тегов начальным тегам и не вызывает обработчик конечных тегов для элементов, которые закрываются неявно путем закрытия внешнего элемента.

Изменено в версии 3.4: convert_charrefs добавлен аргумент ключевого слова.

Изменено в версии 3.5: Значением по умолчанию для аргумента convert_charrefs теперь является True.

Пример приложения для синтаксического анализа HTML

В качестве базового примера ниже приведен простой синтаксический анализатор HTML, который использует класс HTMLParser для вывода начальных тегов, конечных тегов и данных по мере их появления:

from html.parser import HTMLParser

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Encountered a start tag:", tag)

    def handle_endtag(self, tag):
        print("Encountered an end tag :", tag)

    def handle_data(self, data):
        print("Encountered some data  :", data)

parser = MyHTMLParser()
parser.feed('<html><head><title>Test</title></head>'
            '<body><h1>Parse me!</h1></body></html>')

Тогда результатом будет:

Encountered a start tag: html
Encountered a start tag: head
Encountered a start tag: title
Encountered some data  : Test
Encountered an end tag : title
Encountered an end tag : head
Encountered a start tag: body
Encountered a start tag: h1
Encountered some data  : Parse me!
Encountered an end tag : h1
Encountered an end tag : body
Encountered an end tag : html

HTMLParser Методы

HTMLParser экземпляры имеют следующие методы:

HTMLParser.feed(data)

Передайте некоторый текст в синтаксический анализатор. Он обрабатывается, поскольку состоит из полных элементов; неполные данные сохраняются в буфере до тех пор, пока не будут загружены дополнительные данные или не будет вызван close(). данные должны быть str.

HTMLParser.close()

Принудительная обработка всех буферизованных данных, как если бы за ними следовала отметка о конце файла. Этот метод может быть переопределен производным классом для определения дополнительной обработки в конце ввода, но переопределенная версия всегда должна вызывать метод базового класса HTMLParser close().

HTMLParser.reset()

Перезагрузите экземпляр. Все необработанные данные будут удалены. Это вызывается неявно во время создания экземпляра.

HTMLParser.getpos()

Возвращает текущий номер строки и смещение.

HTMLParser.get_starttag_text()

Возвращает текст последнего открытого начального тега. Обычно это не требуется для структурированной обработки, но может быть полезно при работе с HTML «в развернутом виде» или для повторной генерации входных данных с минимальными изменениями (можно сохранить пробелы между атрибутами и т.д.).

Следующие методы вызываются при обнаружении данных или элементов разметки, которые должны быть переопределены в подклассе. Реализации базового класса ничего не делают (за исключением handle_startendtag()):

HTMLParser.handle_starttag(tag, attrs)

Этот метод вызывается для обработки начального тега элемента (например, <div id="main">).

Аргумент tag - это имя тега, преобразованное в нижний регистр. Аргумент attrs представляет собой список пар (name, value), содержащих атрибуты, которые находятся внутри квадратных скобок тега <>. Имя будет переведено в нижний регистр, кавычки в значении будут удалены, а ссылки на символы и сущности заменены.

Например, для тега <A HREF="https://www.cwi.nl/"> этот метод будет вызываться как handle_starttag('a', [('href', 'https://www.cwi.nl/')]).

Все ссылки на объекты из html.entities заменяются в значениях атрибутов.

HTMLParser.handle_endtag(tag)

Этот метод вызывается для обработки конечного тега элемента (например, </div>).

Аргумент tag - это имя тега, преобразованное в нижний регистр.

HTMLParser.handle_startendtag(tag, attrs)

Аналогично handle_starttag(), но вызывается, когда синтаксический анализатор обнаруживает пустой тег в стиле XHTML (<img ... />). Этот метод может быть переопределен подклассами, которым требуется эта конкретная лексическая информация; реализация по умолчанию просто вызывает handle_starttag() и handle_endtag().

HTMLParser.handle_data(data)

Этот метод вызывается для обработки произвольных данных (например, текстовых узлов и содержимого <script>...</script> и <style>...</style>).

HTMLParser.handle_entityref(name)

Этот метод вызывается для обработки именованной символьной ссылки вида &name; (например, &gt;), где name - это общая ссылка на объект (например, 'gt'). Этот метод никогда не вызывается, если значение convert_charrefs равно True.

HTMLParser.handle_charref(name)

Этот метод вызывается для обработки десятичных и шестнадцатеричных ссылок на числовые символы в виде &#NNN; и &#xNNN;. Например, десятичный эквивалент для &gt; равен &#62;, тогда как шестнадцатеричный - &#x3E;; в этом случае метод получит '62' или 'x3E'. Этот метод никогда не вызывается, если значение convert_charrefs равно True.

HTMLParser.handle_comment(data)

Этот метод вызывается при обнаружении комментария (например, <!--comment-->).

Например, комментарий <!-- comment --> приведет к вызову этого метода с аргументом ' comment '.

Содержимое условных комментариев Internet Explorer (презервативы) также будет отправлено этому методу, поэтому для <!--[if IE 9]>IE9-specific content<![endif]--> этот метод получит '[if IE 9]>IE9-specific content<![endif]'.

HTMLParser.handle_decl(decl)

Этот метод вызывается для обработки объявления HTML doctype (например, <!DOCTYPE html>).

Параметр decl будет содержать все содержимое объявления внутри разметки <!...> (например, 'DOCTYPE html').

HTMLParser.handle_pi(data)

Метод, вызываемый при обнаружении инструкции по обработке. Параметр data будет содержать всю инструкцию по обработке. Например, для инструкции по обработке <?proc color='red'> этот метод будет вызываться как handle_pi("proc color='red'"). Он предназначен для переопределения производным классом; реализация базового класса ничего не делает.

Примечание

Класс HTMLParser использует синтаксические правила SGML для обработки инструкций. Команда обработки XHTML, использующая завершающий '?', приведет к включению '?' в data.

HTMLParser.unknown_decl(data)

Этот метод вызывается, когда синтаксический анализатор считывает нераспознанное объявление.

Параметр data будет содержать все содержимое объявления внутри разметки <![...]>. Иногда бывает полезно переопределить его производным классом. Реализация базового класса ничего не делает.

Примеры

Следующий класс реализует синтаксический анализатор, который будет использоваться для иллюстрации дополнительных примеров:

from html.parser import HTMLParser
from html.entities import name2codepoint

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Start tag:", tag)
        for attr in attrs:
            print("     attr:", attr)

    def handle_endtag(self, tag):
        print("End tag  :", tag)

    def handle_data(self, data):
        print("Data     :", data)

    def handle_comment(self, data):
        print("Comment  :", data)

    def handle_entityref(self, name):
        c = chr(name2codepoint[name])
        print("Named ent:", c)

    def handle_charref(self, name):
        if name.startswith('x'):
            c = chr(int(name[1:], 16))
        else:
            c = chr(int(name))
        print("Num ent  :", c)

    def handle_decl(self, data):
        print("Decl     :", data)

parser = MyHTMLParser()

Синтаксический анализ типа документа:

>>> parser.feed('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" '
...             '"http://www.w3.org/TR/html4/strict.dtd">')
Decl     : DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"

Разбор элемента с несколькими атрибутами и заголовком:

>>> parser.feed('<img src="python-logo.png" alt="The Python logo">')
Start tag: img
     attr: ('src', 'python-logo.png')
     attr: ('alt', 'The Python logo')
>>>
>>> parser.feed('<h1>Python</h1>')
Start tag: h1
Data     : Python
End tag  : h1

Содержимое элементов script и style возвращается как есть, без дальнейшего анализа:

>>> parser.feed('<style type="text/css">#python { color: green }</style>')
Start tag: style
     attr: ('type', 'text/css')
Data     : #python { color: green }
End tag  : style

>>> parser.feed('<script type="text/javascript">'
...             'alert("<strong>hello!</strong>");</script>')
Start tag: script
     attr: ('type', 'text/javascript')
Data     : alert("<strong>hello!</strong>");
End tag  : script

Разбор комментариев:

>>> parser.feed('<!-- a comment -->'
...             '<!--[if IE 9]>IE-specific content<![endif]-->')
Comment  :  a comment
Comment  : [if IE 9]>IE-specific content<![endif]

Анализ именованных и числовых ссылок на символы и преобразование их в правильный символ (примечание: все эти 3 ссылки эквивалентны '>'):

>>> parser.feed('&gt;&#62;&#x3E;')
Named ent: >
Num ent  : >
Num ent  : >

Передача неполных фрагментов в feed() работает, но handle_data() может вызываться более одного раза (если только для параметра convert_charrefs не задано значение True):

>>> for chunk in ['<sp', 'an>buff', 'ered ', 'text</s', 'pan>']:
...     parser.feed(chunk)
...
Start tag: span
Data     : buff
Data     : ered
Data     : text
End tag  : span

Синтаксический анализ недопустимого HTML (например, атрибутов без кавычек) также работает:

>>> parser.feed('<p><a class=link href=#main>tag soup</p ></a>')
Start tag: p
Start tag: a
     attr: ('class', 'link')
     attr: ('href', '#main')
Data     : tag soup
End tag  : p
End tag  : a
Вернуться на верх