Python urllib、urllib2、urllib3用法及區別

簡介1

在可供使用的網絡庫中,urlliburllib2可能是投入產出比最高的兩個,是Python中操作url的官方標準庫。它們讓你能夠通過網絡訪問文件,就像這些文件位於你的計算機中一樣。只需一個簡單的函數調用,就幾乎可將統一資源定位符(URL)可指向的任何動作作爲程序的輸入。結合re模塊使用將發揮強大威力!

一個簡單的例子:

req = urllib2.Request(
	url=url,
	data=postdata,
	headers=headers
)
result = urllib2.urlopen(req)

模塊urlliburllib2的功能差不多,簡單來說urllib2urllib的增強——urllib2更好一些,但是urllib中有urllib2中所沒有的函數。對於簡單的下載, urllib綽綽有餘。 如果需要實現HTTP身份驗證Cookie亦或編寫擴展來處理自己的協議,urllib2可能是更好的選擇。在Python2.x中主要爲urlliburllib2,這兩個標準庫是不可相互替代的。但是在Python3.x中將urllib2合併到了urllib,這一點值得注意。

  • urllib支持設置編碼的函數urllib.urlencode,在模擬登陸的時候經常需要傳遞經過post編碼之後的參數,如果不想使用第三方庫完成模擬登錄,就必須使用到標準庫中的urlliburllib提供一些比較原始基礎的方法而urllib2並沒有,比如urllib中的urlencode方法用來GET查詢字符串的產生。

  • urllib2比較有優勢的地方在於urllib2.openurl中可以接受一個Request類的實例來設置Request參數,來修改/設置Header頭從而達到控制HTTP Request的header部分的目的,也可以修改用戶代理,設置cookie等,但urllib僅可以接受URL。這就意味着,如果你訪問一個網站想更改User Agent(可以僞裝你的瀏覽器),你就需要使用urllib2urllib2模塊沒有加入urllib.urlretrieve函數以及urllib.quote等一系列quote和unquote功能,這個時候就需要urllib的輔助。

因此Python2.x中,urlliburllib2兩者搭配使用。

1、打開遠程文件

幾乎可以像打開本地文件一樣打開遠程文件,差別是隻能使用讀取模式,以及使用模塊urllib.request中的函數urlopen,而不是open(或file)。

from urllib.request import urlopen
webpage = urlopen('http://www.python.org')

如果連接到了網絡,變量webpage將包含一個類似於文件的對象,這個對象與網頁http://www.python.org相關聯。

注意:要在沒有聯網的情況下嘗試使用模塊urllib,可使用以file:打頭的URL訪問本地文件,如file:c:\text\somefile.txt(別忘了對反斜槓進行轉義)。

urlopen返回的類似於文件的對象支持方法:close、 read、readline和readlines,還支持迭代等。

假設要提取剛纔所打開網頁中鏈接About的相對URL, 可使用正則表達式 。

>>> import re
>>> text = webpage.read()
# 注意:如果這個網頁發生了變化,你可能需要修改使用的正則表達式。
>>> m = re.search(b'<a href="([^"]+)" .*?>about</a>', text, re.IGNORECASE)
>>> m.group(1)
'about'
02、獲取遠程文件

函數urlopen返回一個類似於文件的對象,可從中讀取數據。如果要讓urllib替你下載文件並將其副本存儲在一個本地文件中,可使用urlretrieve。這個函數不返回一個類似於文件的對象,而返回一個格式爲(filename, headers)的元組,其中filename是本地文件的名稱(由urllib自動創建),而headers包含一些有關遠程文件的信息(這裏不會介紹headers, 如果你想更深入地瞭解它,請在有關urllib的標準庫文檔中查找urlretrieve)。如果要給下載的副本指定文件名,可通過第二個參數來提供。

urlretrieve('http://www.python.org', 'C:\\python_webpage.html')

這將獲取Python官網的主頁,並將其存儲到文件C:\python_webpage.html中。如果你沒有指定文件名,下載的副本將放在某個臨時位置,可使用函數open來打開。但使用完畢後,你可能想將其刪除以免佔用磁盤空間。要清空這樣的臨時文件,可調用函數urlcleanup且不提供任何參數,它將負責替你完成清空工作。

一些實用的函數

