HTMLParser — Простой парсер HTML и XHTML
Примечание
Модуль HTMLParser был переименован в html.parser в Python 3. Инструмент 2to3 автоматически адаптирует импорты при преобразовании исходного кода в Python 3.
Впервые в версии 2.2.
Исходный код: Lib/HTMLParser.py
В этом модуле определен класс HTMLParser, который служит основой для разбора текстовых файлов, отформатированных в HTML (HyperText Mark-up Language) и XHTML. В отличие от парсера в htmllib, этот парсер не основан на SGML-парсере из sgmllib.
-
class HTMLParser.HTMLParser -
Экземпляр класса
HTMLParserполучает данные HTML и вызывает методы обработчика при обнаружении открывающихся тегов, закрывающихся тегов, текста, комментариев и других элементов разметки. Пользователь должен создать подклассHTMLParserи переопределить его методы для реализации желаемого поведения.Класс
HTMLParserинициализируется без аргументов.В отличие от парсера в
htmllib, этот парсер не проверяет соответствие закрывающихся тегов открывающимся тегам или не вызывает обработчик закрывающихся тегов для элементов, которые закрываются неявно при закрытии внешнего элемента.
Также определено исключение:
-
exception HTMLParser.HTMLParseError -
HTMLParserспособен обрабатывать некорректную разметку, но в некоторых случаях может вызывать это исключение при обнаружении ошибки во время разбора. Это исключение предоставляет три атрибута:msg— краткое сообщение, объясняющее ошибку,lineno— номер строки, в которой была обнаружена некорректная конструкция, иoffset— номер символа в строке, с которого начинается конструкция.
1. Пример применения парсера HTML
В качестве простого примера ниже представлен простой парсер HTML, который использует класс HTMLParser для вывода открывающихся тегов, закрывающихся тегов и данных по мере их обнаружения:
from HTMLParser import HTMLParser
# create a subclass and override the handler methods
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
# instantiate the parser and fed it some HTML
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
2. Методы HTMLParser
Экземпляры класса HTMLParser имеют следующие методы:
-
HTMLParser.feed(data) -
Передать текст парсеру. Он обрабатывается по мере того, как он состоит из полных элементов; неполные данные буферизуются до тех пор, пока не будут переданы дополнительные данные или вызван метод
close(). data может быть какunicode, так иstr, но рекомендуется передаватьunicode.
-
HTMLParser.close() -
Принудительно обработать все данные в буфере, как если бы за ними следовал маркер конца файла. Этот метод может быть переопределен производным классом для определения дополнительной обработки в конце входных данных, но переопределенный вариант всегда должен вызывать базовый метод класса
HTMLParserclose().
-
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/')]).Изменено в версии 2.6: Все ссылки на сущности из
htmlentitydefsтеперь заменяются в значениях атрибутов.
-
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]>IE9-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 будет содержать все содержимое объявления внутри
<![...]>разметки. Иногда бывает полезно переопределить его в производном классе.
3. Примеры
Следующий класс реализует парсер, который будет использован для иллюстрации дополнительных примеров:
from HTMLParser import HTMLParser
from htmlentitydefs 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 = unichr(name2codepoint[name])
print "Named ent:", c
def handle_charref(self, name):
if name.startswith('x'):
c = unichr(int(name[1:], 16))
else:
c = unichr(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('>>>')
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
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/2.7/library/htmlparser.html