2012-05-14 219 views
9

我正在尋找一個庫函數來標準化Python中的一個URL,即刪除路徑中的「./」或「../」部分,或添加一個默認端口或轉義特殊字符等。結果應該是指向同一網頁的兩個URL唯一的字符串。例如http://google.comhttp://google.com:80/a/../應返回相同的結果。規範化/標準化URL?

我更喜歡Python 3,並且已經通過urllib模塊查看過。它提供了分割網址的功能,但沒有任何功能可以對它們進行規範化。 Java有URI.normalize()函數做類似的事情(雖然它不認爲默認端口80等於沒有給定的端口),但是有沒有像這樣的python?

+0

作爲一個側面說明,例如資源通過'http:// google.com /'不低於'HTTP相同://谷歌.COM:80 /一個/../'。也就是說,如果'/ a'不存在,那麼第二條路徑將失敗。通過「規範化」它,你失去了這種特殊情況,並且當你開始一個無效的URI時最終得到一個有效的URI ...... –

回答

0

good start之後,我編寫了一個適用於網絡中常見的大多數情況的方法。

def urlnorm(base, link=''): 
    '''Normalizes an URL or a link relative to a base url. URLs that point to the same resource will return the same string.''' 
    new = urlparse(urljoin(base, url).lower()) 
    return urlunsplit((
    new.scheme, 
    (new.port == None) and (new.hostname + ":80") or new.netloc, 
    new.path, 
    new.query, 
    '')) 
4

如何:

In [1]: from urllib.parse import urljoin 

In [2]: urljoin('http://example.com/a/b/c/../', '.') 
Out[2]: 'http://example.com/a/b/' 

靈感來自答案this question。它沒有標準化端口,但它應該很簡單,以掀起一個功能。

+0

我沒有'urllib.parse',但是我有'urlparse'。 – osa

+3

'urllib.parse'是Python 3的位置 - 最初的問題是關於Py 3的問題。 –

4

這是我使用的,它的工作到目前爲止。你可以從pip獲取urlnorm。

請注意,我對查詢參數進行排序。我發現這是至關重要的。

from urlparse import urlsplit, urlunsplit, parse_qsl 
from urllib import urlencode 
import urlnorm 

def canonizeurl(url): 
    split = urlsplit(urlnorm.norm(url)) 
    path = split[2].split(' ')[0] 

    while path.startswith('/..'): 
     path = path[3:] 

    while path.endswith('%20'): 
     path = path[:-3] 

    qs = urlencode(sorted(parse_qsl(split.query))) 
    return urlunsplit((split.scheme, split.netloc, path, qs, '')) 
+0

不錯,刪除無效的父目錄 – hoju

+0

您需要用''split'[split] .split('')[0] urllib.parse.quote(split [2])' - 在某些情況下,URL中有空格是完全正常的,而且實際上是必需的。 此外,urlnorm僅適用於py2k –

+0

此外,在某些不常見的情況下,您將放棄片段,該片段實際上可能是必需的URL組件。是的,有一個非零數量的網頁,其中'blah.com /#wat'是一個完全不同的頁面,然後是'blah.com /'。它通常使用JavaScript完成,並且是一個巨大的PITA,但它存在。 –

2

urltools模塊標準化的多個斜線,...組件而不在http://搞亂了雙斜線。

一旦你這樣做pip install urltools的用法如下:

print urltools.normalize('http://domain.com:80/a////b/../c') 
>>> 'http://domain.com/a/c'