Содержание страницы
20.2. html.parser – Простой парсер HTML и XHTML¶html.parser – Simple HTML and XHTML parser
Исходный код: Lib/html/parser.py
Этот модуль определяет класс HTMLParser, который служит основой для разбора текстовых файлов в формате HTML (язык гипертекстовой разметки) и XHTML.
- class html.parser.HTMLParser(strict=False)¶
Создаёт экземпляр парсера. Если strict равно False (по умолчанию), парсер принимает и разбирает некорректную разметку. Если strict равно True, парсер возбуждает исключение HTMLParseError вместо [1], когда не может разобрать разметку. Использование strict=True не рекомендуется, а аргумент strict устарел.
Экземпляр HTMLParser получает HTML-данные и вызывает методы-обработчики при обнаружении открывающих тегов, закрывающих тегов, текста, комментариев и других элементов разметки. Чтобы реализовать желаемое поведение, следует создать подкласс HTMLParser и переопределить его методы.
Этот парсер не проверяет, соответствуют ли закрывающие теги открывающим, и не вызывает обработчик закрывающего тега для элементов, которые неявно закрываются при закрытии внешнего элемента.
Изменено в версии 3.2: добавлен ключевой аргумент strict.
Устарело с версии 3.3, будет удалено в версии 3.5: Аргумент strict и строгий режим устарели. Теперь парсер также способен принимать и разбирать некорректную разметку.
Также определено исключение:
- exception html.parser.HTMLParseError¶
Исключение, возбуждаемое классом HTMLParser, когда он обнаруживает ошибку при разборе и strict равен True. Это исключение предоставляет три атрибута: msg – краткое сообщение, объясняющее ошибку; lineno – номер строки, в которой обнаружен некорректный элемент; offset – количество символов от начала строки, где начинается этот элемент.
Устарело с версии 3.3, будет удалено в версии 3.5: Это исключение было объявлено устаревшим, поскольку оно никогда не возбуждается парсером (при использовании режима нестрогого разбора по умолчанию).
20.2.1. Пример приложения парсера HTML¶Example HTML Parser Application
В качестве простого примера ниже приведён парсер 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(strict=False)
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
20.2.2. Методы HTMLParser¶HTMLParser Methods
Экземпляры 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">).
Аргумент tag – это имя тега, приведённое к нижнему регистру. Аргумент attrs – это список пар (name, value), содержащих атрибуты, найденные внутри <> скобок тега. name будет преобразован в нижний регистр, кавычки в value удаляются, а символьные и сущностные ссылки заменяются.
Например, для тега <A HREF="http://www.cwi.nl/"> этот метод был бы вызван как handle_starttag('a', [('href', 'http://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; (например, >), где name – это общая ссылка на сущность (например, 'gt').
- HTMLParser.handle_charref(name)¶
Этот метод вызывается для обработки десятичных и шестнадцатеричных числовых символьных ссылок вида &#NNN; и &#xNNN;. Например, десятичный эквивалент для > – >, а шестнадцатеричный – >; в этом случае метод получит '62' или 'x3E'.
- HTMLParser.handle_comment(data)¶
Этот метод вызывается, когда встречается комментарий (например, <!--comment-->).
Например, комментарий <!-- comment --> приведёт к вызову этого метода с аргументом ' comment '.
Содержимое условных комментариев Internet Explorer (condcoms) также будет передаваться этому методу, так что для <!--[if IE 9]>IE9-specific content<![endif]--> этот метод получит '[if IE 9]>IE-specific content<![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, использующая завершающий '?', приведёт к включению '?' в data.
- HTMLParser.unknown_decl(data)¶
Этот метод вызывается, когда парсер считывает нераспознанное объявление.
Параметр data будет содержать всё содержимое объявления внутри разметки <![...]>. Иногда его полезно переопределять в производном классе. Реализация базового класса вызывает исключение HTMLParseError, когда strict имеет значение True.
20.2.3. Примеры¶Examples
Следующий класс реализует парсер, который будет использоваться для иллюстрации дополнительных примеров:
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(strict=False)
Разбор объявления типа документа:
>>> 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]
Разбор именованных и числовых символьных ссылок и преобразование их в соответствующий символ (примечание: эти три ссылки эквивалентны '>'):
>>> parser.feed('>>>')
Named ent: >
Num ent : >
Num ent : >
Передача неполных фрагментов в feed() работает, но handle_data() может вызываться более одного раза:
>>> 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
Сноски
| [1] | По причинам обратной совместимости режим strict не вызывает исключений для всего несоответствующего HTML. То есть некоторый некорректный HTML допускается даже в режиме strict. |