html5lib с lxml treebuilder неправильно анализирует пространства имен

Я пытаюсь проанализировать некоторый HTML-контент с помощью html5lib с помощью lxml построителя дерева. Примечание. Я использую библиотеку requests для захвата содержимого, а содержимое HTML5 (пробовал с XHTML - тот же результат).

Когда я просто вывожу исходный код HTML, все выглядит нормально:

response = requests.get(url)
return response.text

возвращается

<html xmlns:foo="http://www.example.com/ns/foo">

Но когда я на самом деле анализирую его с помощью html5lib, происходит что-то странное:

tree = html5lib.parse(response.text, treebuilder = 'lxml', namespaceHTMLElements = True)
html = tree.getroot()
return lxml.etree.tostring(html, pretty_print = False)

возвращается

<html:html xmlns:html="http://www.w3.org/1999/xhtml" xmlnsU0003Afoo="http://www.example.com/ns/foo">

Обратите внимание на xmlnsU0003Afoo вещь.

Кроме того, html.nsmap dict не содержит пространства имен foo, только html.

Кто-нибудь знает, что происходит и как я могу это исправить?

Позднее редактирование:

Кажется, это ожидаемое поведение:

Если используемый XML API ограничивает допустимые символы в локальных именах элементов и атрибутов, то инструмент может сопоставить все локальные имена элементов и атрибутов [...] с набором разрешенных имен, заменив любой символ, который не не поддерживается с заглавной буквой U и шестью цифрами кода Unicode символа [...] - Приведение HTML DOM к информационному набору


person Alexei    schedule 03.09.2012    source источник
comment
Можете ли вы предоставить пример URL?   -  person Peter Hoffmann    schedule 04.09.2012
comment
В настоящее время я использую образцы данных, которые я создал на своем локальном веб-сервере. Но это должно быть очевидно из вывода примера. Это просто документ HTML с пользовательскими пространствами имен.   -  person Alexei    schedule 04.09.2012


Ответы (1)


Несколько наблюдений:

  • HTML5, похоже, не поддерживает атрибуты xmlns. Цитируя раздел 1.6 последней спецификации HTML5: ". ..пространства имен не могут быть представлены с использованием синтаксиса HTML, но они поддерживаются в DOM и в синтаксисе XHTML». Я вижу, вы тоже пытались использовать XHTML, но в настоящее время вы используете HTML5, поэтому здесь может быть проблема. U+003A — это Unicode для двоеточия, так что xmlns каким-то образом отмечается, но промахивается.

  • Существует открытая проблема с пользовательскими элементами пространства имен по крайней мере для версии PHP.

  • Я не понимаю роль html5lib здесь. Почему бы просто не использовать lxml напрямую:

from lxml import etree

tree = etree.fromstring(resp_text)
print etree.tostring(tree, pretty_print=True)

Кажется, это делает то, что вы хотите, без html5lib и без глупой ошибки xmlnsU0003Afoo. С тестовым HTML, который я использовал, я получил правильный вывод (следует), и tree.nsmap содержал запись для 'foo'.

<html xmlns:foo="http://www.example.com/ns/foo">
    <head>
        <title>yo</title>
    </head>
    <body>
        <p>test</p>
    </body>
</html>

В качестве альтернативы, если вы хотите использовать чистый html5lib, вы можете просто использовать включенный simpletree:

tree = html5lib.parse(resp_text, namespaceHTMLElements=True)
print tree.toxml()

Хотя это не портит атрибут xmlns, simpletree, к сожалению, не имеет более мощных функций ElementTree, таких как xpath().

