# `html.parser` — Simple HTML and XHTML parser

Вихідний код: Lib/html/parser.py

Цей модуль визначає клас `HTMLParser`, який служить основою для аналізу текстових файлів, відформатованих у HTML (HyperText Mark-up Language) і XHTML.

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

  Створіть екземпляр парсера, здатний аналізувати недійсну розмітку.

  If convert_charrefs is true (the default), all character references (except the ones in elements like `script` and `style`) are automatically converted to the corresponding Unicode characters.

  If scripting is false (the default), the content of the `noscript` element is parsed normally; if it’s true, it’s returned as is without being parsed.

  Екземпляр `HTMLParser` отримує дані HTML і викликає методи обробки, коли зустрічаються початкові теги, кінцеві теги, текст, коментарі та інші елементи розмітки. Користувач повинен створити підклас `HTMLParser` і перевизначити його методи для реалізації бажаної поведінки.

  Цей синтаксичний аналізатор не перевіряє відповідність кінцевих тегів початковим тегам і не викликає обробник кінцевих тегів для елементів, які закриваються неявно шляхом закриття зовнішнього елемента.

  Змінено в версії 3.4: Додано аргумент ключового слова convert_charrefs.

  Змінено в версії 3.5: Значення за замовчуванням для аргументу convert_charrefs тепер `True`.

  Змінено в версії 3.11.15: Added the scripting parameter.

## Приклад програми аналізатора 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()`. data має бути `str`.

HTMLParser.close()

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

HTMLParser.reset()

  Скинути примірник. Втрачає всі необроблені дані. Це викликається неявно під час створення екземпляра.

HTMLParser.getpos()

  Повернути поточний номер рядка та зсув.

HTMLParser.get_starttag_text()

  Повертає текст останнього відкритого початкового тегу. Зазвичай це не потрібно для структурованої обробки, але може бути корисним для роботи з HTML «у розгорнутому стані» або для повторного створення вхідних даних із мінімальними змінами (можна зберегти пробіли між атрибутами тощо).

Наступні методи викликаються, коли зустрічаються дані або елементи розмітки, і вони призначені для перевизначення в підкласі. Реалізації базового класу нічого не роблять (крім `handle_startendtag()`):

HTMLParser.handle_starttag(tag, attrs)

  Цей метод викликається для обробки початкового тегу елемента (наприклад, `<div id="main">`).

  Аргумент тег — це назва тегу, перетворена в нижній регістр. Аргумент attrs — це список пар `(ім’я, значення)`, що містить атрибути, що містяться в дужках `<>` тегу. Ім’я буде перекладено на нижній регістр, а лапки в значенні видалено, а посилання на символи та сутності замінено.

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

  Усі посилання на сутності з `html.entities` замінюються в значеннях атрибутів.

HTMLParser.handle_endtag(tag)

  Цей метод викликається для обробки кінцевого тегу елемента (наприклад, `</div>`).

  Аргумент тег — це назва тегу, перетворена в нижній регістр.

HTMLParser.handle_startendtag(tag, attrs)

  Подібно до `handle_starttag()`, але викликається, коли аналізатор зустрічає порожній тег у стилі XHTML (`<img ... />`). Цей метод може бути замінений підкласами, які потребують саме цієї лексичної інформації; стандартна реалізація просто викликає `handle_starttag()` і `handle_endtag()`.

HTMLParser.handle_data(data)

  This method is called to process arbitrary data (e.g. text nodes and the content of elements like `script` and `style`).

HTMLParser.handle_entityref(name)

  This method is called to process a named character reference of the form `&name;` (e.g. `&gt;`), where name is a general entity reference (e.g. `'gt'`). This method is only called if convert_charrefs is false.

HTMLParser.handle_charref(name)

  This method is called to process decimal and hexadecimal numeric character references of the form `&#NNN;` and `&#xNNN;`. For example, the decimal equivalent for `&gt;` is `&#62;`, whereas the hexadecimal is `&#x3E;`; in this case the method will receive `'62'` or `'x3E'`. This method is only called if convert_charrefs is false.

HTMLParser.handle_comment(data)

  Цей метод викликається, коли зустрічається коментар (наприклад, `<!--comment-->`).

  Наприклад, коментар `<!-- comment -->` призведе до виклику цього методу з аргументом `' comment ''`.

  Вміст умовних коментарів Internet Explorer (condcoms) також буде надіслано цьому методу, тому для `<!--[if IE 9]> IE9-специфічного вмісту <![endif]-->` цей метод отримає `'[if IE 9]>IE9-специфічний вміст< ![endif]''`.

HTMLParser.handle_decl(decl)

  Цей метод викликається для обробки декларації типу документа HTML (наприклад, `<!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

The content of elements like `script` and `style` is returned as is, without further parsing:

    >>> 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! &#9786;</strong>");</script>')
    Start tag: script
         attr: ('type', 'text/javascript')
    Data     : alert("<strong>hello! &#9786;</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]

Розбір іменованих і числових посилань на символи та їх перетворення на правильний char (примітка: всі ці 3 посилання еквівалентні `'>'`):

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

Feeding incomplete chunks to `feed()` works, but `handle_data()` might be called more than once if convert_charrefs is false:

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