爬蟲基本庫:urllib

urllib

????在 python2 中,有 urllib 和 urllib2 兩個庫來實現請求的發送,而在 python3 中,統一為 urllib,官方文檔鏈接為:https://docs.python.org/3/library/urllib.html
????urllib 庫是 python 內置的HTTP請求庫,不需要額外安裝即可使用,包括以下4個模塊:

  • request:最基本的HTTP請求模塊,可以用來模擬發送請求,就像在瀏覽器里輸入網址然后回車一樣,只需要給庫方法傳入URL以及額外的參數,就可以模擬實現這個過程。
  • error:異常處理模塊,如果出現請求錯誤,我們可以捕獲這些異常,然后進行重試或其他操作以保證程序不會意外終止。
  • parse:一個工具模塊,提供了許多年URL方法,比如拆分、解析、合并等。
  • robotparser:主要是用來識別網站的 robots.txt 文件,然后判斷哪些網站可以爬,哪些網站不可以爬,用的比較少。

1. request模塊

1.1. urlopen()

????urlllib.request 模塊提供了最基本的構造 HTTP 求的方法,利用它可以模擬瀏覽器的一個請求發起過程,同時它還帶有處理授權驗證(authenticaton)、重定向(redirection)、瀏覽器 Cookies 及其他內容。

from urllib import request

# 抓取網頁源代碼并輸出
response = request.urlopen("https://www.python.org")
print(response.read().decode("utf-8"))
# 輸出response的類型    結果為 <class 'http.client.HTTPResponse'>
print(type(response))

????可以發現是一個HTTPResponse 類型的對象,主要包含 read()、readinto()、getheader(name)、getheaders()、fileno() 等方法,以及 msg、version、status、reason、debuglevel、closed 等屬性。
????得到這個對象之后,我們把它賦值為 response 變量,然后就可以調用這些方法和屬性,得到返回結果的一系列信息了。
????調用read()方法可以得到返回的網頁內容,調用status屬性可以得到返回結果的狀態碼,如200代表請求成功,404代表網頁未找到。

# 輸出相應的狀態碼
print(response.status)
# 200

# 調用getheaders()方法輸出響應頭信息
print(response.getheaders())
"""
[('Server', 'edge-esnssl-1.12.1-13'), ('Date', 'Fri, 23 Nov 2018 07:56:54 GMT'), ('Content-Type', 'text/html'), 
('Transfer-Encoding', 'chunked'), ('Connection', 'close'), ('Last-Modified', 'Fri, 23 Nov 2018 07:54:01 GMT'), 
('Vary', 'Accept-Encoding'), ('X-Powered-By', 'shci_v1.03'), ('Expires', 'Fri, 23 Nov 2018 07:57:54 GMT'), 
('Cache-Control', 'max-age=60'), ('Age', '0'), ('Via', 'https/1.1 ctc.ningbo.ha2ts4.74 (ApacheTrafficServer/6.2.1 [cMsSfW]), 
https/1.1 ctc.qingdao.ha2ts4.26 (ApacheTrafficServer/6.2.1 [cMsSfW])'), 
('X-Via-Edge', '154295981423876e0a07b3105f98c6dbeb1e9'), ('X-Cache', 'MISS.26'), 
('X-Via-CDN', 'f=edge,s=ctc.qingdao.edssl.45.nb.sinaedge.com,c=123.160.224.118;f=edge,
s=ctc.qingdao.ha2ts4.22.nb.sinaedge.com,c=140.249.5.45;f=Edge,s=ctc.qingdao.ha2ts4.26,
c=140.249.5.22;f=edge,s=ctc.ningbo.ha2ts4.73.nb.sinaedge.com,c=140.249.5.26;f=edge,
s=ctc.ningbo.ha2ts4.73.nb.sinaedge.com,c=115.238.190.73;f=Edge,s=ctc.ningbo.ha2ts4.74,c=115.238.190.73')]
"""

# 調用getheader()方法輸出響應頭的Server值
print(response.getheader('Server'))
# edge-esnssl-1.12.1-13

????如果需要給鏈接傳遞參數,該怎么做?下面是urlopen()函數的API(應用程序編程接口):

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)