person Jonathan Eunice    schedule 03.09.2012
comment
1. Проблема здесь не в том, поддерживает ли HTML5 xmlns или нет. Проблема в том, что библиотека, кажется, неправильно анализирует атрибут, независимо от его значения, т.е. я даже не могу сделать: html.attrib['xmlns:foo'], но вместо этого я должен сделать: html.attrib['xmlnsU0003Afoo'] (ну, поскольку я должен действовать так, как будто я не знаю префикс, мне придется перебрать каждый атрибут и посмотреть, начинается ли он с xmlnsU0003A) Я нахожу это странным, правда. - person Alexei; 04.09.2012
comment
2. Я использую html5lib по 2 причинам: одна из них заключается в том, что сейчас я просто дурачусь, изучаю язык Python и другие классные вещи. Во-вторых, в конечном итоге приложение, которое я создаю, должно иметь возможность работать с реальными страницами в Интернете, и я хочу, чтобы оно видело их так, как их видят браузеры (и, как следствие, так, как их видят разработчики, это весь смысл). - person Alexei; 04.09.2012
comment
3. Я видел эту ветку в их списке проблем, касающихся переноса PHP. Это и журнал чата — единственное, что я смог найти (лог чата был бесполезен, кто-то говорил, что html5lib не работает в отношении пространств имен). Я думал, что спрошу людей на SO, прежде чем задавать вопрос, может быть, я делаю что-то не так. - person Alexei; 04.09.2012
comment
Но в любом случае, я заинтересован в том, чтобы продолжить работу над проектом, поэтому я пока переключусь на анализатор HTML, включенный в lxml. Я зарегистрирую проблему завтра утром на веб-сайте html5lib и посмотрю, что они говорят. Спасибо за Ваш ответ! - person Alexei; 04.09.2012
comment
Я тоже предпочел бы, чтобы html5lib вел себя так, как вы ожидаете. OTOH, синтаксические анализаторы имеют долгую историю получения неожиданных результатов при неожиданном или неправильном вводе. Поскольку атрибуты xmlns недопустимы в HTML5, это может быть частью проблемы. ГИГО. Я надеюсь, что проблема именно в этом, потому что в противном случае перекодирование атрибута как xmlnsU0003Afoo — ужасная глупость! Ну, в любом случае, это ужасная глупость, но... - person Jonathan Eunice; 04.09.2012
comment
Насколько я знаю, символ двоеточия : должен быть принят как допустимый символ в имени атрибута, независимо от поддержки пространства имен. Если это недопустимый символ, то почему атрибут xmlns:html не только распознается как атрибут, но фактически интерпретируется как объявление пространства имен? Было бы обидно узнать, что это на самом деле жестко закодировано if attr == 'xmlns:html' :) Тем временем я задал вопрос и, надеюсь, получу ответ. - person Alexei; 04.09.2012
comment
По-видимому, это ожидаемое поведение: если используемый XML API ограничивает допустимые символы в локальных именах элементов и атрибутов, то инструмент может сопоставить все локальные имена элементов и атрибутов [...] с набором разрешенных имен путем замена любого символа, который не поддерживается, на заглавную букву U и шесть цифр кода Unicode символа [...] См. Приведение HTML DOM к информационному набору - person Alexei; 04.09.2012
comment
Если вы готовы отказаться от xpath() и тому подобного, чистый html5lib будет анализироваться, как вы хотите, в simpletree. (См. код, добавленный в конец предыдущего ответа.) - person Jonathan Eunice; 04.09.2012
comment
Я думал об использовании построителя дерева по умолчанию, но мне нужен способ быстро перемещаться. Я не уверен, что simpletree вообще можно использовать в реальном мире. Я, вероятно, когда-нибудь с ним поиграю, но пока я буду придерживаться lxml. На самом деле, прежде чем начать это, я искал ElementTree (я знал об этом некоторое время назад, проводя некоторые исследования, и нашел его удобным), и я был приятно удивлен, обнаружив, что lxml.etree имеет аналогичный API. - person Alexei; 04.09.2012
comment
Я полностью понимаю. ElementTree очень низкоуровневый даже в лучшем случае. Способность lxml выполнять простой xpath поиск очень помогает, но для обработки документов (например, HTML) все еще УЖАСНО по сравнению с чем-то вроде XML::Twig. - person Jonathan Eunice; 05.09.2012
comment
Хотя Perl отлично подходит для обработки текста, на самом деле это не вариант. Не для меня. Я дурачился с ним некоторое время назад и не мог понять свой собственный код на следующий день. Чтобы стать монахом, требуется огромное количество времени и энергии, но я работаю в рекламной индустрии последние 6 лет, и крайний срок всегда вчера, поэтому я должен действовать как можно быстрее. Однако я уверен, что в Perl есть одна строчка для доставки на прошлой неделе. Perl настолько быстр, что вы даже можете путешествовать во времени и исправлять ошибки до того, как они произойдут :D Не может иметь их все! - person Alexei; 05.09.2012