lxml, похоже, добавляет тип документа по умолчанию, когда он отсутствует в html-документе.
Посмотрите этот демонстрационный код:
import lxml.etree
import lxml.html
def beautify(html):
parser = lxml.etree.HTMLParser(
strip_cdata=True,
remove_blank_text=True
)
d = lxml.html.fromstring(html, parser=parser)
docinfo = d.getroottree().docinfo
return lxml.etree.tostring(
d,
pretty_print=True,
doctype=docinfo.doctype,
encoding='utf8'
)
with_doctype = """
<!DOCTYPE html>
<html>
<head>
<title>With Doctype</title>
</head>
</html>
"""
# This passes!
assert "DOCTYPE" in beautify(with_doctype)
no_doctype = """<html>
<head>
<title>No Doctype</title>
</head>
</html>"""
# This fails!
assert "DOCTYPE" not in beautify(no_doctype)
# because the returned html contains this line
# <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# which was not present in the source before
Как я могу сказать lxml не делать этого?
Первоначально эта проблема была поднята здесь: https://github.com/mitmproxy/mitmproxy/issues/845
Цитирование комментария на Reddit может оказаться полезным:
lxml основан на libxml2, который делает это по умолчанию, если только вы не передадите параметр
HTML_PARSE_NODEFDTD
, я полагаю. Код здесь.Я не знаю, можете ли вы указать lxml передать эту опцию. libxml имеет привязки python, которые вы, возможно, могли бы использовать напрямую, но они кажутся очень сложными.
РЕДАКТИРОВАТЬ: еще немного покопался, и эта опция появляется в источнике lxml здесь. Эта опция делает именно то, что вы хотите, но я пока не знаю, как ее активировать, если это вообще возможно.
HTML_PARSE_NODEFDTD
не обрабатывается в HTMLParser. конструктор, так что вам, вероятно, не повезло. - person nwellnhof   schedule 12.08.2016