除了通過URL讀取和下載文件外,urllib還提供了一些用於操作URL的函數,如下所示(這裏假設你對URL和CGI略知一二)。

  • quote(string[, safe]) 返回一個字符串,其中所有的特殊字符(在URL中有特殊意義的字符)都已替換爲對URL友好的版本(如將~替換爲%7E),如果要將包含特殊字符的字符串用作URL很有用。參數safe是一個字符串(默認爲'/'),包含不應像這樣對其進行編碼的字符

  • quote_plus(string[, safe]) 類似於quote,但也將空格替換爲加號。

  • unquote(string):與quote相反。

  • unquote_plus(string):與quote_plus相反。

  • urlencode(query[, doseq]) 將映射(如字典)或由包含兩個元素的元組(形如(key, value))組成的序列轉換爲“使用URL編碼的”字符串。這樣的字符串可用於CGI查詢中(詳細信息請參閱Python文檔)。

關於urllib3

urllib3則是增加了連接池等功能,urllib(Python2.x中包含urlliburllib2)和urllib3互相都有補充的部分。


一、urllib

urllib作爲Python的標準庫,基本上涵蓋了基礎的網絡請求功能。

導航:
2.1. urllib.request
2.2. urllib.response
2.3. urllib.parse
2.4. urllib.error


2.1. urllib.request
urllib中,request這個模塊主要負責構造和發起網絡請求,並在其中加入Headers、Proxy等。

1. 發起GET請求

主要使用urlopen()方法來發起請求:

from urllib import request

resp = request.urlopen('http://www.baidu.com')
print(resp.read().decode())

urlopen()方法中傳入字符串格式的url地址,則此方法會訪問目標網址,然後返回訪問的結果。

返回的結果會是一個http.client.HTTPResponse對象,使用此對象的read()方法可以獲取訪問網頁獲得的數據。但是要注意的是,獲得的數據會是bytes的二進制格式,所以需要decode()一下,轉換成字符串格式。

使用帶參數的GET方法取回URL:

>>> import urllib
>>> params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query?%s" % params)
>>> print f.read()
2. 發起POST請求

urlopen()默認的訪問方式是GET,當在urlopen()方法中傳入data參數時,則會發起POST請求。注意:傳遞的data數據需要爲bytes格式。timeout參數還可以設置超時時間如果請求時間超出,那麼就會拋出異常。

from urllib import request

resp = request.urlopen('http://httpbin.org/post', data=b'word=hello', timeout=10)
print(resp.read().decode())

使用帶參數的POST方法:

>>> import urllib
>>> params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query", params)
>>> print f.read()
3. 添加Headers

通過urllib發起的請求會有默認的一個Headers:"User-Agent":"Python-urllib/3.6",指明請求是由urllib發送的。
所以遇到一些驗證User-Agent的網站時,我們需要自定義Headers,而這需要藉助於urllib.request中的Request對象。

from urllib import request

