2011-04-11 27 views
1

我使用lxml的大库的自动连接功能,如记录在这里:http://lxml.de/api/lxml.html.clean-module.html如何修改lxml自动链接以更自由?

我的问题是,它只能检测到与http开头的网址://。 我想用更广阔的网址检测正则表达式像这样的: 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 

任何蟒蛇/正则表达式大师在那里谁知道如何使这项工作?

回答

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://%[email protected]%3e 
    What about &lt;mailto:[email protected]?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://%[email protected]%3e">message://%[email protected]%3e</a> 
    What about &lt;<a href="mailto:[email protected]?subject=TEST">mailto:[email protected]?subject=TEST</a>&gt; 
    (including brackets). 
    <a href="bit.ly/foo">bit.ly/foo</a> 
</body></html> 
+0

这是一个正则表达式的地狱......但它的作品像魅力。还有一个问题:** bit.ly/foo **将链接到一个子文件夹,而不是域名......你将如何解决这个问题? – Titusz 2011-04-12 00:44:45

+0

您提供的正则表达式会匹配url-link文本,但clean.autolink函数是一个黑盒子:它不会让您传递回调来修改链接,然后对它们进行编码。我建议复制clean.autolink和clean._link_text函数,去掉你不使用的东西,并且自定义行为。特别是当你遍历匹配的url时,找到没有'Host'部分的东西,并且在url上添加'http://'方案(以及任何其他您希望应用的规则)。 – samplebias 2011-04-12 01:04:37

+0

谢谢...我现在正在工作...通过简单的后处理来解决它。 (用于body.xpath('// a')中的链接:....) – Titusz 2011-04-12 11:14:14

0

您确实没有提供足够的信息,但我敢打赌,您正在使用Gruber的正则表达式中的反斜杠来解决问题。尝试使用原始字符串(允许反斜线而不转义)和三重引号,这允许您在字符串中使用引号而不必转义那些引号。例如。

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`!()\[\]{};:'".,<>?«»“”‘’]))""") 
+0

这就是正是试图传递给自动链接功能)但它失败: lxml \ html \ clean.py“,行571,在_link_text host = match.group('host') IndexError:没有这样的组 – Titusz 2011-04-11 23:33:26

+0

啊,看着更多的lxml,他们期待着它产量命名匹配组, Gruber的正则表达式被设计用来匹配整个URL,没有。为了实现这一点,需要在正则表达式上进行更广泛的手术;也许我可以在今晚看更多,假设其他人没有发布解决方案。 – kindall 2011-04-11 23:36:56