2012-01-19 120 views
5

我正在研究一個應用程序,它需要解析HTML頁面中的URL(主要是HTTP URL) - 我無法控制輸入,並且其中一部分與預期的一樣,有點凌亂。Python中的URL解析 - 規範化路徑中的雙斜槓

的一個問題,我頻頻遭遇是,是裏urlparse非常嚴格,當談到有雙斜線的路徑部分解析和加入網址,例如(甚至可能是越野車?):

testUrl = 'http://www.example.com//path?foo=bar' 
urlparse.urljoin(testUrl, 
       urlparse.urlparse(testUrl).path) 

而不是預期的結果http://www.example.com//path(或甚至更好,與規範化的單斜槓),我結束了http://path

順便說一句,我運行這樣的代碼的原因是因爲它是我迄今爲止發現的脫離URL的查詢/碎片部分的唯一方式。也許有更好的方法來做到這一點,但我找不到一個。

任何人都可以推薦一種方法來避免這種情況,或者我應該只使用一個(相對簡單的,我知道)正則表達式來規範自己的路徑嗎?

+0

你所說的 「這是剝奪查詢/片段部分的唯一途徑」 是什麼意思?斜線與查詢有什麼關係? – jknupp

+0

它與查詢無關 - 我解析URL然後將它自己的路徑加入它的原因是因爲我想刪除查詢和片段。如果有更好的方法來做到這一點,我不需要解決這個問題 – shevron

+2

我認爲urlparse只是正確實現了URL的RFC - 它指定在部分似乎只有一個斜槓(http: //tools.ietf.org/html/rfc1738) - 所以在你的情況下,我會嘗試去除額外的斜線,然後將它傳遞給urlparse。 – BergmannF

回答

4

如果你只是想獲得無查詢部分的URL,我會跳過裏urlparse模塊,只是做:

testUrl.rsplit('?') 

該URL將在返回的列表的索引0處以及索引1處的查詢處。

不可能有兩個'?'在一個網址,所以它應該適用於所有的網址。

+0

這不會回答任何urlparse問題,但它絕對以非常簡單的方式解決了我的使用案例。謝謝! – shevron

1

它在official urlparse docs提到:

如果URL是絕對URL(即用//或方案開始://)的URL的主機名和/或方案將是目前的結果。例如

urljoin('http://www.cwi.nl/%7Eguido/Python.html', 
...   '//www.python.org/%7Eguido') 
'http://www.python.org/%7Eguido' 

如果你不希望這樣的行爲,預處理與urlsplit()和urlunsplit()的URL,消除可能的方案和netloc部分。

所以,你可以這樣做:

urlparse.urljoin(testUrl, 
      urlparse.urlparse(testUrl).path.replace('//','/')) 

輸出= 'http://www.example.com/path'

0

難道這不是一個解決方案嗎?

urlparse.urlparse(testUrl).path.replace('//', '/') 
5

的路徑(//path)單獨是無效的,其迷惑函數和被解釋爲一個主機名

http://tools.ietf.org/html/rfc3986.html#section-3.3

如果URI不包含授權組成部分,則路徑不能以兩個斜槓字符(「//」)開頭。

我特別不喜歡這兩種解決方案,但他們的工作:

import re 
import urlparse 

testurl = 'http://www.example.com//path?foo=bar' 

parsed = list(urlparse.urlparse(testurl)) 
parsed[2] = re.sub("/{2,}", "/", parsed[2]) # replace two or more/with one 
cleaned = urlparse.urlunparse(parsed) 

print cleaned 
# http://www.example.com/path?foo=bar 

print urlparse.urljoin(
    testurl, 
    urlparse.urlparse(cleaned).path) 

# http://www.example.com//path 

取決於你在做什麼,你可以做手工加入:

import re 
import urlparse 

testurl = 'http://www.example.com//path?foo=bar' 
parsed = list(urlparse.urlparse(testurl)) 

newurl = ["" for i in range(6)] # could urlparse another address instead 

# Copy first 3 values from 
# ['http', 'www.example.com', '//path', '', 'foo=bar', ''] 
for i in range(3): 
    newurl[i] = parsed[i] 

# Rest are blank 
for i in range(4, 6): 
    newurl[i] = '' 

print urlparse.urlunparse(newurl) 
# http://www.example.com//path 
+0

該URL實際上是有效的,因爲**它包含一個授權部分 - 所以URL可以以'//'開頭。無論如何,即使它無法解析無效,但「真實世界」的URL可能會有所幫助。 – shevron

+0

@ShaharEvron好點 - 編輯答案 – dbr

0

嘗試此:

def http_normalize_slashes(url): 
    url = str(url) 
    segments = url.split('/') 
    correct_segments = [] 
    for segment in segments: 
     if segment != '': 
      correct_segments.append(segment) 
    first_segment = str(correct_segments[0]) 
    if first_segment.find('http') == -1: 
     correct_segments = ['http:'] + correct_segments 
    correct_segments[0] = correct_segments[0] + '/' 
    normalized_url = '/'.join(correct_segments) 
    return normalized_url 

示例網址:

print(http_normalize_slashes('http://www.example.com//path?foo=bar')) 
print(http_normalize_slashes('http:/www.example.com//path?foo=bar')) 
print(http_normalize_slashes('www.example.com//x///c//v///path?foo=bar')) 
print(http_normalize_slashes('http://////www.example.com//x///c//v///path?foo=bar')) 

返回結果:

http://www.example.com/path?foo=bar 
http://www.example.com/path?foo=bar 
http://www.example.com/x/c/v/path?foo=bar 
http://www.example.com/x/c/v/path?foo=bar 

希望它能幫助.. :)

相關問題