url = 'http://httpbin.org/get'
headers = {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'}

# 需要使用url和headers生成一個Request對象,然後將其傳入urlopen方法中
req = request.Request(url, headers=headers)
resp = request.urlopen(req)
print(resp.read().decode())
4. Request對象

如上所示,urlopen()方法中不止可以傳入字符串格式的url,也可以傳入一個Request對象來擴展功能,Request對象如下所示。

class urllib.request.Request(url, data=None, headers={},
                             origin_req_host=None,
                             unverifiable=False, method=None)

構造Request對象必須傳入url參數,data數據和headers都是可選的。
最後,Request方法可以使用method參數來自由選擇請求的方法,如PUT,DELETE等等,默認爲GET。

5. 添加Cookie

爲了在請求時能帶上Cookie信息,我們需要重新構造一個opener。
使用request.build_opener方法來進行構造opener,將我們想要傳遞的cookie配置到opener中,然後使用這個opener的open方法來發起請求。

from http import cookiejar
from urllib import request

url = 'https://www.baidu.com'

# 創建一個cookiejar對象
cookie = cookiejar.CookieJar()

# 使用HTTPCookieProcessor創建cookie處理器
cookies = request.HTTPCookieProcessor(cookie)

# 並以它爲參數創建Opener對象
opener = request.build_opener(cookies)

# 使用這個opener來發起請求
resp = opener.open(url)

# 查看之前的cookie對象,則可以看到訪問百度獲得的cookie
for i in cookie:
    print(i)

或者也可以把這個生成的opener使用install_opener方法來設置爲全局的,之後使用urlopen方法發起請求時,都會帶上這個cookie

# 將這個opener設置爲全局的opener
request.install_opener(opener)
resp = request.urlopen(url)
6. 設置Proxy代理

使用爬蟲來爬取數據的時候,常常需要使用代理來隱藏我們的真實IP。

from urllib import request

url = 'http://httpbin.org/ip'
proxy = {'http':'218.18.232.26:80','https':'218.18.232.26:80'}

# 創建代理處理器
proxies = request.ProxyHandler(proxy)
# 創建opener對象
opener = request.build_opener(proxies)

resp = opener.open(url)
print(resp.read().decode())

urllib官方文檔的例子:

# 使用HTTP代理,自動跟蹤重定向
>>> import urllib
>>> proxies = {'http': 'http://proxy.example.com:8080/'}
>>> opener = urllib.FancyURLopener(proxies)
>>> f = opener.open("http://www.python.org")
>>> f.read()

# 不使用代理
>>> import urllib
>>> opener = urllib.FancyURLopener({})
>>> f = opener.open("http://www.python.org/")
>>> f.read()
7. 下載數據到本地

在我們進行網絡請求時常常需要保存圖片或音頻等數據到本地,一種方法是使用python的文件操作,將read()獲取的數據保存到文件中。
而urllib提供了一個urlretrieve()方法,可以簡單的直接將請求獲取的數據保存成文件。

from urllib import request

url = 'http://python.org/'
# urlretrieve()方法傳入的第二個參數爲文件保存的位置,以及文件名。
request.urlretrieve(url, 'python.html')

urlretrieve()方法是Python2.x直接移植過來的方法,以後有可能在某個版本中棄用。

2.2. urllib.response
在使用urlopen()方法或者opener的open()方法發起請求後,獲得的結果是一個response對象。這個對象有一些方法和屬性,可以讓我們對請求返回的結果進行一些處理。

read():獲取響應返回的數據,只能使用一次。

getcode():獲取服務器返回的狀態碼。

getheaders():獲取返回響應的響應報頭。

geturl():獲取訪問的url。

2.3. urllib.parse
urllib.parseurllib中用來解析各種數據格式的模塊。

2.3.1. urllib.parse.quote
在url中,是隻能使用ASCII中包含的字符的,也就是說,ASCII不包含的特殊字符,以及中文等字符都是不可以在url中使用的。而我們有時候又有將中文字符加入到url中的需求,例如百度的搜索地址:https://www.baidu.com/s?wd=南北?之後的wd參數,則是我們搜索的關鍵詞。那麼我們實現的方法就是將特殊字符進行url編碼,轉換成可以url可以傳輸的格式,urllib中可以使用quote()方法來實現這個功能。

>>> from urllib import parse
>>> keyword = '南北'
>>> parse.quote(keyword)
'%E5%8D%97%E5%8C%97'

如果需要將編碼後的數據轉換回來,可以使用unquote()方法。

>>> parse.unquote('%E5%8D%97%E5%8C%97')
'南北'

2.3.2. urllib.parse.urlencode
在訪問url時,我們常常需要傳遞很多的url參數,而如果用字符串的方法去拼接url的話,會比較麻煩,所以urllib中提供了urlencode這個方法來拼接url參數。

>>> from urllib import parse
>>> params = {'wd': '南北', 'code': '1', 'height': '188'}
>>> parse.urlencode(params)
'wd=%E5%8D%97%E5%8C%97&code=1&height=188'

2.4. urllib.error
在urllib中主要設置了兩個異常,一個是URLError,一個是HTTPErrorHTTPErrorURLError的子類。

HTTPError還包含了三個屬性:

  • code:請求的狀態碼
  • reason:錯誤的原因
  • headers:響應的報頭

例子:

In [1]: from urllib.error import HTTPError

In [2]: try:
   ...:     request.urlopen('https://www.jianshu.com')
   ...: except HTTPError as e:
   ...:     print(e.code)

403

:在Python3.3後urllib2已經不能再用,全部用urllib.request來代替。把import和代碼中的urllib2全部換成urllib.request,如import urllib.request

二、urllib2

一個例子(Python2.x中):

import urllib2
 
# 設置瀏覽器請求頭
ua_headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0"
}

