html.parser — 간단한 HTML과 XHTML 구문 분석기

소스 코드: Lib/html/parser.py


이 모듈은 HTML(HyperText Mark-up Language)와 XHTML 형식의 텍스트 파일을 구문 분석하기 위한 기초로 사용되는 클래스 HTMLParser를 정의합니다.

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의 서브 클래스를 만들고 해당 메서드를 재정의해야 합니다.

이 구문 분석기는 종료 태그가 시작 태그와 일치하는지 검사하거나, 바깥(outer) 요소를 닫음으로써 묵시적으로 닫힌 요소에 대해 종료 태그 처리기를 호출하지 않습니다.

버전 3.4에서 변경: convert_charrefs 키워드 인자가 추가되었습니다.

버전 3.5에서 변경: 인자 convert_charrefs의 기본값은 이제 True입니다.

버전 3.14.1에서 변경: Added the scripting parameter.

HTML 구문 분석기 응용 프로그램 예제

As a basic example, below is a simple HTML parser that uses the HTMLParser class to print out start tags, end tags, and data as they are encountered:

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()가 호출될 때까지 버퍼링 됩니다. datastr이어야 합니다.

HTMLParser.close()

버퍼링 된 모든 데이터를 마치 파일 끝(end-of-file) 표시가 붙은 것처럼 처리합니다. 이 메서드는 파생 클래스에 의해 입력 끝에서의 추가 처리를 정의하기 위해 재정의될 수 있지만, 재정의된 버전에서는 항상 HTMLParser 베이스 클래스 메서드인 close()를 호출해야 합니다.

HTMLParser.reset()

인스턴스를 재설정합니다. 처리되지 않은 모든 데이터를 잃습니다. 이것은 인스턴스 생성 시에 묵시적으로 호출됩니다.

HTMLParser.getpos()

현재의 줄 번호와 오프셋(offset)을 반환합니다.

HTMLParser.get_starttag_text()

가장 최근에 열렸던 시작 태그의 텍스트를 반환합니다. 이것은 일반적으로 구조화된 처리에 필요하지 않지만, “배치된 대로(as deployed)” 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 ... />)를 만날 때 호출됩니다. 이 메서드는 이 특정의 어휘 정보(lexical information)가 필요한 서브 클래스에 의해 재정의될 수 있습니다; 기본 구현은 단순히 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-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)

처리 명령(processing instruction)을 만날 때 호출되는 메서드. data 매개 변수에는 전체 처리 명령이 포함됩니다. 예를 들어, 처리 명령 <?proc color='red'>의 경우, 이 메서드는 handle_pi("proc color='red'")로 호출됩니다. 파생 클래스에 의해 재정의되려는 목적입니다; 베이스 클래스 구현은 아무것도 수행하지 않습니다.

참고

HTMLParser 클래스는 처리 명령에 대해 SGML 구문 규칙을 사용합니다. 후행 '?'를 사용하는 XHTML 처리 명령은 '?'data에 포함되도록 합니다.

HTMLParser.unknown_decl(data)

이 메서드는 구문 분석기가 인식할 수 없는 선언을 읽었을 때 호출됩니다.

data 매개 변수는 <![...]> 마크업 안에 있는 선언의 전체 내용입니다. 파생 클래스가 재정의하는 것이 때때로 유용합니다. 베이스 클래스 구현은 아무것도 수행하지 않습니다.

예제

The following class implements a parser that will be used to illustrate more 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()

Parsing a 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"

Parsing an element with a few attributes and a title:

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

Parsing comments:

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

Parsing named and numeric character references and converting them to the correct char (note: these 3 references are all equivalent to '>'):

>>> parser = MyHTMLParser()
>>> parser.feed('&gt;&#62;&#x3E;')
Data     : >>>

>>> parser = MyHTMLParser(convert_charrefs=False)
>>> 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

Parsing invalid HTML (e.g. unquoted attributes) also works:

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