html.parser — Простой парсер HTML и XHTML

Источник: Lib/html/parser.py


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

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

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

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

Экземпляр 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), содержащих атрибуты, находящиеся внутри скобок <> тега. Имя 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;), где имя - общая ссылка на сущность (например, '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 '.

Содержимое условных комментариев (condcoms) 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, в которой используется концевой '?', приведет к включению '?' в данные.

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()

Разбор doctype:

>>> 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