#建立請求內容
request=urllib2.Request("http://baidu.com/",headers=ua_headers)

#獲取響應
response=urllib2.urlopen(request)

#頁面內容
html=response.read()

print html
print response.getcode()	#返回響應碼
print response.geturl()		#返回實際url
print response.info() 		#返回服務器響應的報頭

另一個例子(Python3.x中使用整合之後的urllib):

from urllib import request

url = r'https://www.baidu.com/'
headers = {
    'User-Agent': r'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  r'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3',
    'Referer': r'http://www.lagou.com/zhaopin/Python/?labelWords=label',
    'Connection': 'keep-alive'
}
req = request.Request(url, headers=headers)
html = request.urlopen(req).read()

# 處理編碼
html = html.decode('utf-8')
print(html)

來自urllib2官方文檔的幾個例子:

GET一個URL:

>>> import urllib2
>>> f = urllib2.urlopen('http://www.python.org/')
>>> print f.read()

使用基本的HTTP認證:

import urllib2
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(realm='PDQ Application',
                          uri='https://mahler:8092/site-updates.py',
                          user='klem',
                          passwd='kadidd!ehopper')
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
urllib2.urlopen('http://www.example.com/login.html')

注:build_opener()默認提供很多處理程序,包括代理處理程序,代理默認會被設置爲環境變量所提供的。

一個使用代理的例子:

proxy_handler = urllib2.ProxyHandler({'http': 'http://www.example.com:3128/'})
proxy_auth_handler = urllib2.ProxyBasicAuthHandler()
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')

opener = urllib2.build_opener(proxy_handler, proxy_auth_handler)
opener.open('http://www.example.com/login.html')

添加HTTP請求頭部:

import urllib2
req = urllib2.Request('http://www.example.com/')
req.add_header('Referer', 'http://www.python.org/')
r = urllib2.urlopen(req)

更改User-agent:

import urllib2
opener = urllib2.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
opener.open('http://www.example.com/')

注:httplibhttplib2httplib是http客戶端協議的實現,通常不直接使用,urllib是以httplib爲基礎,httplib2是第三方庫,比httplib有更多特性。httplib比較底層,一般使用的話用urlliburllib2即可。

三、Python3.X中使用整合後的urllib

Python2.x 有這些庫名可用: urlliburllib2urllib3httplibhttplib2requests
Python3.x 有這些庫名可用: urlliburllib3httplib2requests


若只使用Python3.X,記住有個urllib的庫就行了。Pyhton2.x和Python3.x都有urllib3requests, 它們不是標準庫。urllib3提供線程安全連接池和文件post支持,與urlliburllib2的關係不大。requests 自稱HTTP for Humans,使用更簡潔方便。

一些注意事項

前面提到,在Python3.x中將urllib2合併到了urllib。Python3.x中,隨着urllib2合入urllib,一些常用的方法也發生了變化:2

  1. 在Python2.x中使用import urlparse——在Python3.x中會使用import urllib.parse

  2. 在Python2.x中使用urllib2.urlopen——在Python3.x中會使用urllib.request.urlopen

  3. 在Python2.x中使用urllib2.Request——在Python3.x中會使用urllib.request.Request

  4. 在Python2.x中使用urllib.quote——在Python3.x中會使用urllib.request.quote

  5. 在Python2.x中使用urllib.urlencode——在Python3.x中會使用urllib.parse.urlencode

  6. 在Python2.x中使用cookielib.CookieJar——在Python3.x中會使用http.CookieJar

  7. 異常處理:在Python2.x中使用urllib2.URLError,urllib2.HTTPError——在Python3.x中會使用urllib.error.URLError,urllib.error.HTTPError


urlliburllib2在Python2.x以及Python3.x的區別:

Python2.x中:
import urllib
import urllib2

共同點:都可以直接用urlopen(‘url’)請求頁面

不同點:urlliburlencode(dict)unquote()進行編碼和解碼

對於error:

try:
	response = urllib2.urlopen("http://pythonsite.com/111341.html")
except urllib2.HTTPError as e:
	print(e.reason)
	print(e.code)
	print(e.headers)
