urllib vs urllib2 vs requests

urllib and urllib2 區(qū)別

–博主提示:下面的是python2中的用法盼忌,python3需要做出相應(yīng)修改烹卒。

urllib和urllib2模塊都做與請求URL相關(guān)的操作荣刑,但他們提供不同的功能凑队。?

urllib2.urlopen accepts an instance of the Request class or a url, (whereas urllib.urlopen only accepts a url 中文意思就是:urllib2.urlopen可以接受一個Request對象或者url庇谆,(在接受Request對象時候缀台,并以此可以來設(shè)置一個URL的headers)棠赛,urllib.urlopen只接收一個url?

urllib 有urlencode,urllib2沒有,這也是為什么總是urllib将硝,urllib2常會一起使用的原因

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

1

2

3

4

5

urllib 模塊

I. urlencode不能直接處理unicode對象恭朗,所以如果是unicode,需要先編碼依疼,有unicode轉(zhuǎn)到utf8痰腮,舉例:

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)?

結(jié)果:

[‘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()結(jié)果一樣

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

s = urllib.quote('This is python')? #編碼

print 'quote:\t'+s? ? B砂眨空格用%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? ? ? ? ? ? 0蛑担空格用+替代

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)? ? #編碼字典轉(zhuǎn)換成url參數(shù)

print 's_encode:\t'+s_encode

1

2

3

4

5

6

7

8

9

10

11

12

結(jié)果:

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多數(shù)適用單純的只下載的功能或者顯示下載的進度等

url = 'http://m.sohu.com/?v=3&_once_=000025_v2tov3&_\

? ? ? ? ? smuid=ICvXXapq5EfTpQTVq6Tpz'

urllib.urlretrieve(url, './retrieve_index.html')

1

2

3

4

#直接把url鏈接網(wǎng)頁內(nèi)容下載到retrieve_index.html里了,適用于單純的下載的功能误辑。

? ? #urllib.urlretrieve(url, local_name, method)

1

2

urllib2

I. urllib2模塊定義的函數(shù)和類用來獲取URL(主要是HTTP的)沧踏,他提供一些復(fù)雜的接口用于處理: 基本認證,重定向巾钉,Cookies等翘狱。?

II. 常用方法和類 II.1 urllib2.urlopen(url[, data][, timeout]) #傳url時候,用法同urllib里的urlopen II.1.1 它打開URL網(wǎng)址砰苍,url參數(shù)可以是一個字符串url或者是一個Request對象潦匈。可選的參數(shù)timeout赚导,阻塞操作以秒為單位茬缩,如嘗試連接(如果沒有指定,將使用設(shè)置的全局默認timeout值)吼旧。實際上這僅適用于HTTP凰锡,HTTPS和FTP連接。

url = 'http://m.sohu.com/?v=3&_once_=000025_v2tov3&_\

smuid=ICvXXapq5EfTpQTVq6Tpz'

resp = urllib2.urlopen(url)

page = resp.read()

1

2

3

4

5

II.1.2 urlopen方法也可通過建立了一個Request對象來明確指明想要獲取的url圈暗。調(diào)用urlopen函數(shù)對請求的url返回一個response對象掂为。這個response類似于一個file對象,所以用.read()函數(shù)可以操作這個response對象

url = 'http://m.sohu.com/?v=3&_once_=000025_v2tov3&_smuid\

=ICvXXapq5EfTpQTVq6Tpz'

req = urllib2.Request(url)

resp = urllib2.urlopen(req)

page = resp.read()

1

2

3

4

5

6

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

