urllib
????在 python2 中,有 urllib 和 urllib2 兩個(gè)庫(kù)來(lái)實(shí)現(xiàn)請(qǐng)求的發(fā)送驶赏,而在 python3 中嚼锄,統(tǒng)一為 urllib场刑,官方文檔鏈接為:https://docs.python.org/3/library/urllib.html
????urllib 庫(kù)是 python 內(nèi)置的HTTP請(qǐng)求庫(kù)肩民,不需要額外安裝即可使用唠亚,包括以下4個(gè)模塊:
- request:最基本的HTTP請(qǐng)求模塊,可以用來(lái)模擬發(fā)送請(qǐng)求持痰,就像在瀏覽器里輸入網(wǎng)址然后回車一樣灶搜,只需要給庫(kù)方法傳入U(xiǎn)RL以及額外的參數(shù),就可以模擬實(shí)現(xiàn)這個(gè)過程工窍。
- error:異常處理模塊割卖,如果出現(xiàn)請(qǐng)求錯(cuò)誤,我們可以捕獲這些異常患雏,然后進(jìn)行重試或其他操作以保證程序不會(huì)意外終止鹏溯。
- parse:一個(gè)工具模塊,提供了許多年URL方法纵苛,比如拆分剿涮、解析言津、合并等攻人。
- robotparser:主要是用來(lái)識(shí)別網(wǎng)站的 robots.txt 文件取试,然后判斷哪些網(wǎng)站可以爬,哪些網(wǎng)站不可以爬怀吻,用的比較少瞬浓。
1. request模塊
1.1. urlopen()
????urlllib.request 模塊提供了最基本的構(gòu)造 HTTP 求的方法,利用它可以模擬瀏覽器的一個(gè)請(qǐng)求發(fā)起過程蓬坡,同時(shí)它還帶有處理授權(quán)驗(yàn)證(authenticaton)猿棉、重定向(redirection)、瀏覽器 Cookies 及其他內(nèi)容屑咳。
from urllib import request
# 抓取網(wǎng)頁(yè)源代碼并輸出
response = request.urlopen("https://www.python.org")
print(response.read().decode("utf-8"))
# 輸出response的類型 結(jié)果為 <class 'http.client.HTTPResponse'>
print(type(response))
????可以發(fā)現(xiàn)是一個(gè)HTTPResponse 類型的對(duì)象萨赁,主要包含 read()、readinto()兆龙、getheader(name)杖爽、getheaders()、fileno() 等方法紫皇,以及 msg慰安、version、status聪铺、reason化焕、debuglevel、closed 等屬性铃剔。
????得到這個(gè)對(duì)象之后撒桨,我們把它賦值為 response 變量,然后就可以調(diào)用這些方法和屬性键兜,得到返回結(jié)果的一系列信息了凤类。
????調(diào)用read()方法可以得到返回的網(wǎng)頁(yè)內(nèi)容,調(diào)用status屬性可以得到返回結(jié)果的狀態(tài)碼蝶押,如200代表請(qǐng)求成功踱蠢,404代表網(wǎng)頁(yè)未找到。
# 輸出相應(yīng)的狀態(tài)碼
print(response.status)
# 200
# 調(diào)用getheaders()方法輸出響應(yīng)頭信息
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')]
"""
# 調(diào)用getheader()方法輸出響應(yīng)頭的Server值
print(response.getheader('Server'))
# edge-esnssl-1.12.1-13
????如果需要給鏈接傳遞參數(shù)棋电,該怎么做茎截?下面是urlopen()函數(shù)的API(應(yīng)用程序編程接口):
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
????可以發(fā)現(xiàn),除了第一個(gè)參數(shù)可以傳遞URL外赶盔,還可以傳遞其他內(nèi)容企锌,比如data(附加數(shù)據(jù))、timeout(超時(shí)時(shí)間)等于未。
- data參數(shù)
????data 參數(shù)是可選的撕攒,如果要添加該參數(shù)陡鹃,并且如果它是字節(jié)流編碼格式的內(nèi)容,即 bytes 類型抖坪,則需要通過 bytes() 方法轉(zhuǎn)化萍鲸,該方法的第一個(gè)參數(shù)需要是 str(字符串)類型,需要用 urllib.parse 模塊里的 urlencode() 方法來(lái)將參數(shù)字典轉(zhuǎn)化為字符串擦俐。另外脊阴,如果傳遞了這個(gè)參數(shù),則它的請(qǐng)求方式就不再是GET蚯瞧,而是POST方式嘿期。 - timeout參數(shù)
????timeout 參數(shù)用于設(shè)置超時(shí)時(shí)間,單位為秒埋合,意思就是如果請(qǐng)求超出了設(shè)置的這個(gè)時(shí)間备徐,還沒有得到響應(yīng),就會(huì)拋出異常甚颂。如果不指定該參數(shù)蜜猾,就會(huì)使用全局默認(rèn)時(shí)間。它支持HTTP西设、 HTTPS瓣铣、FTP請(qǐng)求。
from urllib import request
# 設(shè)置超時(shí)時(shí)間為1秒贷揽,1秒過后服務(wù)器沒有響應(yīng)則跑出URLError異常棠笑,錯(cuò)誤原因是超時(shí)
response = request.urlopen("url地址", timeout=1)
print(response.read())
- 其他參數(shù)
????除data參數(shù)和timeout參數(shù)外,還有context參數(shù)必須是ssl.SSLContext類型禽绪,用來(lái)指定SSL設(shè)置蓖救。此外,cafile和capath這兩個(gè)參數(shù)分別制定CA證書和它的路徑印屁,這個(gè)在請(qǐng)求HTTPS鏈接時(shí)有用循捺。cadefault參數(shù)已經(jīng)棄用,默認(rèn)值為False雄人。
urlopen()方法官方文檔:https://docs.python.org/3/library/urllib.request.html
1.2. Request
????urlopen() 方法可以實(shí)現(xiàn)最基本請(qǐng)求的發(fā)起从橘,但幾個(gè)簡(jiǎn)單的參數(shù)并不足以構(gòu)建一個(gè)完整的請(qǐng)求。如果請(qǐng)求中需要加入Headers等信息础钠,可以利用強(qiáng)大的Request類來(lái)構(gòu)建恰力。
from urllib import request
req = request.Request('url地址')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
????依舊是用urlopen()方法來(lái)發(fā)送請(qǐng)求,不過這次的參數(shù)是一個(gè)Request類型的對(duì)象旗吁。通過構(gòu)造這個(gè)數(shù)據(jù)結(jié)構(gòu)踩萎,一方面我們可以將請(qǐng)求獨(dú)立成一個(gè)對(duì)象,另一方面可以更加豐富和靈活地配置參數(shù)很钓。
????Request參數(shù)構(gòu)造方法:
Class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
- 第一個(gè)參數(shù) url 用于請(qǐng)求URL香府,這是必傳參數(shù)董栽,其他都是可選參數(shù)。
- 第二個(gè)參數(shù) data 如果要傳企孩,必須傳 bytes(字節(jié)流)類型的锭碳,如果它是字典,可以先用 urllib.parse 模塊里的 urlencode() 編碼柠硕。
- 第三個(gè)參數(shù) headers 是一個(gè)字典工禾,它就是請(qǐng)求頭运提,我們可以在構(gòu)造請(qǐng)求是通過 headers 參數(shù)直接構(gòu)造蝗柔,也可以通過調(diào)用請(qǐng)求實(shí)例的 add_header() 方法添加。
添加請(qǐng)求頭最常用的方法就是通過修改User_Agent 來(lái)偽裝瀏覽器民泵,默認(rèn)的User_Agent 是 Python_urllib癣丧,我們可以通過修改它來(lái)偽裝瀏覽器,比如偽裝火狐瀏覽器栈妆,可以設(shè)置為Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11
headers還可以用 add_header() 方法來(lái)添加
req = request.Request(url=url, data=data, method='POST')
req.add_header('User-Agent', 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)')
- 第四個(gè)參數(shù) origin_req_host 指的是請(qǐng)求方的 host 名稱或者IP地址
- 第五個(gè)參數(shù) unverifiable 表示這個(gè)請(qǐng)求是否是無(wú)法驗(yàn)證的胁编,默認(rèn)是 False ,意思就是說用戶沒有足夠權(quán)限來(lái)選擇接收這個(gè)請(qǐng)求的結(jié)果鳞尔。例如嬉橙,我們請(qǐng)求一個(gè) HTML 文檔中的圖片,但是我們沒有向動(dòng)抓取圖像的權(quán)限寥假,這時(shí) unverifiable 的值就是 True市框。
- 第六個(gè)參數(shù) method 是一個(gè)字符串,用來(lái)指示請(qǐng)求使用的方法糕韧,如GET枫振、POST 和 PUT 等。
1.3. 高級(jí)用法
????處理器 Handler:處理登錄驗(yàn)證萤彩、Cookies粪滤、代理設(shè)置。
????urllib.request 模塊里的 BaseHandler 類是所有其他 Handler 的父類雀扶,它提供了最基本的方法杖小,例如 default_open()、protocol_request() 等愚墓。
????接下來(lái)予权,就有各種 Handler 子類繼承 BaseHandler 類:
- HTTPDefaultErrorHandler:用于處理HTTP響應(yīng)錯(cuò)誤,錯(cuò)誤都會(huì)拋出HTTPError類型的異常转绷。
- HTTPRedirectHandler:用于處理重定向伟件。
- HTTPCookieProcessor:用于處理Cookies。
- ProxyHandler:用于設(shè)置代理议经,默認(rèn)代理為空斧账。
- HTTPPasswordMgr:用于管理密碼谴返,它維護(hù)了用戶名和密碼的表。
- HTTPBasicAuthHandler:用于管理認(rèn)證咧织,如果一個(gè)鏈接打開時(shí)需要認(rèn)證嗓袱,那么可以用它來(lái)解決認(rèn)證問題。
更多詳情見官方文檔:https://docs.python.org/3/library/urllib.request.html#urllib.request.BaseHandler
????另一個(gè)比較重要的類就是OpenerDirector习绢,我們可以稱為Opener渠抹。之前的 urlopen() 方法就是 urllib 提供的一個(gè) Opener 。
????之前的 Request 和 urlopen() 相當(dāng)于類庫(kù)封裝好了常用的方法闪萄,利用它們可以完成基本的請(qǐng)求梧却,但是想要實(shí)現(xiàn)更高級(jí)的功能,就需要深入一層進(jìn)行配置败去,使用更底層的實(shí)例完成操作放航,所以就用到了Opener。
????Opener 可以使用 open() 方法圆裕,返回的類型和 urlopen() 如出一轍广鳍,那么它和Handler 有什么區(qū)別呢?簡(jiǎn)而言之吓妆,就是利用 Handler 來(lái)構(gòu)建 Opener赊时。
- 驗(yàn)證
????有些網(wǎng)站打開時(shí)會(huì)彈出提示框,提示輸入賬號(hào)密碼驗(yàn)證成功后才能查看頁(yè)面行拢,那么祖秒,如果要請(qǐng)求這樣的頁(yè)面,需要借助 HTTPBasicAuthHandler 來(lái)完成:
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)
????這里首先實(shí)例化 HTTPBasicAuthHandler 對(duì)象剂陡,其參數(shù)是 HTTPPasswordMgrWithDefaultRealm 對(duì)象狈涮,它利用 add_password() 添加進(jìn)去用戶名和密碼,這樣就建立了一個(gè)處理驗(yàn)證的 Handler鸭栖。
????接下來(lái)利用這個(gè) Handler 并使用 build_opener() 方法構(gòu)建了一個(gè) Opener 歌馍,這個(gè) Opener 在發(fā)送請(qǐng)求就相當(dāng)于已經(jīng)驗(yàn)證成功了。
????最后利用 Opener 的 open() 方法打開鏈接晕鹊,就可以完成驗(yàn)證獲取到頁(yè)面源碼內(nèi)容松却。
- 代理
????我們?cè)谧雠老x的時(shí)候免不了要使用代理,添加代理時(shí)可以這樣做:
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)
????本地搭建代理溅话,運(yùn)行在9743端口晓锻。使用的 ProxyHandler 參數(shù)為一個(gè)字典,鍵名是協(xié)議類型(如HTTP或者HTTPS等)飞几,鍵值是代理鏈接砚哆,可以添加多個(gè)代理。之后利用 Handler 以及 build_opener() 方法構(gòu)造一個(gè) Opener 屑墨,之后發(fā)送請(qǐng)求即可躁锁。
- Cookies
????Cookies 的處理需要相關(guān)的 Handler纷铣,用實(shí)例獲取網(wǎng)站的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)
????首先聲明一個(gè) CookieJar 對(duì)象,然后利用 HTTPCookieProcessor 來(lái)創(chuàng)建一個(gè) Handler战转,最后利用 build_opener() 方法構(gòu)建出 Opener 搜立,執(zhí)行 open() 函數(shù)即可獲得。
運(yùn)行結(jié)果如下:
BAIDUID=D467648C85174615BC257302C9AB32BF:FG=1
BIDUPSID=D467648C85174615BC257302C9AB32BF
H_PS_PSSID=1459_21119_26350_27508
PSTM=1543026564
delPer=0
BDSVRTM=0
BD_HOME=0
????Cookies 實(shí)際上是以文本形式保存的槐秧,所以也可以將其輸出為文件:
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 的子類啄踊,在生成文件時(shí)會(huì)用到,可以用來(lái)處理 Cookies 和文件相關(guān)的事件刁标,比如讀取和保存 Cookies 颠通,可以將 Cookies 保存成 Mozilla 型瀏覽器的 Cookies 格式。
????運(yùn)行后生成一個(gè) cookies.txt 文件命雀,其內(nèi)容如下:
# 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. 處理異常
????在網(wǎng)絡(luò)不好的情況下蒜哀,如果出現(xiàn)了異常,該怎么辦吏砂?這時(shí)如果不處理這些異常,程序很可能因報(bào)錯(cuò)而終止運(yùn)行乘客,所以異常處理還是十分有必要的狐血。
????urllib 的 error 模塊定義了由 request 模塊產(chǎn)生的異常。如果出現(xiàn)了問題易核,request 模塊便會(huì)拋出 error 模塊中定義的異常匈织。
2.1. URLError
????URLError 類來(lái)自 urllib 庫(kù)的 error 模塊,它繼承自 OSError 類牡直,是 error 異常模塊的基類缀匕,由 request 模塊產(chǎn)生的異常都可以通過捕獲這個(gè)類來(lái)處理。它具有一個(gè)屬性 reason碰逸,即返回錯(cuò)誤的原因乡小。
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)
????打開一個(gè)不存在的頁(yè)面照理來(lái)說應(yīng)該會(huì)報(bào)錯(cuò),但是這時(shí)我們捕獲了 URLError 這個(gè)異常饵史,運(yùn)行結(jié)果如下:
????????Not Found
????程序沒有直接報(bào)錯(cuò)满钟,而是輸出了如上內(nèi)容,這樣通過如上操作胳喷,我們就可以避免程序異常終止湃番,同時(shí)異常得到了有效處理。
2.2. HTTPError
????它是 URLError 的子類吭露,專門用來(lái)處理 HTTP 請(qǐng)求錯(cuò)誤吠撮,比如認(rèn)證請(qǐng)求失敗等。 它有如下3個(gè)屬性:
- code:返回 HTTP 狀態(tài)碼讲竿,比如 404 表示網(wǎng)頁(yè)不存在泥兰, 500 表示服務(wù)器內(nèi)部錯(cuò)誤等择浊。
- reason:同父類一樣,用于返回錯(cuò)誤的原因逾条。
- headers:返回請(qǐng)求頭琢岩。
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/"
????是同樣的網(wǎng)址,這里捕獲了 HTTPError 異常师脂,輸出了 reason担孔,code,headers 屬性吃警。
????因?yàn)?URLError 是 HTTPError 的父類糕篇,所以可以先選擇捕獲子類的錯(cuò)誤,再去捕獲父類的錯(cuò)誤酌心,所以上述代碼更好的寫法如下:
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 拌消,獲取它的錯(cuò)誤狀態(tài)碼 、原因安券、headers 等信息墩崩。如果不是 HTTPError 異常,就會(huì)捕獲 URLError 異常侯勉,輸出錯(cuò)誤原因鹦筹。最后,用 else 來(lái)處理正常的邏輯址貌。
????有時(shí)候铐拐,reason 屬性返回的不一定是字符串,也可能是一個(gè)對(duì)象:
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!')
????直接設(shè)置超時(shí)時(shí)間強(qiáng)制拋出 timeout 異常
<class 'socket.timeout'>
Time Out!
????可以發(fā)現(xiàn)练对,reason 屬性的結(jié)果是 socket.timeout 類遍蟋,可以用 isinstance() 方法來(lái)判斷它的類型,作出更詳細(xì)的異常判斷螟凭。
3. 解析鏈接
????urllib 庫(kù)里還提供了 parse 模塊虚青,它定義了處理 URL 的標(biāo)準(zhǔn)接口,例如實(shí)現(xiàn) URL 各部分的抽取赂摆、合并以及鏈接轉(zhuǎn)換挟憔。它支持如下協(xié)議的 URL 處理:file、gopher烟号、hdl绊谭、http、https汪拥、imap达传、mailto、mms、news宪赶、nntp宗弯、prospero、rsync搂妻、rtsp蒙保、rtspu、sftp欲主、sip邓厕、sips、snews扁瓢、svn详恼、svn+ssh、telnet 和 wais引几。本節(jié)介紹一下該模塊中常用的方法昧互。
3.1. urlparse()
????該方法實(shí)現(xiàn)了URL的識(shí)別與分段
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')
返回結(jié)果是一個(gè) ParseResult 類型的對(duì)象,它包含6個(gè)部分伟桅,分別是 scheme敞掘、netloc、path贿讹、params渐逃、query、fragment民褂。
????urlparse() 方法將其拆分成了6個(gè)部分。大體觀察可以發(fā)現(xiàn)疯潭,解析時(shí)有特定的分隔符赊堪。比如,:// 前面的就是 scheme竖哩,代表協(xié)議哭廉;第一個(gè) / 符號(hào)前面便是 netloc,即域名相叁;后面是 path 遵绰,即訪問路徑;分號(hào) ; 前面是 params 增淹,代表參數(shù)椿访;問號(hào)?后面是查詢條件 query,一般用作 GET 類型的 URL虑润;井號(hào)#后面是錨點(diǎn)成玫,用于直接定位頁(yè)面內(nèi)部的下拉位置。
????所以,可以得出一個(gè)標(biāo)準(zhǔn)的鏈接格式哭当,具體如下:
????除了這種最基本的解析方式外猪腕,urlparse() 方法還有其他配置。它的 API 用法:
urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
有三個(gè)參數(shù):
- urlstring:這是必填項(xiàng)钦勘,待解析的URL
- scheme:默認(rèn)的協(xié)議(如 HTTP 或 HTTPS 等)陋葡,假如鏈接沒有帶協(xié)議信息,會(huì)將這個(gè)作為默認(rèn)的協(xié)議
from urllib.parse import urlparse
result = urlparse('www.baidu.com/index.html;user?id=5#comment', scheme='https')
print(result)
運(yùn)行結(jié)果:
ParseResult(scheme='https', netloc='', path='www.baidu.com/index.html', params='user', query='id=5', fragment='comment')
提供的URL沒有包含 scheme 信息彻采,但是通過指定的 scheme 默認(rèn)參數(shù)腐缤,返回的結(jié)果是https。
# 參數(shù)中帶上scheme
from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html;user?id=5#comment', scheme='https')
print(result)
運(yùn)行結(jié)果
ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')
有結(jié)果可見颊亮,scheme 只有在 URL 中不包含 scheme 信息時(shí)才生效柴梆;如果 URL 中包含 scheme,則會(huì)解析出 URL 本身的 scheme终惑。
- allow_fragments:即是否忽略 fragment绍在。如果設(shè)置為False,fragment 部分內(nèi)容就會(huì)被忽略雹有,它會(huì)被解析為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='')
# 當(dāng) URL 中不包含 params 和 query 時(shí)溜宽,fragment 會(huì)被解析為 path 的一部分
# 返回結(jié)果 ParseResult 是一個(gè)元組,可以通過索引或?qū)傩悦麃?lái)獲取
# print(result.scheme, result[0], result.netloc, result[1])
# http http www.baidu.com www.baidu.com
3.2. urlunparse()
????相對(duì)于 urlparse() 的解析鏈接质帅,自然有另一種構(gòu)造鏈接的方法:urlunparse()适揉,它接受的參數(shù)是一個(gè)可迭代對(duì)象,但是長(zhǎng)度必須是6煤惩,否則會(huì)拋出參數(shù)數(shù)量不足或者過多的問題嫉嘀。
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
????參數(shù) data 用了列表類型,也可以用元組或特定的數(shù)據(jù)結(jié)構(gòu)魄揉,這樣就實(shí)現(xiàn)了 URL 的構(gòu)造剪侮。
3.3. urlsplit()
????這個(gè)方法和 urlparse() 方法非常相似,只不過它不再單獨(dú)解析 params 這一部分洛退,只返回5個(gè)結(jié)果瓣俯。上面例子中的 params 會(huì)合并到 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')
????返回結(jié)果 SplitResult 是一個(gè)元組類型兵怯,可以通過屬性值或索引來(lái)獲取彩匕。
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() 類似,這是將鏈接各個(gè)部分組合成完整鏈接的方法摇零,傳入的參數(shù)也是一個(gè)可迭代對(duì)象推掸,例如列表桶蝎、元組等,唯一的區(qū)別是長(zhǎng)度必須是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() 方法登渣,我們可以完成鏈接的合井,不過前提必須要有特定長(zhǎng)度的對(duì)象毡泻,鏈接的每一部分都要清晰分開胜茧。
????此外,生成鏈接還有另一個(gè)方法仇味,那就是 urljoin() 方法呻顽。我們可以提供一個(gè) base_url(基礎(chǔ)鏈接)作為第一個(gè)參數(shù),將新的鏈接作為第二個(gè)參數(shù)丹墨,該方法會(huì)分析 base_url 的 scheme廊遍、netloc、path 這3個(gè)內(nèi)容并對(duì)新鏈接缺失的部分進(jìn)行補(bǔ)充贩挣,最后返回結(jié)果喉前。
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'))
運(yùn)行結(jié)果為:
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
????可以發(fā)現(xiàn),base_url 提供了三項(xiàng)內(nèi)容 scheme王财、netloc卵迂、path。如果這3項(xiàng)在新的鏈接里不存在绒净,就予以補(bǔ)充见咒;如果新的鏈接存在,就使用新的鏈接的部分挂疆。而 base_url 中的 params改览、 query、fragment 是不起作用的缤言。通過 urljoin() 方法恃疯,可以輕松實(shí)現(xiàn)鏈接的解析、拼合與生成墨闲。
3.6. urlencode()
????構(gòu)造 GET 請(qǐng)求參數(shù)時(shí)可以將 params 參數(shù)字典序列化成 GET 請(qǐng)求參數(shù)。
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 請(qǐng)求參數(shù),利用 parse_qs()方法犬性, 就可以將它轉(zhuǎn)回字典瞻离,示例如下:
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() 方法用于將參數(shù)轉(zhuǎn)化為元組組成的列表,運(yùn)行結(jié)果是一個(gè)列表乒裆,而列表中的每一個(gè)元素都是一個(gè)元組套利,元組的第一個(gè)內(nèi)容是參數(shù)名,第二個(gè)內(nèi)容是參數(shù)值。
from urllib.parse import parse_qsl
query = 'name=germey&age=22'
print(parse_qsl(query))
# [('name', 'germey'), ('age', '22')]
3.9. quote()
????該方法可以將內(nèi)容轉(zhuǎn)化為 URL 編碼的格式 URL 中帶有中文參數(shù)時(shí)肉迫,有時(shí)可能會(huì)導(dǎo)致亂碼的問題验辞,此時(shí)用這個(gè)方法可以將巾文字符轉(zhuǎn)化為 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 解碼方法喊衫,上面的編碼結(jié)果用 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=壁紙