【问题标题】:How do I parse HTML lists in python like browsers do, tolerating lack of li elements?如何像浏览器一样在 python 中解析 HTML 列表,容忍缺少 li 元素?
【发布时间】:2021-10-10 21:38:20
【问题描述】:

我正在从用户剪切和粘贴中获取 HTML(在 Summernote rich edit 小部件中)。这意味着它不必是有效的 HTML 或有效的 XML,我无法控制它。这是一个无效的 HTML 示例(ulol 的子元素,而不是将 li 元素作为子元素)和无效的 XML(未关闭的 br 标记)。

<ol>one<ul>two<li>item</li></ul><br></ol>

Chrome 和 safari 都将其呈现为好像 "two" 在嵌套列表中,即使没有 li:

这似乎是合理的。

但是,parsing in python using lxml does not return an equivalent list structure。看到那个问题,它返回:

<div><ol/><ul><li>item</li></ul>
</div>

我需要接受格式错误的 HTML 和 XML 并以这样的方式修复它,特别是列表结构保留浏览器显示它的方式。更准确地说,在这种特殊情况下(缺少li),如果浏览器选择将项目显示为嵌套,我想将其解析为嵌套。

关于如何做到这一点的建议?是否有可以更稳健地处理这种特殊情况的 Python HTML 解析器?

Regexes are not great for this.

无论我如何表达这个问题,人们似乎给出的答案是“你真的应该有格式良好的 HTML/XML”,但这不是一个有用的答案。我不控制它。我需要处理格式错误的 HTML/XML,因为这是一种格式错误(缺少 li),因为浏览器会处理它。

【问题讨论】:

  • 您正在为不可预测的问题寻找可预测的答案。该序列不是有效的 HTML,因此没有“正确答案”。仅仅因为 Chrome 和 Safari 今天碰巧以这种方式呈现它并不意味着其他浏览器会,甚至它们会在他们的下一个版本中呈现。你正试图从混乱中提取秩序。如果有的话,正确的答案应该是将其标记为无效的 HTML。
  • 不知何故这个声音总是出现,即使我在问题中明确提到它。当然,我可以标记它,但用户不在乎。他们从某个地方复制了一些东西,看起来不错,现在他们希望它能够工作。如果将来发生变化,他们会希望它起作用。是的,制作令人愉悦的产品使用正是从混乱中提取秩序。
  • 我想这是一个哲学问题。这些用户犯了一个错误。他们破坏了代码。有人需要告诉他们如何正确地做到这一点。为什么不是你?试图模仿不可预测的行为对社会来说不是更好吗?
  • 没有。他们可能不拥有损坏的代码(例如,microsoft word、google docs、notion 等)。无论如何,这不是经营企业的方式。 “你犯了一个错误,但你不知道,因为一切看起来都很好,世界上的每个浏览器都能正确呈现它。请去更改一些你无权访问的代码,而不是完成你的工作我们的工具”是错误的答案。
  • 好吧,我断然不同意,但这是你的客户。

标签: python html lxml


【解决方案1】:

Python 有 html5lib 所以

import html5lib

def print_tree(node, indent = ''):
    print(indent + node.tag)
    for n in node:
        print_tree(n, indent = indent + '\t')

document = html5lib.parse("<ol>one<ul>two<li>item</li></ul><br></ol>")
print(html5lib.serialize(document))

print_tree(document)

给出例如

<ol>one<ul>two<li>item</ul><br></ol>
{http://www.w3.org/1999/xhtml}html
        {http://www.w3.org/1999/xhtml}head
        {http://www.w3.org/1999/xhtml}body
                {http://www.w3.org/1999/xhtml}ol
                        {http://www.w3.org/1999/xhtml}ul
                                {http://www.w3.org/1999/xhtml}li
                        {http://www.w3.org/1999/xhtml}br

意思是,一个类似于浏览器的DOM树https://software.hixie.ch/utilities/js/live-dom-viewer/saved/9540的树就建好了。

如果您不想在树中使用 HTML 命名空间,请使用 document = html5lib.parse("&lt;ol&gt;one&lt;ul&gt;two&lt;li&gt;item&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;/ol&gt;", namespaceHTMLElements = False)

你也可以使用 html5lib 来构建一个 lxml 树:

import html5lib

def print_tree(node, indent = ''):
    print(indent, node.tag, node.text if node.text else '')
    for n in node:
        print_tree(n, indent = indent + '\t')

document = html5lib.parse("<ol>one<ul>two<li>item</li></ul><br></ol>", treebuilder = 'lxml', namespaceHTMLElements = False)

print_tree(document.getroot())

【讨论】:

    猜你喜欢
    • 2023-03-10
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 2014-06-01
    • 2022-12-12
    • 2013-08-12
    • 1970-01-01
    相关资源
    最近更新 更多