II.2.1 Request類是一個抽象的URL請求员串。5個參數(shù)的說明如下: II.2.1.1 URL——是一個字符串菩掏,其中包含一個有效的URL。 II.2.1.2 data——是一個字符串昵济,指定額外的數(shù)據(jù)發(fā)送到服務(wù)器智绸,如果沒有data需要發(fā)送可以為“None”野揪。目前使用data的HTTP請求是唯一的。當(dāng)請求含有data參數(shù)時瞧栗,HTTP的請求為POST斯稳,而不是GET。數(shù)據(jù)應(yīng)該是緩存在一個標(biāo)準(zhǔn)的application/x-www-form-urlencoded格式中迹恐。urllib.urlencode()函數(shù)用映射或2元組挣惰,返回一個這種格式的字符串。通俗的說就是如果想向一個URL發(fā)送數(shù)據(jù)(通常這些數(shù)據(jù)是代表一些CGI腳本或者其他的web應(yīng)用)殴边。例如在網(wǎng)上填的form(表單)時憎茂,瀏覽器會POST表單的內(nèi)容,這些數(shù)據(jù)需要被以標(biāo)準(zhǔn)的格式編碼(encode)锤岸,然后作為一個數(shù)據(jù)參數(shù)傳送給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()

1

2

3

4

5

6

7

8

9

10

11

II.2.1.3 headers——是字典類型拳氢,頭字典可以作為參數(shù)在request時直接傳入,也可以把每個鍵和值作為參數(shù)調(diào)用add_header()方法來添加蛋铆。作為辨別瀏覽器身份的User-Agent header是經(jīng)常被用來惡搞和偽裝的馋评,因為一些HTTP服務(wù)只允許某些請求來自常見的瀏覽器而不是腳本,或是針對不同的瀏覽器返回不同的版本刺啦。例如留特,Mozilla Firefox瀏覽器被識別為“Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11”。默認情況下玛瘸,urlib2把自己識別為Python-urllib/x.y(這里的xy是python發(fā)行版的主要或次要的版本號蜕青,如在Python 2.6中,urllib2的默認用戶代理字符串是“Python-urllib/2.6捧韵。下面的例子和上面的區(qū)別就是在請求時加了一個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()

1

2

3

4

5

6

7

8

9

10

11

12

13

標(biāo)準(zhǔn)的headers組成是(Content-Length, Content-Type and Host)再来,只有在Request對象調(diào)用urlopen()(上面的例子也屬于這個情況)或者OpenerDirector.open()時加入。兩種情況的例子如下: 使用headers參數(shù)構(gòu)造Request對象磷瘤,如上例在生成Request對象時已經(jīng)初始化header芒篷,而下例是Request對象調(diào)用add_header(key, val)方法附加header(Request對象的方法下面再介紹):

import urllib2

req = urllib2.Request('http://www.example.com/')

req.add_header('Referer', 'http://www.python.org/')? ?

1

2

3

4

#http是無狀態(tài)的協(xié)議,上一次客戶端的請求與下一次客戶端到服務(wù)器的請求無關(guān)系的采缚,多數(shù)省略這一步?

r = urllib2.urlopen(req)?

OpenerDirector為每一個Request自動加上一個User-Agent header针炉,所以第二種方法如下(urllib2.buildopener會返回一個OpenerDirector對象,關(guān)于urllib2.buildopener類下面再說):

import urllib2

opener = urllib2.build_opener()

opener.addheaders = [('User-agent', 'Mozilla/5.0')]

opener.open('http://www.example.com/')

1

2

3

4

5

II.3 urllib2.installopener(opener)和urllib2.buildopener([handler, …])?

installopener和buildopener這兩個方法通常都是在一起用,也有時候buildopener單獨使用來得到OpenerDirector對象扳抽。?

installopener實例化會得到OpenerDirector 對象用來賦予全局變量opener篡帕。如果想用這個opener來調(diào)用urlopen殖侵,那么就必須實例化得到OpenerDirector;這樣就可以簡單的調(diào)用OpenerDirector.open()來代替urlopen()镰烧。?

build_opener實例化也會得到OpenerDirector對象拢军,其中參數(shù)handlers可以被BaseHandler或他的子類實例化。子類中可以通過以下實例化:ProxyHandler (如果檢測代理設(shè)置用)掃描代理會用到怔鳖,很重要這個, 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)

1

2

3

4

5

6

如上使用 urllib2.install_opener()設(shè)置 urllib2 的全局 opener。這樣后面的使用會很方便结执,但不能做更細粒度的控制度陆,比如想在程序中使用兩個不同的 Proxy 設(shè)置等。比較好的做法是不使用 install_opener 去更改全局的設(shè)置献幔,而只是直接調(diào)用 opener的open 方法代替全局的 urlopen 方法懂傀。

