Python3標准庫:urllib.parse分解URL


1. urllib.parse分解URL

urllib.parse模塊提供了一些函數,可以管理URL及其組成部分,這包括將URL分解為組成部分以及由組成部分構成URL。

1.1 解析

urlparse()函數的返回值是一個ParseResult對象,其相當於一個包含6個元素的tuple。

from urllib.parse import urlparse

url = 'http://netloc/path;param?query=arg#frag'
parsed = urlparse(url)
print(parsed)

通過元組接口得到的URL各部分分別是機制、網絡位置、路徑、路徑段參數(由一個分號將路徑分開)、查詢以及片段。

盡管返回值相當於一個元組,但實際上它基於一個namedtuple,這是tuple的一個子類,除了可以通過索引訪問,它還支持通過命名屬性訪問URL的各部分。屬性API不僅更易於程序員使用,還允許訪問tupleAPI中未提供的很多值。

from urllib.parse import urlparse

url = 'http://user:pwd@NetLoc:80/path;param?query=arg#frag'
parsed = urlparse(url)
print('scheme  :', parsed.scheme)
print('netloc  :', parsed.netloc)
print('path    :', parsed.path)
print('params  :', parsed.params)
print('query   :', parsed.query)
print('fragment:', parsed.fragment)
print('username:', parsed.username)
print('password:', parsed.password)
print('hostname:', parsed.hostname)
print('port    :', parsed.port)

輸入URL中可能提供用戶名(username)和密碼(password),如果沒有提供就設置為None。主機名(hostname)與netloc值相同,全為小寫並且去除端口值。如果有端口(port),則轉換為一個整數,如果沒有則設置為None。

 

urlsplit()函數可以替換urlparse(),但行為稍有不同,因為它不會從URL分解參數。

from urllib.parse import urlsplit

url = 'http://user:pwd@NetLoc:80/p1;para/p2;para?query=arg#frag'
parsed = urlsplit(url)
print(parsed)
print('scheme  :', parsed.scheme)
print('netloc  :', parsed.netloc)
print('path    :', parsed.path)
print('query   :', parsed.query)
print('fragment:', parsed.fragment)
print('username:', parsed.username)
print('password:', parsed.password)
print('hostname:', parsed.hostname)
print('port    :', parsed.port)

由於沒有分解參數,tuple API胡顯示五個元素而不是6個,並且這里沒有params屬性。

要想從一個URL剝離出片段標識符,如從一個URL查找基頁面名,可以使用urldefrag()。

from urllib.parse import urldefrag

original = 'http://netloc/path;param?query=arg#frag'
print('original:', original)
d = urldefrag(original)
print('url     :', d.url)
print('fragment:', d.fragment)

返回值是一個基於namedtuple的DefragResult,其中包含基URL和片段。

1.2 反解析

還可以利用一些方法把分解的URL的各個部分重新組裝在一起,形成一個串。解析的URL對象有一個geturl()方法。

from urllib.parse import urlparse

original = 'http://netloc/path;param?query=arg#frag'
print('ORIG  :', original)
parsed = urlparse(original)
print('PARSED:', parsed.geturl())

geturl()只適用於urlparse()或urlsplit()返回的對象。

利用urlunparse()可以將包含串的普通元組重新組合為一個URL。

from urllib.parse import urlparse, urlunparse

original = 'http://netloc/path;param?query=arg#frag'
print('ORIG  :', original)
parsed = urlparse(original)
print('PARSED:', type(parsed), parsed)
t = parsed[:]
print('TUPLE :', type(t), t)
print('NEW   :', urlunparse(t))

盡管urlparse()返回的ParseResult可以作為一個元組,但這個例子卻顯式地創建了一個新元組,來展示urlunparse()也適用於普通元組。

如果輸入URL包含多余的部分,那么重新構造的URL可能會將其去除。 

from urllib.parse import urlparse, urlunparse

original = 'http://netloc/path;?#'
print('ORIG  :', original)
parsed = urlparse(original)
print('PARSED:', type(parsed), parsed)
t = parsed[:]
print('TUPLE :', type(t), t)
print('NEW   :', urlunparse(t))

在這里,原URL中沒有參數、查詢和片段。新URL看起來與原URL並不相同,不過按照標准它們是等價的。

1.3 連接 

除了解析URL,urlparse還包括一個urljoin()方法,可以由相對片段構造絕對URL。

from urllib.parse import urljoin

print(urljoin('http://www.example.com/path/file.html',
              'anotherfile.html'))
print(urljoin('http://www.example.com/path/file.html',
              '../anotherfile.html'))

在這個例子中,計算第二個URL時要考慮路徑的相對部分("../")。

非相對路徑的處理與os.path.join()的處理方式相同。 

from urllib.parse import urljoin

print(urljoin('http://www.example.com/path/',
              '/subpath/file.html'))
print(urljoin('http://www.example.com/path/',
              'subpath/file.html'))

如果連接到URL的路徑以一個斜線開頭(/),那么urljoin()會把URL的路徑重置為頂級路徑。如果不是以一個斜線開頭,那么新路徑值則追加到URL當前路徑的末尾。

1.4 解碼查詢參數

參數在被增加到一個URL之前,需要先編碼。 

from urllib.parse import urlencode

query_args = {
    'q': 'query string',
    'foo': 'bar',
}
encoded_args = urlencode(query_args)
print('Encoded:', encoded_args)

編碼會替換諸如空格之類的特殊字符,以確保采用一種符合標准的格式將它們傳遞到服務器。

如果要利用查詢串中的變量傳遞一個值序列,那么需要在調用urlencode()時將doseq設置為True。

from urllib.parse import urlencode

query_args = {
    'foo': ['foo1', 'foo2'],
}
print('Single  :', urlencode(query_args))
print('Sequence:', urlencode(query_args, doseq=True))

結果是一個查詢串,包含與一個名關聯的多個值。

要解碼這個查詢串,可以使用parse_qs()或parse_qsl()。 

from urllib.parse import parse_qs, parse_qsl

encoded = 'foo=foo1&foo=foo2'

print('parse_qs :', parse_qs(encoded))
print('parse_qsl:', parse_qsl(encoded))

parse_qs()的返回值是一個將名映射到值的字典,而parse_qsl()返回一個元組列表,每個元組包含一個名和一個值。

查詢參數中可能有一些特殊字符,會導致服務器端在解析URL時出問題,所以在傳遞到urlencode()時要對這些特殊字符“加引號”。要在本地對它們加引號以建立這些串的安全版本,可以直接使用quote()或quote_plus()函數。

from urllib.parse import quote, quote_plus, urlencode

url = 'http://localhost:8080/~hellmann/'
print('urlencode() :', urlencode({'url': url}))
print('quote()     :', quote(url))
print('quote_plus():', quote_plus(url))

quote_plus()中的加引號實現會更大程度的替換字符。

 

要完成加引號操作的逆過程,可以在適當的時候使用unquote()或unquote_plus()。

from urllib.parse import unquote, unquote_plus

print(unquote('http%3A//localhost%3A8080/%7Ehellmann/'))
print(unquote_plus(
    'http%3A%2F%2Flocalhost%3A8080%2F%7Ehellmann%2F'
))

編碼的值會轉換回一個普通的URL串。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM