在開始后面的內(nèi)容之前,先來(lái)解釋一下 urllib2 中的兩個(gè)個(gè)方法:info and geturl urlopen 返回的應(yīng)答對(duì)象 response(或者 HTTPError 實(shí)例)有兩個(gè)很有用的方法 info()和 geturl()
這個(gè)返回獲取的真實(shí)的 URL,這個(gè)很有用,因?yàn)?urlopen(或者 opener 對(duì)象使用的)或許會(huì)有重定向。獲取的 URL 或許跟請(qǐng)求 URL 不同。
以人人中的一個(gè)超級(jí)鏈接為例,我們建一個(gè) urllib2_test10.py 來(lái)比較一下原始 URL 和重定向的鏈接:
from urllib2 import Request, urlopen, URLError, HTTPError
old_url = 'http://rrurl.cn/b1UZuP'
req = Request(old_url)
response = urlopen(req)
print 'Old url :' + old_url
print 'Real url :' + response.geturl()
運(yùn)行之后可以看到真正的鏈接指向的網(wǎng)址:
http://wiki.jikexueyuan.com/project/python-crawler/images/2.png" alt="" />
這個(gè)返回對(duì)象的字典對(duì)象,該字典描述了獲取的頁(yè)面情況。通常是服務(wù)器發(fā)送的特定頭 headers。目前是 httplib.HTTPMessage 實(shí)例。
經(jīng)典的 headers 包含"Content-length","Content-type",和其他內(nèi)容。
我們建一個(gè) urllib2_test11.py 來(lái)測(cè)試一下 info 的應(yīng)用:
from urllib2 import Request, urlopen, URLError, HTTPError
old_url = 'http://www.baidu.com'
req = Request(old_url)
response = urlopen(req)
print 'Info():'
print response.info()
運(yùn)行的結(jié)果如下,可以看到頁(yè)面的相關(guān)信息:
http://wiki.jikexueyuan.com/project/python-crawler/images/3.png" alt="" />
下面來(lái)說(shuō)一說(shuō) urllib2 中的兩個(gè)重要概念:Openers 和 Handlers。
當(dāng)你獲取一個(gè) URL 你使用一個(gè) opener(一個(gè) urllib2.OpenerDirector 的實(shí)例)。正常情況下,我們使用默認(rèn) opener:通過 urlopen。但你能夠創(chuàng)建個(gè)性的 openers。
Openers 使用處理器 handlers,所有的“繁重”工作由 handlers 處理。每個(gè) handlers 知道如何通過特定協(xié)議打開 URLs,或者如何處理 URL 打開時(shí)的各個(gè)方面。
例如 HTTP 重定向或者 HTTP cookies。
如果你希望用特定處理器獲取 URLs 你會(huì)想創(chuàng)建一個(gè) openers,例如獲取一個(gè)能處理 cookie 的 opener,或者獲取一個(gè)不重定向的 opener。
要?jiǎng)?chuàng)建一個(gè) opener,可以實(shí)例化一個(gè) OpenerDirector,然后調(diào)用 .add\_handler(some\_handler\_instance)。同樣,可以使用 build_opener,這是一個(gè)更加方便的函數(shù),用來(lái)創(chuàng)建 opener 對(duì)象,他只需要一次函數(shù)調(diào)用。build_opener 默認(rèn)添加幾個(gè)處理器,但提供快捷的方法來(lái)添加或更新默認(rèn)處理器。
其他的處理器 handlers 你或許會(huì)希望處理代理,驗(yàn)證,和其他常用但有點(diǎn)特殊的情況。
install_opener 用來(lái)創(chuàng)建(全局)默認(rèn) opener。這個(gè)表示調(diào)用 urlopen 將使用你安裝的 opener。 Opener 對(duì)象有一個(gè) open 方法。該方法可以像 urlopen 函數(shù)那樣直接用來(lái)獲取 urls:通常不必調(diào)用 install_opener,除了為了方便。
說(shuō)完了上面兩個(gè)內(nèi)容,下面我們來(lái)看一下基本認(rèn)證的內(nèi)容,這里會(huì)用到上面提及的 Opener 和 Handler。
Basic Authentication 基本驗(yàn)證
為了展示創(chuàng)建和安裝一個(gè) handler,我們將使用 HTTPBasicAuthHandler。 當(dāng)需要基礎(chǔ)驗(yàn)證時(shí),服務(wù)器發(fā)送一個(gè) header(401 錯(cuò)誤碼) 請(qǐng)求驗(yàn)證。這個(gè)指定了 scheme 和一個(gè)‘realm’,看起來(lái)像這樣:Www-authenticate: SCHEME realm="REALM"。
例如
Www-authenticate: Basic realm="cPanel Users"
客戶端必須使用新的請(qǐng)求,并在請(qǐng)求頭里包含正確的姓名和密碼。這是“基礎(chǔ)驗(yàn)證”,為了簡(jiǎn)化這個(gè)過程,我們可以創(chuàng)建一個(gè) HTTPBasicAuthHandler 的實(shí)例,并讓opener 使用這個(gè) handler 就可以啦。
HTTPBasicAuthHandler 使用一個(gè)密碼管理的對(duì)象來(lái)處理 URLs 和 realms 來(lái)映射用戶名和密碼。如果你知道 realm(從服務(wù)器發(fā)送來(lái)的頭里)是什么,你就能使用 HTTPPasswordMgr。
通常人們不關(guān)心 realm 是什么。那樣的話,就能用方便的 HTTPPasswordMgrWithDefaultRealm。這個(gè)將在你為 URL 指定一個(gè)默認(rèn)的用戶名和密碼。這將在你為特定 realm 提供一個(gè)其他組合時(shí)得到提供。我們通過給 realm 參數(shù)指定 None 提供給 add_password 來(lái)指示這種情況。
最高層次的 URL 是第一個(gè)要求驗(yàn)證的 URL。你傳給 .add_password()更深層次的 URLs 將同樣合適。說(shuō)了這么多廢話,下面來(lái)用一個(gè)例子演示一下上面說(shuō)到的內(nèi)容。
我們建一個(gè) urllib2_test12.py 來(lái)測(cè)試一下 info 的應(yīng)用:
\# -*- coding: utf-8 -*-
import urllib2
\# 創(chuàng)建一個(gè)密碼管理者
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
\# 添加用戶名和密碼
top_level_url = "http://example.com/foo/"
\# 如果知道 realm, 我們可以使用他代替 ``None``.
\# password_mgr.add_password(None, top_level_url, username, password)
password_mgr.add_password(None, top_level_url,'why', '1223')
\# 創(chuàng)建了一個(gè)新的handler
handler = urllib2.HTTPBasicAuthHandler(password_mgr)
\# 創(chuàng)建 "opener" (OpenerDirector 實(shí)例)
opener = urllib2.build_opener(handler)
a_url = 'http://www.baidu.com/'
\# 使用 opener 獲取一個(gè)URL
opener.open(a_url)
\# 安裝 opener.
\# 現(xiàn)在所有調(diào)用 urllib2.urlopen 將用我們的 opener.
urllib2.install_opener(opener)
注意:以上的例子我們僅僅提供我們的 HHTPBasicAuthHandler 給 build_opener。默認(rèn)的 openers 有正常狀況的 handlers:ProxyHandler,UnknownHandler,HTTPHandler,HTTPDefaultErrorHandler,HTTPRedirectHandler,F(xiàn)TPHandler, FileHandler, HTTPErrorProcessor。
代碼中的 top\_level\_url 實(shí)際上可以是完整 URL(包含"http:",以及主機(jī)名及可選的端口號(hào))。
例如:http://example.com/。也可以是一個(gè)“authority”(即主機(jī)名和可選的包含端口號(hào))。
例如:“example.com” or “example.com:8080”。后者包含了端口號(hào)。