理解urllib、urllib2及requests區別及運用

urllib and urllib2 區別

–博主提示:下面的是python2中的用法,python3須要作出相應修改。javascript

urllib和urllib2模塊都作與請求URL相關的操做,但他們提供不一樣的功能。 
urllib2.urlopen accepts an instance of the Request class or a url, (whereas urllib.urlopen only accepts a url 中文意思就是:urllib2.urlopen能夠接受一個Request對象或者url,(在接受Request對象時候,並以此能夠來設置一個URL的headers),urllib.urlopen只接收一個url 
urllib 有urlencode,urllib2沒有,這也是爲何老是urllib,urllib2常會一塊兒使用的緣由css

r = Request(url='http://www.mysite.com')
 r.add_header('User-Agent', 'awesome fetcher')
 r.add_data(urllib.urlencode({'foo': 'bar'})
 response = urllib2.urlopen(r)     #post method

urllib 模塊

I. urlencode不能直接處理unicode對象,因此若是是unicode,須要先編碼,有unicode轉到utf8,舉例:html

urllib.urlencode (u'bl'.encode('utf-8')) 
II. 示例 

import urllib #sohu 手機主頁 
url = 'http://m.sohu.com/?v=3&_once_=000025_v2tov3&_smuid=\ 
ICvXXapq5EfTpQTVq6Tpz' 
resp = urllib.urlopen(url) 
page = resp.read() 
f = open('./urllib_index.html', 'w') 
f.write(page) 
print dir(resp) 
java

結果:python

[‘doc’, ‘init’, ‘iter’, ‘module’, ‘repr’, ‘close’, ‘code’, ‘fileno’, ‘fp’, ‘getcode’, ‘geturl’, ‘headers’, ‘info’, ‘next’, ‘read’, ‘readline’, ‘readlines’, ‘url’] 
print resp.getcode(), resp.geturl(), resp.info(), resp.headers, resp.url 
#resp.url和resp.geturl()結果同樣linux

III. 編解碼示例 urllib.quote和urllib.urlencode都是編碼,但用法不同web

s = urllib.quote('This is python')  #編碼
print 'quote:\t'+s    #空格用%20替代
s_un = urllib.unquote(s)    #解碼
print 'unquote:\t'+s_un
s_plus = urllib.quote_plus('This is python')  #編碼
print 'quote_plus:\t'+s_plus            #空格用+替代
 s_unplus = urllib.unquote_plus(s_plus)       #解碼
 print 's_unplus:\t'+s_unplus
s_dict = {'name': 'dkf', 'pass': '1234'}
 s_encode = urllib.urlencode(s_dict)    #編碼字典轉換成url參數 
 print 's_encode:\t'+s_encode

結果:json

quote: This%20is%20python 
unquote: This is Python 
quote_plus: This+is+python 
s_unplus: This is python 
s_encode: name=dkf&pass=1234瀏覽器

IV. urlretrieve() urlretrieve多數適用單純的只下載的功能或者顯示下載的進度等緩存

url = 'http://m.sohu.com/?v=3&_once_=000025_v2tov3&_\
          smuid=ICvXXapq5EfTpQTVq6Tpz'
urllib.urlretrieve(url, './retrieve_index.html')

#直接把url連接網頁內容下載到retrieve_index.html裏了,適用於單純的下載的功能。

#urllib.urlretrieve(url, local_name, method)

urllib2

I. urllib2模塊定義的函數和類用來獲取URL(主要是HTTP的),他提供一些複雜的接口用於處理: 基本認證,重定向,Cookies等。 
II. 經常使用方法和類 II.1 urllib2.urlopen(url[, data][, timeout]) #傳url時候,用法同urllib裏的urlopen II.1.1 它打開URL網址,url參數能夠是一個字符串url或者是一個Request對象。可選的參數timeout,阻塞操做以秒爲單位,如嘗試鏈接(若是沒有指定,將使用設置的全局默認timeout值)。實際上這僅適用於HTTP,HTTPS和FTP鏈接。

url = 'http://m.sohu.com/?v=3&_once_=000025_v2tov3&_\
smuid=ICvXXapq5EfTpQTVq6Tpz'
resp = urllib2.urlopen(url)
page = resp.read()

II.1.2 urlopen方法也可經過創建了一個Request對象來明確指明想要獲取的url。調用urlopen函數對請求的url返回一個response對象。這個response相似於一個file對象,因此用.read()函數能夠操做這個response對象

url = 'http://m.sohu.com/?v=3&_once_=000025_v2tov3&_smuid\
=ICvXXapq5EfTpQTVq6Tpz'
req = urllib2.Request(url)
resp = urllib2.urlopen(req)
page = resp.read()

II.2 class urllib2.Request(url[, data][, headers][, originreqhost][, unverifiable])

II.2.1 Request類是一個抽象的URL請求。5個參數的說明以下: II.2.1.1 URL——是一個字符串,其中包含一個有效的URL。 II.2.1.2 data——是一個字符串,指定額外的數據發送到服務器,若是沒有data須要發送能夠爲「None」。目前使用data的HTTP請求是惟一的。當請求含有data參數時,HTTP的請求爲POST,而不是GET。數據應該是緩存在一個標準的application/x-www-form-urlencoded格式中。urllib.urlencode()函數用映射或2元組,返回一個這種格式的字符串。通俗的說就是若是想向一個URL發送數據(一般這些數據是表明一些CGI腳本或者其餘的web應用)。例如在網上填的form(表單)時,瀏覽器會POST表單的內容,這些數據須要被以標準的格式編碼(encode),而後做爲一個數據參數傳送給Request對象。Encoding是在urlib模塊中完成的,而不是在urlib2中完成的。下面是個例子:

import urllib
import urllib2
url = 'http://www.someserver.com/cgi-bin/register.cgi'
values = {'name' : 'Michael Foord',
   'location' : 'Northampton',
   'language' : 'Python' }
data = urllib.urlencode(values)      
req = urllib2.Request(url, data)   #send post
response = urllib2.urlopen(req)
page = response.read()

II.2.1.3 headers——是字典類型,頭字典能夠做爲參數在request時直接傳入,也能夠把每一個鍵和值做爲參數調用add_header()方法來添加。做爲辨別瀏覽器身份的User-Agent header是常常被用來惡搞和假裝的,由於一些HTTP服務只容許某些請求來自常見的瀏覽器而不是腳本,或是針對不一樣的瀏覽器返回不一樣的版本。例如,Mozilla Firefox瀏覽器被識別爲「Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11」。默認狀況下,urlib2把本身識別爲Python-urllib/x.y(這裏的xy是python發行版的主要或次要的版本號,如在Python 2.6中,urllib2的默認用戶代理字符串是「Python-urllib/2.6。下面的例子和上面的區別就是在請求時加了一個headers,模仿IE瀏覽器提交請求。

import urllib
import urllib2
url = 'http://www.someserver.com/cgi-bin/register.cgi'
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
values = {'name' : 'Michael Foord',
        'location' : 'Northampton',
        'language' : 'Python' }
headers = { 'User-Agent' : user_agent }
data = urllib.urlencode(values)
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
the_page = response.read()

標準的headers組成是(Content-Length, Content-Type and Host),只有在Request對象調用urlopen()(上面的例子也屬於這個狀況)或者OpenerDirector.open()時加入。兩種狀況的例子以下: 使用headers參數構造Request對象,如上例在生成Request對象時已經初始化header,而下例是Request對象調用add_header(key, val)方法附加header(Request對象的方法下面再介紹):

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

#http是無狀態的協議,上一次客戶端的請求與下一次客戶端到服務器的請求無關係的,多數省略這一步 
r = urllib2.urlopen(req) 
OpenerDirector爲每個Request自動加上一個User-Agent header,因此第二種方法以下(urllib2.buildopener會返回一個OpenerDirector對象,關於urllib2.buildopener類下面再說):

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

II.3 urllib2.installopener(opener)和urllib2.buildopener([handler, …])  
installopener和buildopener這兩個方法一般都是在一塊兒用,也有時候buildopener單獨使用來獲得OpenerDirector對象。 
installopener實例化會獲得OpenerDirector 對象用來賦予全局變量opener。若是想用這個opener來調用urlopen,那麼就必須實例化獲得OpenerDirector;這樣就能夠簡單的調用OpenerDirector.open()來代替urlopen()。 
build_opener實例化也會獲得OpenerDirector對象,其中參數handlers能夠被BaseHandler或他的子類實例化。子類中能夠經過如下實例化:ProxyHandler (若是檢測代理設置用)掃描代理會用到,很重要這個, UnknownHandler, HTTPHandler, HTTPDefaultErrorHandler, HTTPRedirectHandler, FTPHandler, FileHandler, HTTPErrorProcessor。

import urllib2
req = urllib2.Request('http://www.python.org/')
opener=urllib2.build_opener()
urllib2.install_opener(opener)
f = opener.open(req)

如上使用 urllib2.install_opener()設置 urllib2 的全局 opener。這樣後面的使用會很方便,但不能作更細粒度的控制,好比想在程序中使用兩個不一樣的 Proxy 設置等。比較好的作法是不使用 install_opener 去更改全局的設置,而只是直接調用 opener的open 方法代替全局的 urlopen 方法。

說到這Opener和Handler之間的操做聽起來有點暈。整理下思路就清楚了。當獲取一個URL時,可使用一 個opener(一個urllib2.OpenerDirector實例對象,能夠由build_opener實例化生成)。正常狀況下程 序一直經過urlopen使用默認的opener(也就是說當你使用urlopen方法時,是在隱式的使用默認的opener 對象),但也能夠建立自定義的openers(經過操做 器handlers建立的opener實例)。全部的重活和麻煩 都交給這些handlers來作。每個handler知道如何以一種特定的協議(http,ftp等等)打開url,或 者如何處理打開url發生的HTTP重定向,或者包含的HTTP cookie。建立openers時若是想要安裝特別的han dlers來實現獲取url(如獲取一個處理cookie的opener,或者一個不處理重定向的opener)的話,先實例 一個OpenerDirector對象,而後屢次調用.add_handler(some_handler_instance)來建立一個opene r。或者,你能夠用build_opener,這是一個很方便的建立opener對象的函數,它只有一個函數調用 。build_opener默認會加入許多handlers,它提供了一個快速的方法添加更多東西和使默認的handler 失效。

install_opener如上所述也能用於建立一個opener對象,可是這個對象是(全局)默認的opener。這意味着調用urlopen將會用到你剛建立的opener。也就是說上面的代碼能夠等同於下面這段。這段代碼最終仍是使用的默認opener。通常狀況下咱們用build_opener爲的是生成自定義opener,沒有必要調用install_opener,除非是爲了方便。

import urllib2
req = urllib2.Request('http://www.python.org/')
opener=urllib2.build_opener()       # 建立opener對象
urllib2.install_opener(opener)      #定義全局默認opener
f = urllib2.urlopen(req)          #urlopen使用默認opener,可是install_opener

#已經把opener設爲全局默認了,這裏即是使用上面的創建的opener 
III. 異常處理 
當咱們調用urllib2.urlopen的時候不會老是這麼順利,就像瀏覽器打開url時有時也會報 錯,因此就須要咱們有應對異常的處理。說到異常,咱們先來了解返回的response對象的 幾個經常使用的方法: 
geturl() — 返回檢索的URL資源,這個是返回的真正url,一般是用來鑑定是否重定向的 
info() — 返回頁面的原信息就像一個字段的對象, 如headers,它以mimetools.Message實例爲格式(能夠參考HTTP Headers說明)。 
getcode() — 返回響應的HTTP狀態代碼,運行下面代碼能夠獲得code=200 當不能處理一個response時,urlopen拋出一個URLError(對於python APIs,內建異常如,ValueError, TypeError 等也會被拋出。)

HTTPError是HTTP URL在特別的狀況下被拋出的URLError的一個子類。下面就詳細說說URLError和HTTPError。 URLError——handlers當運行出現問題時(一般是由於沒有網絡鏈接也就是沒有路由到指定的服務器,或在指定的服務器不存在) 
HTTPError——HTTPError是URLError的子類。每一個來自服務器HTTP的response都包含「status code」. 有時status code不能處理這個request. 默認的處理程序將處理這些異常的responses。例如,urllib2發現response的URL與你請求的URL不一樣時也就是發生了重定向時,會自動處理。對於不能處理的請求, urlopen將拋出 - - - HTTPError異常. 典型的錯誤包含‘404’ (沒有找到頁面), ‘403’ (禁止請求),‘401’ (須要驗證)等。它包含2個重要的屬性reason和code。 
程序對於重定向時默認處理的

總結

若是隻是單純的下載或者顯示下載進度,不對下載後的內容作處理等,好比下載圖片,css,js文件等,能夠用urlilb.urlretrieve() 
若是是下載的請求須要填寫表單,輸入帳號,密碼等,建議用urllib2.urlopen(urllib2.Request()) 
在對字典數據編碼時候,用到的是urllib.urlencode()

requests

I. Requests 使用的是 urllib3,繼承了urllib2的全部特性。Requests支持HTTP鏈接保持和鏈接池,支持使用cookie保持會話,支持文件上傳,支持自動肯定響應內容的編碼,支持國際化的 URL 和 POST 數據自動編碼。 II. 舉例:

import requests
 ...

 resp = requests.get('http://www.mywebsite.com/user')
 userdata = {"firstname": "John", "lastname": "Doe", "password": "jdoe123"}
 resp = requests.post('http://www.mywebsite.com/user', params=userdata)
 resp = requests.put('http://www.mywebsite.com/user/put')
 resp = requests.delete('http://www.mywebsite.com/user/delete')
 resp.json()   # 假如返回的是json數據
 resp.text     #返回的不是text數據
 resp.headers['content-type']  #返回text/html;charset=utf-8
 f = open('request_index.html', 'w')
 f.write(page.encode('utf8'))          
 #test 發現requests抓下來的頁面必需要編碼\
 #寫入,(抓下來的是unicode),urllib和urllib2抓下來能夠直接寫入,
 #由於這二者抓下來的page是str

III. 其餘功能特性

國際化域名和 URLs
Keep-Alive & 鏈接池
持久的 Cookie 會話
類瀏覽器式的 SSL 加密認證 
基本/摘要式的身份認證
優雅的鍵/值 Cookies
自動解壓
Unicode 編碼的響應體
多段文件上傳
鏈接超時
支持 .netrc
適用於 Python 2.6—3.4
線程安全

IV. requests不是python自帶的庫,須要另外安裝 easy_install or pip install

V. requests缺陷:直接使用不能異步調用,速度慢(from others)。官方的urllib能夠替代它。

VI. 我的不建議使用requests模塊

更詳細的相關介紹

相關文章
相關標籤/搜索