2014-02-07 99 views
26

我想用python更改一個url中的主機名,並且一直在使用urlparse模塊玩了一會兒而沒有找到令人滿意的解決方案。作爲一個例子,考慮網址:在一個url中更改主機名

https://www.google.dk:80/barbaz

我想換成「www.google.dk」與如「www.foo.dk」,所以我得到以下網址:

https://www.foo.dk:80/barbaz

所以我想要替換的部分是urlparse.urlsplit指的是主機名。我本來希望urlsplit的結果能讓我做出改變,但是結果類型ParseResult並不允許我這樣做。如果沒有別的東西,我當然可以通過將所有部分與+一起附加到一起來重新構建新的url,但是這會讓我得到一些帶有很多條件的非常難看的代碼,以便在正確的位置獲得「://」和「:」 。

+0

我試圖避免任何if語句,因爲它可能會有所不同,無論基地址是否有端口號。根據你的回答,似乎我不能避免它:-)。謝謝你的幫助。 – Endling

回答

49

可以使用urlparse.urlparse功能和ParseResult._replace方法:

>>> import urlparse 
>>> parsed = urlparse.urlparse("https://www.google.dk:80/barbaz") 
>>> replaced = parsed._replace(netloc="www.foo.dk:80") 
>>> print replaced 
ParseResult(scheme='https', netloc='www.foo.dk:80', path='/barbaz', params='', query='', fragment='') 

ParseResultnamedtuple_replace一個子類是namedtuple方法:

返回指定的元組更換指定的新實例字段 具有新值

UPDATE

如@ 2rs2ts在註釋所述netloc屬性包括端口號。

好消息:ParseResulthostnameport屬性。 壞消息:hostnameport不是namedtuple的成員,它們是動態屬性,不能做parsed._replace(hostname="www.foo.dk")。它會拋出一個異常。

如果你不想拆就:和您的網址總是有一個端口號,並沒有usernamepassword(這是網址,如「https://username:[email protected]:80/barbaz」),你可以這樣做:

parsed._replace(netloc="{}:{}".format(parsed.hostname, parsed.port)) 
+1

請注意,主機名被稱爲'netloc',它包含任何端口號。這個答案表明,但沒有明確說明。 – 2rs2ts

+6

使用私人方法'_replace'感覺不對。 – Flimm

+12

'_replace'是'namedtuple'公共API的一部分。它只是從下劃線開始,以避免與字段名稱衝突。 –

14

你可以利用urlspliturlunsplit從Python的urlparse

>>> from urlparse import urlsplit, urlunsplit 
>>> url = list(urlsplit('https://www.google.dk:80/barbaz')) 
>>> url 
['https', 'www.google.dk:80', '/barbaz', '', ''] 
>>> url[1] = 'www.foo.dk:80' 
>>> new_url = urlunsplit(url) 
>>> new_url 
'https://www.foo.dk:80/barbaz' 

隨着文檔狀態,傳遞給urlunsplit()參數「可以是任何五我tem iterable「,所以上面的代碼按預期工作。

0

只需更換主機不接觸所使用的端口(如果有的話),使用此:

import re, urlparse 

p = list(urlparse.urlsplit('https://www.google.dk:80/barbaz')) 
p[1] = re.sub('^[^:]*', 'www.foo.dk', p[1]) 
print urlparse.urlunsplit(p) 

打印

https://www.foo.dk:80/barbaz 

如果您沒有給出任何端口已經,這工作正常以及。

如果你喜歡_replace方式奈傑爾指出的那樣,你可以使用它代替:

p = urlparse.urlsplit('https://www.google.dk:80/barbaz') 
p = p._replace(netloc=re.sub('^[^:]*', 'www.foo.dk', p.netloc)) 
print urlparse.urlunsplit(p) 
4

使用urlparse模塊的urlparseurlunparse方法:

import urlparse 

old_url = 'https://www.google.dk:80/barbaz' 
url_lst = list(urlparse.urlparse(old_url)) 
# Now url_lst is ['https', 'www.google.dk:80', '/barbaz', '', '', ''] 
url_lst[1] = 'www.foo.dk:80' 
# Now url_lst is ['https', 'www.foo.dk:80', '/barbaz', '', '', ''] 
new_url = urlparse.urlunparse(url_lst) 

print(old_url) 
print(new_url) 

輸出:

https://www.google.dk:80/barbaz 
https://www.foo.dk:80/barbaz 
1

一個簡單的字符串替換ho ST中netloc也能在大多數情況下:

>>> p = urlparse.urlparse('https://www.google.dk:80/barbaz') 
>>> p._replace(netloc=p.netloc.replace(p.hostname, 'www.foo.dk')).geturl() 
'https://www.foo.dk:80/barbaz' 

如果由於某種原因,用戶名或密碼的主機名匹配這將無法正常工作。你不能限制str.replace僅替換最後一次出現,所以我們可以將使用分割和結合​​:

>>> p = urlparse.urlparse('https://www.google.dk:[email protected]:80/barbaz') 
>>> new_netloc = 'www.foo.dk'.join(p.netloc.rsplit(p.hostname, 1)) 
>>> p._replace(netloc=new_netloc).geturl() 
'https://www.google.dk:[email protected]:80/barbaz' 
+0

_replace是私人的,不應該被客戶端代碼使用。 –

+0

比接受的答案更好,尤其是第二種選擇。 –

+0

@gb:_replace在NamedTuple中不是私有的。它是API的一部分: https://docs.python.org/2/library/collections.html#collections.namedtuple – kbyrd

0

我也建議使用urlspliturlunsplit像@ linkyndy的答案,但對於Python3這將是:

>>> from urllib.parse import urlsplit, urlunsplit 
>>> url = list(urlsplit('https://www.google.dk:80/barbaz')) 
>>> url 
['https', 'www.google.dk:80', '/barbaz', '', ''] 
>>> url[1] = 'www.foo.dk:80' 
>>> new_url = urlunsplit(url) 
>>> new_url 
'https://www.foo.dk:80/barbaz'