說到這Opener和Handler之間的操作聽起來有點暈。整理下思路就清楚了斜姥。當(dāng)獲取一個URL時鸿竖,可以使用一 個opener(一個urllib2.OpenerDirector實例對象,可以由build_opener實例化生成)铸敏。正常情況下程 序一直通過urlopen使用默認的opener(也就是說當(dāng)你使用urlopen方法時缚忧,是在隱式的使用默認的opener 對象),但也可以創(chuàng)建自定義的openers(通過操作 器handlers創(chuàng)建的opener實例)杈笔。所有的重活和麻煩 都交給這些handlers來做闪水。每一個handler知道如何以一種特定的協(xié)議(http,ftp等等)打開url蒙具,或 者如何處理打開url發(fā)生的HTTP重定向球榆,或者包含的HTTP cookie。創(chuàng)建openers時如果想要安裝特別的han dlers來實現(xiàn)獲取url(如獲取一個處理cookie的opener禁筏,或者一個不處理重定向的opener)的話持钉,先實例 一個OpenerDirector對象,然后多次調(diào)用.add_handler(some_handler_instance)來創(chuàng)建一個opene r篱昔∶壳浚或者,你可以用build_opener州刽,這是一個很方便的創(chuàng)建opener對象的函數(shù)空执,它只有一個函數(shù)調(diào)用 。build_opener默認會加入許多handlers穗椅,它提供了一個快速的方法添加更多東西和使默認的handler 失效辨绊。

install_opener如上所述也能用于創(chuàng)建一個opener對象,但是這個對象是(全局)默認的opener匹表。這意味著調(diào)用urlopen將會用到你剛創(chuàng)建的opener门坷。也就是說上面的代碼可以等同于下面這段宣鄙。這段代碼最終還是使用的默認opener。一般情況下我們用build_opener為的是生成自定義opener默蚌,沒有必要調(diào)用install_opener框冀,除非是為了方便。

import urllib2

req = urllib2.Request('http://www.python.org/')

opener=urllib2.build_opener()? ? ? # 創(chuàng)建opener對象

urllib2.install_opener(opener)? ? ? #定義全局默認opener

f = urllib2.urlopen(req)? ? ? ? ? #urlopen使用默認opener敏簿,但是install_opener

1

2

3

4

5

6

#已經(jīng)把opener設(shè)為全局默認了明也,這里便是使用上面的建立的opener?

III. 異常處理?

當(dāng)我們調(diào)用urllib2.urlopen的時候不會總是這么順利,就像瀏覽器打開url時有時也會報 錯惯裕,所以就需要我們有應(yīng)對異常的處理温数。說到異常,我們先來了解返回的response對象的 幾個常用的方法:?

geturl() — 返回檢索的URL資源蜻势,這個是返回的真正url撑刺,通常是用來鑒定是否重定向的?

info() — 返回頁面的原信息就像一個字段的對象, 如headers握玛,它以mimetools.Message實例為格式(可以參考HTTP Headers說明)够傍。?

getcode() — 返回響應(yīng)的HTTP狀態(tài)代碼,運行下面代碼可以得到code=200 當(dāng)不能處理一個response時挠铲,urlopen拋出一個URLError(對于python APIs冕屯,內(nèi)建異常如,ValueError, TypeError 等也會被拋出拂苹。)

HTTPError是HTTP URL在特別的情況下被拋出的URLError的一個子類浴韭。下面就詳細說說URLError和HTTPError连霉。 URLError——handlers當(dāng)運行出現(xiàn)問題時(通常是因為沒有網(wǎng)絡(luò)連接也就是沒有路由到指定的服務(wù)器翠语,或在指定的服務(wù)器不存在)?

