如何修改lxml autolink更自由?

时间:2011-04-11 23:09:30

标签: python regex hyperlink lxml

我正在使用伟大的lxml库的自动链接功能,如下所示:http://lxml.de/api/lxml.html.clean-module.html

我的问题是它只检测以 http:// 开头的网址。 我想使用像这样一个更广泛的url检测正则表达式: http://daringfireball.net/2010/07/improved_regex_for_matching_urls

我尝试使用lxml自动链接功能使该正则表达式无效。 我总是最终得到:

lxml\html\clean.py", line 571, in _link_text
host = match.group('host')
IndexError: no such group

那些知道如何使这项工作的python / regex专家呢?

2 个答案:

答案 0 :(得分:2)

为了使正则表达式适应lxml的自动链接,有两件事要做。首先将整个url模式匹配包装在组(?P<body> .. )中 - 这使lxml知道href=""属性中的内容。

接下来,将主机部分包装在(?<host> .. )组中,并在调用自动​​链接功能时传递avoid_hosts=[]参数。原因是您正在使用的正则表达式模式并不总是找到主机(有时host部分将是None),因为它匹配部分网址和模糊的网址模式。

我修改了正则表达式以包含上述更改并给出了一个代码段测试用例:

import re
import lxml.html
import lxml.html.clean

url_regexp = re.compile(r"""(?i)\b(?P<body>(?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|(?P<host>[a-z0-9.\-]+[.][a-z]{2,4}/))(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""")

DOC = """<html><body>
    http://foo.com/blah_blah
    http://foo.com/blah_blah/.
    http://www.extinguishedscholar.com/wpglob/?p=364.
    http://✪df.ws/1234
    rdar://1234
    rdar:/1234
    message://%3c330e7f840905021726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e
    What about &lt;mailto:gruber@daringfireball.net?subject=TEST&gt; (including brokets).
    bit.ly/foo
</body></html>"""

tree = lxml.html.fromstring(DOC)
body = tree.find('body')
lxml.html.clean.autolink(body, [url_regexp], avoid_hosts=[])
print lxml.html.tostring(tree)

输出:

<html><body>
    <a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>
    <a href="http://foo.com/blah_blah/">http://foo.com/blah_blah/</a>.
    <a href="http://www.extinguishedscholar.com/wpglob/?p=364">http://www.extinguishedscholar.com/wpglob/?p=364</a>.
    <a href="http://%C3%A2%C2%9C%C2%AAdf.ws/1234">http://&#226;&#156;&#170;df.ws/1234</a>
    <a href="rdar://1234">rdar://1234</a>
    <a href="rdar:/1234">rdar:/1234</a>
    <a href="message://%3c330e7f840905021726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e">message://%3c330e7f840905021726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e</a>
    What about &lt;<a href="mailto:gruber@daringfireball.net?subject=TEST">mailto:gruber@daringfireball.net?subject=TEST</a>&gt;
    (including brackets).
    <a href="bit.ly/foo">bit.ly/foo</a>
</body></html>

答案 1 :(得分:0)

你并没有给出足够的信息以确定,但我敢打赌,你正在逃避格鲁伯正则表达式反斜杠的问题。尝试使用原始字符串,它允许反斜杠而不转义,以及三引号,它允许您在字符串中使用引号而不必转义它们。 E.g。

re.compile(r"""(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""")