lxml 和 <wbr> 标签

Posted

技术标签:

【中文标题】lxml 和 <wbr> 标签【英文标题】:lxml and <wbr> tags 【发布时间】:2012-05-07 16:32:53 【问题描述】:

默认情况下 lxml 不理解 wbr 标签,用于在长词中添加分词。当它应该被简单地格式化为&lt;wbr&gt;时,它将它格式化为&lt;wbr&gt;&lt;/wbr&gt;,类似于br标签。

如何将此行为添加到 lxml?

【问题讨论】:

我不确定你的申请,但你能简单地删除结束标签吗? 【参考方案1】:

由于&lt;wbr&gt; 仅存在于 html5 中,我怀疑正确的做法是使用 lxml.html.html5parser

除此之外,空标签列表是在常规 Python 代码中定义的,因此您可以随时对其进行猴子补丁;见lxml.html.defs.empty_tags。欢迎补丁,我敢肯定。 :)

【讨论】:

@bukzor: 'br' 也在special_inline_tags 中……你可能还需要在其中添加monkeypatch 'wbr'。 您可能需要先导入defs 并对其进行monkeypatch,然后再导入lxml 中的任何其他内容,否则其他模块将导入旧值。【参考方案2】:

好消息!这是完全不可能的。 HTML 标记名称为 baked right into libxml2

lxml.html.html5parser 包含几个严重的错误,这些错误的修复尚未发布。

但见鬼,让我们在本地修复它们,看看会发生什么。

>>> lxml.html.tostring(lxml.html.html5parser.fromstring('<p>hello<wbr>world!</p>'), encoding=unicode)
u'<html:p xmlns:html="http://www.w3.org/1999/xhtml">hello<html:wbr></html:wbr>world!</html:p>'

如此接近,却又如此遥远。至少结构是正确的。

再试一次:

>>> lxml.html.tostring(lxml.html.html5parser.fromstring('<p>hello<wbr>world!</p>', parser=lxml.html.html5parser.HTMLParser(namespaceHTMLElements=False)), encoding=unicode)
u'<p>hello<wbr></wbr>world!</p>'

求救。

至少没有

我想我可能会针对 lxml 和 libxml2 提交一些错误。

【讨论】:

【参考方案3】:

其实给 libxml2 打补丁并不难(这个演练是在 Ubuntu 11.04 和 Python 2.7.3 上完成的)

首先定义一个测试程序wbr_test.py

from lxml import etree
from cStringIO import StringIO

wbr_html = """\
<html>
  <head>
    <title>wbr test</title>
  </head>
<body>
  Test for a breakable<wbr>word implemenation change
</body>
</html>
"""

parser = etree.HTMLParser()
tree   = etree.parse(StringIO(wbr_html), parser)

result = etree.tostring(tree.getroot(),
                         pretty_print=True, method="html")
if result.split() != wbr_html.split(): # split, as we are not interested in whitespace differences
    print(result)
    print("not ok")
else:
    print("OK")

通过运行python wbr_test.py 确保它失败。它应该在之前插入一个&lt;\wbr&gt; &lt;\body&gt;,最后打印not ok

下载、解压、编译libxml2

wget ftp://xmlsoft.org/libxml2/libxml2-2.8.0.tar.gz
tar xvf libxml2-2.8.0.tar.gz 
cd libxml2-2.8.0/
./configure --prefix=/usr
make -j8  # adjust number to match your number of cores

安装和安装 python libxml2 绑定:

sudo make install
cd to_python_bindings
sudo python setup.py install

再次测试您的wbr_test.py,以确保使用最新的 libxml2 版本失败。

首先复制HTMLparser.c,例如在/var/tmp

现在在 libxml2 源代码的顶层编辑文件 HTMLparser.c。搜索单词forced(仅出现一次)。您将位于&lt;br&gt; 标记定义处。复制从刚刚找到的行开始的三行。最合适的插入点就在结尾之前(&lt;var&gt; 的定义之后)。要在表格中正确使用最后一个逗号,请在仅带有 '' 的一行之前插入三行,而不是带有 ';' 的一行。

在新插入的代码中,将br 替换为wbr 并将DECL clear_attrs 更改为NULL(假设新标签没有不推荐使用的属性)。

结果应该与/var/tmp (diff -u HTMLparser.c /var/tmp) 中的版本不同,如下所示:

@@ -1039,6 +1039,9 @@
 ,
  "var",   0, 0, 0, 0, 0, 0, 1, "instance of a variable or program argument",
DECL html_inline, NULL, DECL html_attrs, NULL, NULL
+,
+ "wbr",   0, 2, 2, 1, 0, 0, 1, "possible line break ",
+   EMPTY , NULL , DECL core_attrs, NULL , NULL
 
 ;

制作和安装:

make && sudo make install

再次测试您的wbr_test.py。应该显示OK

【讨论】:

非常酷!您能否确认仅使用运行时配置无法获得类似的结果? 表达相同问题的另一种方式:libxml2 是否不允许对您已修补的列表进行运行时配置? 我真的很想知道 libxml2 是否可以在不重构源代码的情况下实现这一点。定义位于静态 const 元素表中,它不会 被复制到更动态的结构中,而是按原样使用。无法从 C 中向此类表添加条目,因此无法从 Python 中添加条目。 谢谢安东。这似乎很权威。如果上游的这种重组会受到赞赏,您是否有任何暗示? 重组可能有点过火。 HTML 是唯一一种具有此类特定标签语义的类 XML 语言;这里的问题只是HTML5添加了更多标签,而libxml2只知道HTML4。添加新标签以及指定要使用的 HTML 版本的方法肯定就足够了。【参考方案4】:

作为一种快速修复,为什么不使用字符串的replace 方法来删​​除关闭标签?

>>> t = 'Thisisa<wbr></wbr>test'
>>> t.replace('</wbr>', '')
'Thisisa<wbr>test'

【讨论】:

以上是关于lxml 和 <wbr> 标签的主要内容,如果未能解决你的问题,请参考以下文章

Python通过lxml库遍历xml通过xpath查询(标签,属性名称,属性值,标签对属性)

如何从没有尾巴的lxml中的节点删除标签?

Python:使用`lxml.html`将HTML内容注入标签

是否有任何 html 实体可以替代“break”标签 (<br>)? [复制]

使用 python 和 lxml 模块从 html 中删除所有 javascript 标签和样式标签

如何用Python爬取出HTML指定标签内的文本?