except urllib2.URLError as e:
	print(e.reason)

else:
	print("reqeust successfully")
Python3.x中:

請求頁面:urllib.request.urlopen(‘url’)

對於error:

from urllib import request,error
try:
	response = request.urlopen("http://pythonsite.com/113211.html")
except error.HTTPError as e:
	print(e.reason)
	print(e.code)
	print(e.headers)
except error.URLError as e:
	print(e.reason)

else:
	print("reqeust successfully")

Python3.X中urllib成了一個包, 此包分成了幾個模塊:

  • urllib.request 用於打開和讀取URL,
  • urllib.error 用於處理前面request引起的異常,
  • urllib.parse 用於解析URL,
  • urllib.robotparser用於解析robots.txt文件,

注:Python2.X中的urllib.urlopen()被廢棄, urllib2.urlopen()相當於python3.X中的urllib.request.urlopen()

幾個官方例子:

GET一個URL:

>>> import urllib.request
>>> with urllib.request.urlopen('http://www.python.org/') as f:
...     print(f.read(300))

PUT一個請求:

import urllib.request
DATA=b'some data'
req = urllib.request.Request(url='http://localhost:8080', data=DATA,method='PUT')
with urllib.request.urlopen(req) as f:
    pass
print(f.status)
print(f.reason)

基本的HTTP認證:

import urllib.request
auth_handler = urllib.request.HTTPBasicAuthHandler()
auth_handler.add_password(realm='PDQ Application',
                          uri='https://mahler:8092/site-updates.py',
                          user='klem',
                          passwd='kadidd!ehopper')
opener = urllib.request.build_opener(auth_handler)
urllib.request.install_opener(opener)
urllib.request.urlopen('http://www.example.com/login.html')

使用proxy:

proxy_handler = urllib.request.ProxyHandler({'http': 'http://www.example.com:3128/'})
proxy_auth_handler = urllib.request.ProxyBasicAuthHandler()
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')

opener = urllib.request.build_opener(proxy_handler, proxy_auth_handler)
opener.open('http://www.example.com/login.html')

添加頭部:

import urllib.request
req = urllib.request.Request('http://www.example.com/')
req.add_header('Referer', 'http://www.python.org/')
r = urllib.request.urlopen(req)

更改User-agent:

import urllib.request
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
opener.open('http://www.example.com/')

使用GET時設置URL的參數:

>>> import urllib.request
>>> import urllib.parse
>>> params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> url = "http://www.musi-cal.com/cgi-bin/query?%s" % params
>>> with urllib.request.urlopen(url) as f:
...     print(f.read().decode('utf-8'))
...

使用POST時設置參數:

>>> import urllib.request
>>> import urllib.parse
>>> data = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> data = data.encode('ascii')
>>> with urllib.request.urlopen("http://requestb.in/xrbl82xr", data) as f:
...     print(f.read().decode('utf-8'))
...

指定proxy:

>>> import urllib.request
>>> proxies = {'http': 'http://proxy.example.com:8080/'}
>>> opener = urllib.request.FancyURLopener(proxies)
>>> with opener.open("http://www.python.org") as f:
...     f.read().decode('utf-8')
...

不使用proxy, 覆蓋環境變量的proxy:

>>> import urllib.request
>>> opener = urllib.request.FancyURLopener({})
>>> with opener.open("http://www.python.org/") as f:
...     f.read().decode('utf-8')
...

注:Python2.X中的httplib被重命名爲http.client

使用2to3工具轉換源碼時, 會自動處理這幾個庫的導入.

總的來說, 使用Python3.x, 記住只有urllib, 想要更簡潔好用就用requests, 但不夠通用。

四、urllib33

urllib3功能強大且易於使用,用於HTTP客戶端的Python庫。許多Python的原生系統已經開始使用urllib3。

>>> import urllib3
>>> http = urllib3.PoolManager()
>>> r = http.request('GET', 'http://httpbin.org/robots.txt')
>>> r.status
200
>>> r.data
'User-agent: *\nDisallow: /deny\n'

urllib3提供了很多python標準庫urllib裏所沒有的重要特性:

  • 線程安全
  • 連接池
  • 客戶端SSL/TLS驗證
  • 文件分部編碼上傳
  • 協助處理重複請求和HTTP重定位
  • 支持gzip和deflate壓縮編碼
  • 支持HTTP和SOCKS代理
  • 100%測試覆蓋率