????可以發現,除了第一個參數可以傳遞URL外,還可以傳遞其他內容,比如data(附加數據)、timeout(超時時間)等。

  • data參數
    ????data 參數是可選的,如果要添加該參數,并且如果它是字節流編碼格式的內容,即 bytes 類型,則需要通過 bytes() 方法轉化,該方法的第一個參數需要是 str(字符串)類型,需要用 urllib.parse 模塊里的 urlencode() 方法來將參數字典轉化為字符串。另外,如果傳遞了這個參數,則它的請求方式就不再是GET,而是POST方式。
  • timeout參數
    ????timeout 參數用于設置超時時間,單位為秒,意思就是如果請求超出了設置的這個時間,還沒有得到響應,就會拋出異常。如果不指定該參數,就會使用全局默認時間。它支持HTTP、 HTTPS、FTP請求。
from urllib import request

# 設置超時時間為1秒,1秒過后服務器沒有響應則跑出URLError異常,錯誤原因是超時
response = request.urlopen("url地址", timeout=1)
print(response.read())
  • 其他參數
    ????除data參數和timeout參數外,還有context參數必須是ssl.SSLContext類型,用來指定SSL設置。此外,cafile和capath這兩個參數分別制定CA證書和它的路徑,這個在請求HTTPS鏈接時有用。cadefault參數已經棄用,默認值為False。

urlopen()方法官方文檔:https://docs.python.org/3/library/urllib.request.html

1.2. Request

????urlopen() 方法可以實現最基本請求的發起,但幾個簡單的參數并不足以構建一個完整的請求。如果請求中需要加入Headers等信息,可以利用強大的Request類來構建。

from urllib import request

req = request.Request('url地址')
response = request.urlopen(req)
print(response.read().decode('utf-8'))

????依舊是用urlopen()方法來發送請求,不過這次的參數是一個Request類型的對象。通過構造這個數據結構,一方面我們可以將請求獨立成一個對象,另一方面可以更加豐富和靈活地配置參數。
????Request參數構造方法:

Class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
  • 第一個參數 url 用于請求URL,這是必傳參數,其他都是可選參數。
  • 第二個參數 data 如果要傳,必須傳 bytes(字節流)類型的,如果它是字典,可以先用 urllib.parse 模塊里的 urlencode() 編碼。
  • 第三個參數 headers 是一個字典,它就是請求頭,我們可以在構造請求是通過 headers 參數直接構造,也可以通過調用請求實例的 add_header() 方法添加。
    添加請求頭最常用的方法就是通過修改User_Agent 來偽裝瀏覽器,默認的User_Agent 是 Python_urllib,我們可以通過修改它來偽裝瀏覽器,比如偽裝火狐瀏覽器,可以設置為Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11
    headers還可以用 add_header() 方法來添加
req = request.Request(url=url, data=data, method='POST')
req.add_header('User-Agent', 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)')
  • 第四個參數 origin_req_host 指的是請求方的 host 名稱或者IP地址
  • 第五個參數 unverifiable 表示這個請求是否是無法驗證的,默認是 False ,意思就是說用戶沒有足夠權限來選擇接收這個請求的結果。例如,我們請求一個 HTML 文檔中的圖片,但是我們沒有向動抓取圖像的權限,這時 unverifiable 的值就是 True。
  • 第六個參數 method 是一個字符串,用來指示請求使用的方法,如GET、POST 和 PUT 等。

1.3. 高級用法

????處理器 Handler:處理登錄驗證、Cookies、代理設置。
????urllib.request 模塊里的 BaseHandler 類是所有其他 Handler 的父類,它提供了最基本的方法,例如 default_open()、protocol_request() 等。
????接下來,就有各種 Handler 子類繼承 BaseHandler 類:

  • HTTPDefaultErrorHandler:用于處理HTTP響應錯誤,錯誤都會拋出HTTPError類型的異常。
  • HTTPRedirectHandler:用于處理重定向。
  • HTTPCookieProcessor:用于處理Cookies。
  • ProxyHandler:用于設置代理,默認代理為空。
  • HTTPPasswordMgr:用于管理密碼,它維護了用戶名和密碼的表。
  • HTTPBasicAuthHandler:用于管理認證,如果一個鏈接打開時需要認證,那么可以用它來解決認證問題。

