2016-08-12 1 views
0

lxml, кажется, добавляет тип doctype по умолчанию, когда его нет в документе html.Как предотвратить добавление lxml по умолчанию doctype

Смотрите этот демонстрационный код:

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

Цитируя comment on reddit, как это может быть полезно:

LXML основан на libxml2, что делает это по умолчанию, если вы не передаете параметр HTML_PARSE_NODEFDTD, Я верю. Код here.

Я не знаю, можете ли вы передать lxml, чтобы передать этот вариант, хотя .. libxml имеет привязки python, которые вы могли бы использовать напрямую, но они кажутся действительно волосатыми.

РЕДАКТИРОВАТЬ: еще некоторое копание, и этот вариант появляется в суде lxml here. Этот вариант делает именно то, что вы хотите, но я не уверен, как его активировать, если это возможно.

+0

Параметр 'HTML_PARSE_NODEFDTD' не обрабатывается в [конструкторе HTMLParser] (https://github.com/lxml/lxml/blob/lxml-3.4/src/lxml/parser.pxi#L1625), поэтому вы вероятно, не повезло. – nwellnhof

+0

@nwellnhof Возможно, мы могли бы исправить это и создать PR @ lxml? Опция присутствует [здесь] (https://github.com/lxml/lxml/blob/93ec66f6533995a7742278f9ba14b925149ac140/src/lxml/includes/htmlparser.pxd#L19-L20). – dufferZafar

+0

Я также [задал этот вопрос в списке рассылки lxml] (https://mailman-mail5.webfaction.com/pipermail/lxml/2016-August/007738.html). Пока нет решения. – dufferZafar

ответ

1

Там в настоящее время нет способа сделать это в LXML, но я создал Pull Request on lxml который добавляет default_doctype булево к HTMLParser.

После того, как код становится слиты в синтаксический анализатор должен быть создан следующим образом:

parser = lxml.etree.HTMLParser(
    strip_cdata=True, 
    remove_blank_text=True, 
    default_doctype=False, 
) 

Все остальное остается неизменным.

Смежные вопросы