urllib.request模板的高階用法
一 urllib.request的各種Handler
Handler簡而言之,我們可以把它理解為各種處理器,有專門處理登入驗證的,有處理Cookies的,有處理代理設定的。利用它們,我們幾乎可以做到HTTP請求中所有的事情。
首先,介紹一下urllib.request模組裡的BaseHandler類,它是所有其他Handler的父類,它提供了最基本的方法,例如default_open()、protocol_request()等。各種Handler子類繼承這個BaseHandler類。
-
HTTPDefaultErrorHandler:用於處理HTTP響應錯誤,錯誤都會丟擲HTTPError型別的異常。
-
HTTPRedirectHandler:用於處理重定向。
-
HTTPCookieProcessor:用於處理Cookies。
-
ProxyHandler:用於設定代理,預設代理為空。
-
HTTPPasswordMgr:用於管理密碼,它維護了使用者名稱和密碼的表。
-
HTTPBasicAuthHandler:用於管理認證,如果一個連結開啟時需要認證,那麼可以用它來解決認證問題。
二 OpenerDirector介紹
OpenerDirector,我們可以稱為Opener。我們之前用過urlopen()這個方法,實際上它就是urllib為我們提供的一個Opener。
那麼,為什麼要引入Opener呢?因為需要實現更高階的功能。之前使用的Request和urlopen()相當於類庫為你封裝好了極其常用的請求方法,利用它們可以完成基本的請求,但是現在不一樣了,我們需要實現更高階的功能,所以需要深入一層進行配置,使用更底層的例項來完成操作,所以這裡就用到了Opener。
Opener可以使用open()方法,返回的型別和urlopen()如出一轍。那麼,它和Handler有什麼關係呢?簡而言之,就是利用Handler來構建Opener。
三 驗證
1 場景
有些網站在開啟時就會彈出提示框,直接提示你輸入使用者名稱和密碼,驗證成功後才能檢視頁面,例如:
2 程式碼舉例
from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
from urllib.error import URLError
username = 'username'
password = 'password'
url = 'http://localhost:8000/account/my-information/'
p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, url, username, password)
# 這裡首先例項化HTTPBasicAuthHandler物件,其引數是HTTPPasswordMgrWithDefaultRealm物件,
# 它利用add_password()新增進去使用者名稱和密碼,這樣就建立了一個處理驗證的Handler。
auth_handler = HTTPBasicAuthHandler(p)
# 利用這個Handler並使用build_opener()方法構建一個Opener,這個Opener在傳送請求時就相當於已經驗證成功了。
opener = build_opener(auth_handler)
try:
# 利用Opener的open()方法開啟連結,就可以完成驗證了。這裡獲取到的結果就是驗證後的頁面原始碼內容。
result = opener.open(url)
html = result.read().decode('utf-8')
print(html)
except URLError as e:
print(e.reason)
四 代理
1 點睛
在做爬蟲的時候,免不了要使用代理,如果要新增代理,可以像下面這樣做。
2 程式碼
from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener
# 這裡使用了ProxyHandler,其引數是一個字典,
# 鍵名是協議型別(比如HTTP或者HTTPS等),鍵值是代理連結,可以新增多個代理。
proxy_handler = ProxyHandler({
# 這裡我們在本地搭建了一個代理,它執行在8000埠上
'http': 'http://127.0.0.1:8000',
'https': 'https://127.0.0.1:8000'
})
# 利用這個Handler及build_opener()方法構造一個Opener,之後傳送請求即可
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)
五 Cookies
1 獲取網站Cookies
1.1 程式碼
import http.cookiejar, urllib.request
# 必須宣告一個CookieJar物件。
cookie = http.cookiejar.CookieJar()
# 利用HTTPCookieProcessor來構建一個Handler
handler = urllib.request.HTTPCookieProcessor(cookie)
# 利用build_opener()方法構建出Opener
opener = urllib.request.build_opener(handler)
# 執行open()函式即可
response = opener.open('http://www.baidu.com')
for item in cookie:
print(item.name + "=" + item.value)
1.2 執行結果
E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_1_1.py
BAIDUID=80E7B05274F7644E00E3FA0142947F25:FG=1
BIDUPSID=80E7B05274F7644E00E3FA0142947F25
H_PS_PSSID=1454_21089_28205_28132_28267_28139
PSTM=1546766806
delPer=0
BDSVRTM=0
BD_HOME=0
2 將Cookies儲存成文字
2.1 程式碼
import http.cookiejar, urllib.request
filename = 'cookies.txt'
# 這時CookieJar就需要換成MozillaCookieJar,它在生成檔案時會用到,是CookieJar的子類,
# 可以用來處理Cookies和檔案相關的事件,比如讀取和儲存Cookies,可以將Cookies儲存成Mozilla型瀏覽器的Cookies格式。
cookie = http.cookiejar.MozillaCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)
2.2 生成檔案內容如下
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file! Do not edit.
.baidu.com TRUE / FALSE 3694250720 BAIDUID 18FC099E164E6C0B70DA82B6B1BB27F1:FG=1
.baidu.com TRUE / FALSE 3694250720 BIDUPSID 18FC099E164E6C0B70DA82B6B1BB27F1
.baidu.com TRUE / FALSE H_PS_PSSID 1426_21125_28205_28132_26350_28267_28139
.baidu.com TRUE / FALSE 3694250720 PSTM 1546767074
.baidu.com TRUE / FALSE delPer 0
www.baidu.com FALSE / FALSE BDSVRTM 0
www.baidu.com FALSE / FALSE BD_HOME 0
3 將Cookies儲存成LWP格式
3.1 程式碼
import http.cookiejar, urllib.request
filename = 'cookies1.txt'
# 檔案儲存成LWP格式的Cookies檔案
cookie = http.cookiejar.LWPCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)
3.2 生成檔案內容如下
#LWP-Cookies-2.0
Set-Cookie3: BAIDUID="09D84C55FF9E09D21860188E0987C4AD:FG=1"; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-01-24 12:49:12Z"; version=0
Set-Cookie3: BIDUPSID=09D84C55FF9E09D21860188E0987C4AD; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-01-24 12:49:12Z"; version=0
Set-Cookie3: H_PS_PSSID=1425_21106_18560_28206_28132_26350_28266_28140_27509; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: PSTM=1546767306; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-01-24 12:49:12Z"; version=0
Set-Cookie3: delPer=0; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: BDSVRTM=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0
Set-Cookie3: BD_HOME=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0
4 利用生成了Cookies檔案
import http.cookiejar, urllib.request
cookie = http.cookiejar.LWPCookieJar()
# 這裡呼叫load()方法來讀取本地的Cookies檔案,
# 獲取到了Cookies的內容。不過前提是我們首先生成了LWPCookieJar格式的Cookies,
# 並儲存成檔案,然後讀取Cookies之後使用同樣的方法構建Handler和Opener即可完成操作。
cookie.load('cookies1.txt', ignore_discard=True, ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
# 執行結果正常的話,會輸出百度網頁的原始碼。
print(response.read().decode('utf-8'))