更多詳情見官方文檔:https://docs.python.org/3/library/urllib.request.html#urllib.request.BaseHandler

????另一個比較重要的類就是OpenerDirector,我們可以稱為Opener。之前的 urlopen() 方法就是 urllib 提供的一個 Opener 。
????之前的 Request 和 urlopen() 相當于類庫封裝好了常用的方法,利用它們可以完成基本的請求,但是想要實現更高級的功能,就需要深入一層進行配置,使用更底層的實例完成操作,所以就用到了Opener。
????Opener 可以使用 open() 方法,返回的類型和 urlopen() 如出一轍,那么它和Handler 有什么區別呢?簡而言之,就是利用 Handler 來構建 Opener。

  • 驗證
    ????有些網站打開時會彈出提示框,提示輸入賬號密碼驗證成功后才能查看頁面,那么,如果要請求這樣的頁面,需要借助 HTTPBasicAuthHandler 來完成:
from urllib.request import HTTPPasswordMgrWithDefaultRealm
from urllib.request import HTTPBasicAuthHandler
from urllib.request import build_opener
from urllib.error import URLError

username = 'username'
password = 'password'
url = 'http://localhost:5000/'

p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, url, username, password)
auth_handler = HTTPBasicAuthHandler(p)
opener = build_opener(auth_handler)

try:
    result = opener.open(url)
    html = result.read().decode('utf-8')
except URLError as e:
    print(e.reason)

????這里首先實例化 HTTPBasicAuthHandler 對象,其參數是 HTTPPasswordMgrWithDefaultRealm 對象,它利用 add_password() 添加進去用戶名和密碼,這樣就建立了一個處理驗證的 Handler。
????接下來利用這個 Handler 并使用 build_opener() 方法構建了一個 Opener ,這個 Opener 在發送請求就相當于已經驗證成功了。
????最后利用 Opener 的 open() 方法打開鏈接,就可以完成驗證獲取到頁面源碼內容。

  • 代理
    ????我們在做爬蟲的時候免不了要使用代理,添加代理時可以這樣做:
prom urllib.error import URLError
from urllib.request import ProxyHandler
from urllib.request import build_opener

proxy_handler = ProxyHandler({
    'http': 'http://127.0.0.1:9743',
    'https': 'https://127.0.0.1:9743'
})

opener = build_opener(proxy_handler)

try:
    response = opener.open('https://www.baidu.com')
    print(response.read().decode('utf-8'))
except URLError as e:
    print(e.reason)

????本地搭建代理,運行在9743端口。使用的 ProxyHandler 參數為一個字典,鍵名是協議類型(如HTTP或者HTTPS等),鍵值是代理鏈接,可以添加多個代理。之后利用 Handler 以及 build_opener() 方法構造一個 Opener ,之后發送請求即可。

  • Cookies
    ????Cookies 的處理需要相關的 Handler,用實例獲取網站的Cookies:
from http import cookiejar
from urllib import request

cookie = cookiejar.CookieJar()
handler = request.HTTPCookieProcessor(cookie)
opener = request.build_opener(handler)
response = opener.open('http://www.baidu.com')
for item in cookie:
    print(item.name + "=" + item.value)

????首先聲明一個 CookieJar 對象,然后利用 HTTPCookieProcessor 來創建一個 Handler,最后利用 build_opener() 方法構建出 Opener ,執行 open() 函數即可獲得。

運行結果如下:
BAIDUID=D467648C85174615BC257302C9AB32BF:FG=1
BIDUPSID=D467648C85174615BC257302C9AB32BF
H_PS_PSSID=1459_21119_26350_27508
PSTM=1543026564
delPer=0
BDSVRTM=0
BD_HOME=0

????Cookies 實際上是以文本形式保存的,所以也可以將其輸出為文件:

from http import cookiejar
from urllib import request

filename = 'cookies.txt'
cookie = cookiejar.MozillaCookieJar(filename)
handler = request.HTTPCookieProcessor(cookie)
opener = request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)