3.1. 安裝
urllib3是一個第三方庫,pip安裝:

$ pip install urllib3

或者,可以從GitHub獲取最新的源代碼:

$ git clone git://github.com/shazow/urllib3.git
$ python setup.py install

3.2. 使用
urllib3主要使用連接池進行網絡請求的訪問,所以訪問之前我們需要創建一個連接池對象:

# 導入urllib3模塊:
>>> import urllib3
# 需要一個PoolManager實例來生成請求,由該實例對象處理與線程池的連接以及線程安全的所有細節,不需要任何人爲操作:
>>> http = urllib3.PoolManager()
# 通過request()方法創建一個請求,該方法返回一個HTTPResponse對象:
>>> r = http.request('GET', 'http://httpbin.org/robots.txt')
>>> r.status
200
>>> r.data
'User-agent: *\nDisallow: /deny\n'

3.2.1. 設置headers
通過request()方法向請求(request)中添加一些其他信息:

>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     fields={'hello': 'world'})

或者:在request()方法中,可以定義一個字典類型(dictionary),並作爲headers參數傳入:

headers={'X-Something': 'value'}
resp = http.request('GET', 'http://httpbin.org/headers', headers=headers)

請求(request)中的數據項(request data)可包括:JSON、files以及binary data。

Request data

Headers
在request()方法中,可以定義一個字典類型(dictionary)並作爲headers參數傳入:

>>> r = http.request(
...     'GET',
...     'http://httpbin.org/headers',
...     headers={
...         'X-Something': 'value'
...     })
>>> json.loads(r.data.decode('utf-8'))['headers']
{'X-Something': 'value', ...}

Query parameters
對於GET、HEAD和DELETE請求,可以簡單的通過定義一個字典類型作爲fields參數傳入即可:

>>> r = http.request(
...     'GET',
...     'http://httpbin.org/get',
...     fields={'arg': 'value'})
>>> json.loads(r.data.decode('utf-8'))['args']
{'arg': 'value'}

對於POST和PUT請求(request),需要手動對傳入數據進行編碼,然後加在URL之後:

>>> from urllib.parse import urlencode
>>> encoded_args = urlencode({'arg': 'value'})
>>> url = 'http://httpbin.org/post?' + encoded_args
>>> r = http.request('POST', url)
>>> json.loads(r.data.decode('utf-8'))['args']
{'arg': 'value'}

Form data
對於PUT和POST請求(request),urllib3會自動將字典類型的field參數編碼成表格類型.

>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     fields={'field': 'value'})
>>> json.loads(r.data.decode('utf-8'))['form']
{'field': 'value'}

JSON
在發起請求時,可以通過定義body參數並定義headers的Content-Type參數來發送一個已經過編譯的JSON數據:

>>> import json
>>> data = {'attribute': 'value'}
>>> encoded_data = json.dumps(data).encode('utf-8')
>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     body=encoded_data,
...     headers={'Content-Type': 'application/json'})
>>> json.loads(r.data.decode('utf-8'))['json']
{'attribute': 'value'}

Files & binary data
使用multipart/form-data編碼方式上傳文件,可以使用和傳入Form data數據一樣的方法進行,並將文件定義爲一個元組的形式(file_name,file_data):

>>> with open('example.txt') as fp:
...     file_data = fp.read()
>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     fields={
...         'filefield': ('example.txt', file_data),
...     })
>>> json.loads(r.data.decode('utf-8'))['files']
{'filefield': '...'}

文件名(filename)的定義不是嚴格要求的,但是推薦使用,以使得表現得更像瀏覽器。同時,還可以向元組中再增加一個數據來定義文件的MIME類型:

>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     fields={
...         'filefield': ('example.txt', file_data, 'text/plain'),
...     })

如果是發送原始二進制數據,只要將其定義爲body參數即可。同時,建議對headerContent-Type參數進行設置:

>>> with open('example.jpg', 'rb') as fp:
...     binary_data = fp.read()
>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     body=binary_data,
...     headers={'Content-Type': 'image/jpeg'})
>>> json.loads(r.data.decode('utf-8'))['data']
b'...'