HTTPError——HTTPError是URLError的子類点骑。每個來自服務(wù)器HTTP的response都包含“status code”. 有時status code不能處理這個request. 默認的處理程序?qū)⑻幚磉@些異常的responses紧索。例如,urllib2發(fā)現(xiàn)response的URL與你請求的URL不同時也就是發(fā)生了重定向時冈敛,會自動處理暮蹂。對于不能處理的請求, urlopen將拋出 - - - HTTPError異常. 典型的錯誤包含‘404’ (沒有找到頁面), ‘403’ (禁止請求),‘401’ (需要驗證)等我纪。它包含2個重要的屬性reason和code券犁。?

程序?qū)τ谥囟ㄏ驎r默認處理的

總結(jié)

如果只是單純的下載或者顯示下載進度荞估,不對下載后的內(nèi)容做處理等,比如下載圖片,css,js文件等,可以用urlilb.urlretrieve()?

如果是下載的請求需要填寫表單失暂,輸入賬號彼宠,密碼等,建議用urllib2.urlopen(urllib2.Request())?

在對字典數(shù)據(jù)編碼時候弟塞,用到的是urllib.urlencode()

requests

I. Requests 使用的是 urllib3兵志,繼承了urllib2的所有特性。Requests支持HTTP連接保持和連接池宣肚,支持使用cookie保持會話想罕,支持文件上傳,支持自動確定響應(yīng)內(nèi)容的編碼霉涨,支持國際化的 URL 和 POST 數(shù)據(jù)自動編碼按价。 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數(shù)據(jù)

resp.text? ? #返回的不是text數(shù)據(jù)

resp.headers['content-type']? #返回text/html;charset=utf-8

f = open('request_index.html', 'w')

f.write(page.encode('utf8'))? ? ? ? ?

#test 發(fā)現(xiàn)requests抓下來的頁面必須要編碼\

#寫入,(抓下來的是unicode),urllib和urllib2抓下來可以直接寫入笙瑟,

#因為這兩者抓下來的page是str

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

III. 其他功能特性

國際化域名和 URLs

Keep-Alive & 連接池

持久的 Cookie 會話

類瀏覽器式的 SSL 加密認證

基本/摘要式的身份認證

優(yōu)雅的鍵/值 Cookies

自動解壓

Unicode 編碼的響應(yīng)體

多段文件上傳

連接超時

支持 .netrc

適用于 Python 2.6—3.4

線程安全

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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

V. requests缺陷:直接使用不能異步調(diào)用,速度慢(from others)往枷。官方的urllib可以替代它框产。

VI. 個人不建議使用requests模塊

更詳細的相關(guān)介紹

urllib 官網(wǎng)

urllib2 官網(wǎng)

requests 官網(wǎng)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市错洁,隨后出現(xiàn)的幾起案子秉宿,更是在濱河造成了極大的恐慌,老刑警劉巖屯碴,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件描睦,死亡現(xiàn)場離奇詭異,居然都是意外死亡导而,警方通過查閱死者的電腦和手機忱叭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來今艺,“玉大人韵丑,你說我怎么就攤上這事⌒槎校” “怎么了撵彻?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我千康,道長,這世上最難降的妖魔是什么铲掐? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任拾弃,我火速辦了婚禮,結(jié)果婚禮上摆霉,老公的妹妹穿的比我還像新娘豪椿。我一直安慰自己,他們只是感情好携栋,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布搭盾。 她就那樣靜靜地躺著,像睡著了一般婉支。 火紅的嫁衣襯著肌膚如雪鸯隅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天向挖,我揣著相機與錄音蝌以,去河邊找鬼。 笑死何之,一個胖子當(dāng)著我的面吹牛跟畅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溶推,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼徊件,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蒜危?” 一聲冷哼從身側(cè)響起虱痕,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辐赞,沒想到半個月后皆疹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡占拍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年略就,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晃酒。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡表牢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贝次,到底是詐尸還是另有隱情崔兴,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站敲茄,受9級特大地震影響位谋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜堰燎,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一掏父、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秆剪,春花似錦赊淑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至洁灵,卻和暖如春饱岸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背徽千。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工伶贰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人罐栈。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓黍衙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親荠诬。 傳聞我的和親對象是個殘疾皇子琅翻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容