????MozillaCookieJar 是 CookieJar 的子類,在生成文件時會用到,可以用來處理 Cookies 和文件相關的事件,比如讀取和保存 Cookies ,可以將 Cookies 保存成 Mozilla 型瀏覽器的 Cookies 格式。
????運行后生成一個 cookies.txt 文件,其內容如下:

# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file! Do not edit.

.baidu.com TRUE / FALSE 3690511287 BAIDUID 681BB9746C6952E4B3BCFF5DD3E6560:FG=1
.baidu.com TRUE / FALSE 3690511287 BIDUPSID B681BB9746C6952E4B3BCFF5DD3E6560
.baidu.com TRUE / FALSE H_PS_PSSID 1427_21111_18560_22160
.baidu.com TRUE / FALSE 3690511287 PSTM 1543027641
.baidu.com TRUE / FALSE delPer 0
www.baidu.com FALSE / FALSE BDSVRTM 0
www.baidu.com FALSE / FALSE BD_HOME 0

2. 處理異常

????在網絡不好的情況下,如果出現了異常,該怎么辦?這時如果不處理這些異常,程序很可能因報錯而終止運行,所以異常處理還是十分有必要的。
????urllib 的 error 模塊定義了由 request 模塊產生的異常。如果出現了問題,request 模塊便會拋出 error 模塊中定義的異常。

2.1. URLError

????URLError 類來自 urllib 庫的 error 模塊,它繼承自 OSError 類,是 error 異常模塊的基類,由 request 模塊產生的異常都可以通過捕獲這個類來處理。它具有一個屬性 reason,即返回錯誤的原因。

from urllib import request
from urllib import error

try:
    response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.URLError as e:
    print(e.reason)

????打開一個不存在的頁面照理來說應該會報錯,但是這時我們捕獲了 URLError 這個異常,運行結果如下:
????????Not Found
????程序沒有直接報錯,而是輸出了如上內容,這樣通過如上操作,我們就可以避免程序異常終止,同時異常得到了有效處理。

2.2. HTTPError

????它是 URLError 的子類,專門用來處理 HTTP 請求錯誤,比如認證請求失敗等。 它有如下3個屬性:

  • code:返回 HTTP 狀態碼,比如 404 表示網頁不存在, 500 表示服務器內部錯誤等。
  • reason:同父類一樣,用于返回錯誤的原因。
  • headers:返回請求頭。
from urllib import error
from urllib import request

try:
    response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.HTTPError as e:
    print(e.reason, e.code, e.headers)

Not Found
404
Server: nginx/1.10.3 (Ubuntu)
Date: Sat, 24 Nov 2018 03:28:20 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: close
Vary: Cookie
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Link: https://cuiqingcai.com/wp-json/; rel="https://api.w.org/"

????是同樣的網址,這里捕獲了 HTTPError 異常,輸出了 reason,code,headers 屬性。
????因為 URLError 是 HTTPError 的父類,所以可以先選擇捕獲子類的錯誤,再去捕獲父類的錯誤,所以上述代碼更好的寫法如下:

from urllib import error
from urllib import request

try:
    response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.HTTPError as e:
    print(e.reason, e.code, e.headers)
except error.URLError as e:
    print(e.reason)
else:
    print('Request Successfully!')

????這樣就可以做到先捕獲 HTTPError ,獲取它的錯誤狀態碼 、原因、headers 等信息。如果不是 HTTPError 異常,就會捕獲 URLError 異常,輸出錯誤原因。最后,用 else 來處理正常的邏輯。
????有時候,reason 屬性返回的不一定是字符串,也可能是一個對象:

import socket
from urllib import error
from urllib import request

try:
    response = request.urlopen('https://www.baidu.com', timeout=0.01)
except error.URLError as e:
    print(type(e.reason))
    if isinstance(e.reason, socket.timeout):
        print('Time Out!')

????直接設置超時時間強制拋出 timeout 異常

<class 'socket.timeout'>
Time Out!

????可以發現,reason 屬性的結果是 socket.timeout 類,可以用 isinstance() 方法來判斷它的類型,作出更詳細的異常判斷。