Response content
The HTTPResponse object provides status, data, and header attributes:

>>> r = http.request('GET', 'http://httpbin.org/ip')
>>> r.status
200
>>> r.data
b'{\n  "origin": "104.232.115.37"\n}\n'
>>> r.headers
HTTPHeaderDict({'Content-Length': '33', ...})

JSON content
JSON content can be loaded by decoding and deserializing the data attribute of the request:

>>> import json
>>> r = http.request('GET', 'http://httpbin.org/ip')
>>> json.loads(r.data.decode('utf-8'))
{'origin': '127.0.0.1'}

Binary content
The data attribute of the response is always set to a byte string representing the response content:

>>> r = http.request('GET', 'http://httpbin.org/bytes/8')
>>> r.data
b'\xaa\xa5H?\x95\xe9\x9b\x11'

Note
For larger responses, it’s sometimes better to stream the response.


Using timeouts
Timeouts allow you to control how long requests are allowed to run before being aborted. In simple cases, you can specify a timeout as a float to request():
使用timeout,可以控制請求的運行時間。在一些簡單的應用中,可以將timeout參數設置爲一個浮點數:

>>> http.request(
...     'GET', 'http://httpbin.org/delay/3', timeout=4.0)
<urllib3.response.HTTPResponse>
>>> http.request(
...     'GET', 'http://httpbin.org/delay/3', timeout=2.5)
MaxRetryError caused by ReadTimeoutError

For more granular control you can use a Timeout instance which lets you specify separate connect and read timeouts:
要進行更精細的控制,可以使用Timeout實例,將連接的timeout和讀的timeout分開設置:

>>> http.request(
...     'GET',
...     'http://httpbin.org/delay/3',
...     timeout=urllib3.Timeout(connect=1.0))
<urllib3.response.HTTPResponse>
>>> http.request(
...     'GET',
...     'http://httpbin.org/delay/3',
...     timeout=urllib3.Timeout(connect=1.0, read=2.0))
MaxRetryError caused by ReadTimeoutError

If you want all requests to be subject to the same timeout, you can specify the timeout at the PoolManager level:
如果想讓所有的request都遵循一個timeout,可以將timeout參數定義在PoolManager中:

>>> http = urllib3.PoolManager(timeout=3.0)
# 或者這樣
>>> http = urllib3.PoolManager(
...     timeout=urllib3.Timeout(connect=1.0, read=2.0))

You still override this pool-level timeout by specifying timeout to request().
當在具體的request中再次定義timeout時,會覆蓋PoolManager層面上的timeout。

請求重試(Retrying requests):
urllib3 can automatically retry idempotent requests. This same mechanism also handles redirects. You can control the retries using the retries parameter to request(). By default, urllib3 will retry requests 3 times and follow up to 3 redirects.
urllib3可以自動重試冪等請求,原理和handles redirect一樣。可以通過設置retries參數對重試進行控制。Urllib3默認進行3次請求重試,並進行3次方向改變。

To change the number of retries just specify an integer:
給retries參數定義一個整型來改變請求重試的次數:

>>> http.requests('GET', 'http://httpbin.org/ip', retries=10)

To disable all retry and redirect logic specify retries=False:
關閉請求重試(retrying request)及重定向(redirect)只要將retries定義爲False即可:

>>> http.request(
...     'GET', 'http://nxdomain.example.com', retries=False)
NewConnectionError
>>> r = http.request(
...     'GET', 'http://httpbin.org/redirect/1', retries=False)
>>> r.status
302

To disable redirects but keep the retrying logic, specify redirect=False:
關閉重定向(redirect)但保持重試(retrying request),將redirect參數定義爲False即可:

>>> r = http.request(
...     'GET', 'http://httpbin.org/redirect/1', redirect=False)
>>> r.status
302

For more granular control you can use a Retry instance. This class allows you far greater control of how requests are retried.
要進行更精細的控制,可以使用retry實例,通過該實例可以對請求的重試進行更精細的控制。
For example, to do a total of 3 retries, but limit to only 2 redirects:
例如,進行3次請求重試,但是隻進行2次重定向:

>>> http.request(
...     'GET',
...     'http://httpbin.org/redirect/3',
...     retries=urllib3.Retry(3, redirect=2))
MaxRetryError

