2011-04-11 62 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