3. 解析鏈接

????urllib 庫里還提供了 parse 模塊,它定義了處理 URL 的標準接口,例如實現 URL 各部分的抽取、合并以及鏈接轉換。它支持如下協議的 URL 處理:file、gopher、hdl、http、https、imap、mailto、mms、news、nntp、prospero、rsync、rtsp、rtspu、sftp、sip、sips、snews、svn、svn+ssh、telnet 和 wais。本節介紹一下該模塊中常用的方法。

3.1. urlparse()

????該方法實現了URL的識別與分段

from urllib.parse import urlparse

result = urlparse('http://www.baidu.com/index.html;user?id=5#comment')
print(type(result), result)

<class 'urllib.parse.ParseResult'>
ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')
返回結果是一個 ParseResult 類型的對象,它包含6個部分,分別是 scheme、netloc、path、params、query、fragment。

????urlparse() 方法將其拆分成了6個部分。大體觀察可以發現,解析時有特定的分隔符。比如,:// 前面的就是 scheme,代表協議;第一個 / 符號前面便是 netloc,即域名;后面是 path ,即訪問路徑;分號 ; 前面是 params ,代表參數;問號?后面是查詢條件 query,一般用作 GET 類型的 URL;井號#后面是錨點,用于直接定位頁面內部的下拉位置。
????所以,可以得出一個標準的鏈接格式,具體如下:

scheme://netloc/path;params?query#fragment

????除了這種最基本的解析方式外,urlparse() 方法還有其他配置。它的 API 用法:

urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)

有三個參數:
  • urlstring:這是必填項,待解析的URL
  • scheme:默認的協議(如 HTTP 或 HTTPS 等),假如鏈接沒有帶協議信息,會將這個作為默認的協議
from urllib.parse import urlparse

result = urlparse('www.baidu.com/index.html;user?id=5#comment', scheme='https')
print(result)

運行結果:
ParseResult(scheme='https', netloc='', path='www.baidu.com/index.html', params='user', query='id=5', fragment='comment')
提供的URL沒有包含 scheme 信息,但是通過指定的 scheme 默認參數,返回的結果是https。

# 參數中帶上scheme
from urllib.parse import urlparse

result = urlparse('http://www.baidu.com/index.html;user?id=5#comment', scheme='https')
print(result)

運行結果
ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')
有結果可見,scheme 只有在 URL 中不包含 scheme 信息時才生效;如果 URL 中包含 scheme,則會解析出 URL 本身的 scheme。

  • allow_fragments:即是否忽略 fragment。如果設置為False,fragment 部分內容就會被忽略,它會被解析為path、parameters 或者 query 的一部分,而 fragment 部分為空。
from urllib.parse import urlparse

result = urlparse('http://www.baidu.com/index.html;user?id=5#comment', allow_fragments=False)
print(result)
# ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5#comment', fragment='')
from urllib.parse import urlparse

result1 = urlparse('http://www.baidu.com/index.html#comment', allow_fragments=False)
print(result1)
# ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html#comment', params='', query='', fragment='')
# 當 URL 中不包含 params 和 query 時,fragment 會被解析為 path 的一部分
# 返回結果 ParseResult 是一個元組,可以通過索引或屬性名來獲取
# print(result.scheme, result[0], result.netloc, result[1])
# http   http     www.baidu.com   www.baidu.com

3.2. urlunparse()

????相對于 urlparse() 的解析鏈接,自然有另一種構造鏈接的方法:urlunparse(),它接受的參數是一個可迭代對象,但是長度必須是6,否則會拋出參數數量不足或者過多的問題。

from urllib.parse import urlunparse

data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
print(urlunparse(data))
# http://www.baidu.com/index.html;user?a=6#comment

????參數 data 用了列表類型,也可以用元組或特定的數據結構,這樣就實現了 URL 的構造。

3.3. urlsplit()

????這個方法和 urlparse() 方法非常相似,只不過它不再單獨解析 params 這一部分,只返回5個結果。上面例子中的 params 會合并到 path 中,示例如下:

from urllib.parse import urlsplit

result = urlsplit('http://www.baidu.com/index.html;user?id=5#comment')
print(result)
#SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment')