You can also disable exceptions for too many redirects and just return the 302 response:

>>> r = http.request(
...     'GET',
...     'http://httpbin.org/redirect/3',
...     retries=urllib3.Retry(
...         redirect=2, raise_on_redirect=False))
>>> r.status
302

If you want all requests to be subject to the same retry policy, you can specify the retry at the PoolManager level:
如果想讓所有請求都遵循一個retry策略,可以在PoolManager中定義retry參數:

>>> http = urllib3.PoolManager(retries=False)
# 或者這樣:
>>> http = urllib3.PoolManager(
...     retries=urllib3.Retry(5, redirect=2))

You still override this pool-level retry policy by specifying retries to request().
當在具體的request中再次定義retry時,會覆蓋 PoolManager層面上的retry。
Errors & Exceptions
urllib3 wraps lower-level exceptions, for example:

>>> try:
...     http.request('GET', 'nx.example.com', retries=False)
>>> except urllib3.exceptions.NewConnectionError:
...     print('Connection failed.')

See exceptions for the full list of all exceptions.

Logging
If you are using the standard library logging module urllib3 will emit several logs. In some cases this can be undesirable. You can use the standard logger interface to change the log level for urllib3’s logger:

>>> logging.getLogger("urllib3").setLevel(logging.WARNING)

3.2.2. 設置url參數
對於GET等沒有請求正文的請求方法,可以簡單的通過設置fields參數來設置url參數。

fields = {'arg': 'value'}
resp = http.request('GET', 'http://httpbin.org/get', fields=fields)

如果使用的是POST等方法,則會將fields作爲請求的請求正文發送。
所以,如果你的POST請求是需要url參數的話,那麼需要自己對url進行拼接。

fields = {'arg': 'value'}
resp = http.request('POST', 'http://httpbin.org/get', fields=fields)

3.2.3. 設置代理

>>> import urllib3
>>> proxy = urllib3.ProxyManager('http://50.233.137.33:80', headers={'connection': 'keep-alive'})
>>> resp = proxy.request('get', 'http://httpbin.org/ip')
>>> resp.status
200
>>> resp.data
b'{"origin":"50.233.136.254"}\n'

注:urllib3中沒有直接設置cookies的方法和參數,只能將cookies設置到headers中。

三、requests

requests使用的是urllib3,繼承了urllib2的所有特性。requests有很大功能特性:

  • 支持HTTP連接保持和連接池;
  • 支持使用cookie保持會話;
  • 支持文件上傳;
  • 支持自動確定響應內容的編碼;
  • 支持國際化的URL和POST數據自動編碼。

requests是第三方類庫,需要另外安裝。

簡單使用:

import requests
 
r = requests.get(url='http://www.baidu.com')    # 最基本的GET請求
print(r.status_code)    # 獲取返回狀態

#帶參數的GET請求,http://dict.baidu.com/s?wd=python
r = requests.get(url='http://dict.baidu.com/s', params={'wd':'python'})   
print(r.url)
print(r.text)   #打印解碼後的返回數據

除了get請求外,還可以POST請求,PUT請求,DELETE請求,HEAD請求,OPTIONS請求。對於web系統來說除了get請求外,還可以POST請求,PUT請求,DELETE請求,HEAD請求,OPTIONS請求一般只支持 GET 和 POST,有一些還支持 HEAD 方法

關於requests更詳細的介紹,請參閱 https://mp.csdn.net/mdeditor/87564359


參考:
python中urllib, urllib2,urllib3, httplib,httplib2, request的區別 https://blog.csdn.net/permike/article/details/52437492
Python網絡請求urllib和urllib3詳解 https://www.jianshu.com/p/f05d33475c78
Python–urllib3庫詳解1 https://www.cnblogs.com/KGoing/p/6146999.html
urllib2庫.官方文檔翻譯 https://blog.csdn.net/u014343243/article/details/49308043


  1. 部分內容參考Python基礎教程 ↩︎

  2. 進一步瞭解urllib2,參見中文版翻譯文檔:http://blog.csdn.net/u014343243/article/details/49308043 ↩︎

  3. urllib3官方文檔: https://urllib3.readthedocs.io/en/latest/
    urllib3其他參考文檔: https://pypi.org/project/urllib3/ ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章