????返回結果 SplitResult 是一個元組類型,可以通過屬性值或索引來獲取。

from urllib.parse import urlsplit

result = urlsplit('http://www.baidu.com/index.html;user?id=5#comment')
print(result.scheme, result[0])
# http  http

3.4. urlunsplit()

????與 urlunparse() 類似,這是將鏈接各個部分組合成完整鏈接的方法,傳入的參數也是一個可迭代對象,例如列表、元組等,唯一的區別是長度必須是5,。

from urllib.parse import urlunsplit

data = ['http', 'www.baidu.com', 'index.html', 'a=6', 'comment']
print(urlunsplit(data))
# http://www.baidu.com/index.html?a=6#comment

3.5. urljoin()

????有了 urlunparse() 和 urlunsplit() 方法,我們可以完成鏈接的合井,不過前提必須要有特定長度的對象,鏈接的每一部分都要清晰分開。
????此外,生成鏈接還有另一個方法,那就是 urljoin() 方法。我們可以提供一個 base_url(基礎鏈接)作為第一個參數,將新的鏈接作為第二個參數,該方法會分析 base_url 的 scheme、netloc、path 這3個內容并對新鏈接缺失的部分進行補充,最后返回結果。

from urllib.parse import urljoin

print(urljoin('http://www.baidu.com', 'PAQ.html'))
print(urljoin('http://www.baidu.com', 'https://cuiqinghai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://cuiqinghai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://cuiqinghai.com/FAQ.html?question=2'))
print(urljoin('http://www.baidu.com?wd=abc', 'https://cuiqinghai.com/index.php'))
print(urljoin('http://www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com#comment', '?category=2'))

運行結果為:
http://www.baidu.com/PAQ.html
https://cuiqinghai.com/FAQ.html
https://cuiqinghai.com/FAQ.html
https://cuiqinghai.com/FAQ.html?question=2
https://cuiqinghai.com/index.php
http://www.baidu.com?category=2#comment
www.baidu.com?category=2#comment
www.baidu.com?category=2

????可以發現,base_url 提供了三項內容 scheme、netloc、path。如果這3項在新的鏈接里不存在,就予以補充;如果新的鏈接存在,就使用新的鏈接的部分。而 base_url 中的 params、 query、fragment 是不起作用的。通過 urljoin() 方法,可以輕松實現鏈接的解析、拼合與生成。

3.6. urlencode()

????構造 GET 請求參數時可以將 params 參數字典序列化成 GET 請求參數。

from urllib.parse import urlencode

params = {
    'name': 'germey',
    'age': 22
}
base_url = 'http://www.baidu.com?'
url = base_url + urlencode(params)
print(url)
# http://www.baidu.com?name=germey&age=22

3.7. parse_qs()

????有了序列化,必然就有反序列化。如果我們有一串 GET 請求參數,利用 parse_qs()方法, 就可以將它轉回字典,示例如下:

from urllib.parse import parse_qs

query = 'name=germey&age=22'
print(parse_qs(query))
# {'name': ['germey'], 'age': ['22']}

3.8. parse_qsl()

????parse_qsl() 方法用于將參數轉化為元組組成的列表,運行結果是一個列表,而列表中的每一個元素都是一個元組,元組的第一個內容是參數名,第二個內容是參數值。

from urllib.parse import parse_qsl

query = 'name=germey&age=22'
print(parse_qsl(query))
# [('name', 'germey'), ('age', '22')]

3.9. quote()

????該方法可以將內容轉化為 URL 編碼的格式 URL 中帶有中文參數時,有時可能會導致亂碼的問題,此時用這個方法可以將巾文字符轉化為 URL 編碼。

from urllib.parse import quote

keyword = '壁紙'
url = 'https://www.baidu.com/s?wd=' + quote(keyword)
print(url)
# https://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8

3.10. unquote()

????URL 解碼方法,上面的編碼結果用 unquote() 方法還原:

from urllib.parse import unquote

url = 'https://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8'
print(unquote(url))
# https://www.baidu.com/s?wd=壁紙
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,296評論 2 376

推薦閱讀更多精彩內容