urllib是Python中請求url連線的官方標準庫,在Python3中將Python2中的urllib和urllib2整合成了urllib。urllib中一共有四個模組,分別如下:
- request:主要負責構造和發起網路請求,定義了適用於在各種複雜情況下開啟 URL (主要為 HTTP) 的函式和類
- error:處理異常
- parse:解析各種資料格式
- robotparser:解析robot.txt檔案
一、request模組
1.urlopen()方法:
- 在urlopen()方法中,直接寫入要訪問的url地址字串,該方法就會主動的訪問目標網址,然後返回訪問結果,返回的訪問結果是一個http.client.HTTPResponse物件,該物件的常見方法有:
- read() :獲取訪問網頁獲取的資料,bytes型別
- info():返回響應頭資訊
- getcode():返回Http狀態碼。
- geturl():返回請求的url
-
傳送簡單的GET請求
from urllib.request import urlopen #向指定的url傳送請求,並返回伺服器響應的類檔案物件 resp = urlopen('https://www.baidu.com') print(resp.read().decode())
-
傳送簡單的POST請求(data引數)
from urllib.reuqest import urlopen from urllib.parse import urlencode #將字典型別的資料轉換成表單型別的資料格式,如"world=hello" data = urlencode({"word":"hello"}).encode() response = request.urlopen('http://httpbin.org/post', data=data) print(response.read().decode())
預設的訪問方式是GET,當在urlopen()方法中傳入data引數時,則會發起POST請求。注意:傳遞的data資料需要為bytes格式
2.Request
- 如果需要執行更復雜的操作,比如增加HTTP報頭,必須建立一個 Request 例項來作為urlopen()的引數;而需要訪問的url地址則作為 Request 例項的引數。
- 為了使爬蟲程式更像一個真實使用者,那我們第一步就是需要偽裝成一個被公認的瀏覽器,在傳送請求的時候帶上User-Agent頭
from urllib.request import Request,urlopen url = 'https://www.baidu.com/' ua_header = {"User-Agent" : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"} #url連同headers一起構造request請求,這個請求附帶IE 9.0瀏覽器的User-Agent request = Request(url,headers=ua_header) #向伺服器傳送請求 resp = urlopen(request) print(resp.read().decode)
3.ProxyHandler處理器(代理IP)
- 使用爬蟲來爬取資料的時候,如果過於頻繁的訪問,而且網站還設有限制的話,很有可能會禁封我們的ip地址,這個時候就需要設定代理,來隱藏我們的真實IP。
- 代理IP的原理:以本機先訪問代理IP,再通過代理IP地址訪問伺服器,這樣伺服器接受到的訪問IP就是代理IP地址。
from urllib.request import build_opener,urlopen(),install_opener,Request,ProxyHandler # 構建了兩個代理Handler,一個有代理IP,一個沒有代理IP httpproxy_handler = urllib2.ProxyHandler({'http': '218.18.232.26:80', 'https': '218.18.232.26:80'}) nullproxy_handler = urllib2.ProxyHandler({}) proxySwitch = True #定義一個代理開關 # 通過build_opener()方法使用這些代理Handler物件,建立自定義opener物件 # 根據代理開關是否開啟,使用不同的代理模式 if proxySwitch: opener = build_opener(httpproxy_handler) else: opener = build_opener(nullproxy_handler) request = Request("http://www.baidu.com/") # 1. 如果這麼寫,只有使用opener.open()方法傳送請求才使用自定義的代理,而urlopen()則不使用自定義代理。 resp = opener.open(request) # 2. 如果這麼寫,就是將opener應用到全域性,之後所有的,不管是opener.open()還是urlopen() 傳送請求,都將使用自定義代理。 # install_opener(opener) # resp = urlopen(request) print (resp.read().decode())
如果代理需要授權驗證,簡單的方式是隻需要在ProxyHandler傳入的引數字典中,將值改為'使用者名稱:密碼@ip:埠號'這種形式,比如{"http":"myname:mypasswd@124.88.67.81:80"},複雜一點的需要建立一個密碼管理物件,下面會有介紹。
4.HTTPPasswordMgrWithDefaultRealm()
- 利用這個類建立一個密碼管理物件,用來儲存 HTTP 請求相關的使用者名稱和密碼,主要應用兩個場景:
- 驗證代理授權的使用者名稱和密碼 (
ProxyBasicAuthHandler())
- 驗證Web客戶端的的使用者名稱和密碼 (
HTTPBasicAuthHandler())
5.ProxyBasicAuthHandler(代理授權驗證)
- 在使用私密代理時,需要通過授權驗證身份
from urllib.request import HTTPPasswordMgrWithDefaultRealm,ProxyBasicAuthHandler,build_opener,Request # 私密代理授權的賬戶 user = "mr_mao_hacker" # 私密代理授權的密碼 passwd = "sffqry9r" # 私密代理 IP proxyserver = "61.158.163.130:16816" # 1. 構建一個密碼管理物件,用來儲存需要處理的使用者名稱和密碼 passwdmgr = HTTPPasswordMgrWithDefaultRealm() # 2. 新增賬戶資訊,第一個引數realm是與遠端伺服器相關的域資訊,一般沒人管它都是寫None,後面三個引數分別是代理伺服器、使用者名稱、密碼 passwdmgr.add_password(None, proxyserver, user, passwd) # 3. 構建一個代理基礎使用者名稱/密碼驗證的ProxyBasicAuthHandler處理器物件,引數是建立的密碼管理物件 # 注意,這裡不再使用普通ProxyHandler類了 proxyauth_handler = ProxyBasicAuthHandler(passwdmgr) # 4. 通過 build_opener()方法使用這些代理Handler物件,建立自定義opener物件,引數包括構建的 proxy_handler 和 proxyauth_handler opener = build_opener(proxyauth_handler) request = urllib2.Request("https://www.baidu.com/") resp = opener.open(request) print (resp.read().decode())
注:通常使用者名稱和密碼不直接寫在程式中,而是存放在環境變數,或者單獨寫入一個模組,然後從模組匯入
6.HTTPBasicAuthHandler(WEB客戶端授權驗證)
- 有些Web伺服器(包括HTTP/FTP等)訪問時,需要進行使用者身份驗證,爬蟲直接訪問會報HTTP 401 錯誤,表示訪問身份未經授權
- 如果我們有客戶端的使用者名稱和密碼,只需要將上述代理授權驗證程式碼中的ProxyBasicAuthHandler改成HTTPBasicAuthHandler即可
7.Cookies
- Cookies在爬蟲方面最典型的應用是判定註冊使用者是否已經登入網站,使用者可能會得到提示,是否在下一次進入此網站時保留使用者資訊以便簡化登入手續。
- 由於urllib並沒有很好的處理cookie的物件,所以在這裡我們需要用到一個別的庫,即http庫,並使用裡面的cookiejar來進行cookie的管理,該模組主要的物件有主要的物件有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar:
-
-
CookieJar:管理HTTP cookie值、儲存HTTP請求生成的cookie、向傳出的HTTP請求新增cookie的物件。整個cookie都儲存在記憶體中,對CookieJar例項進行垃圾回收後cookie也將丟失。
-
FileCookieJar (filename,delayload=None,policy=None):從CookieJar派生而來,用來建立FileCookieJar例項,檢索cookie資訊並將cookie儲存到檔案中。filename是儲存cookie的檔名。delayload為True時支援延遲訪問訪問檔案,即只有在需要時才讀取檔案或在檔案中儲存資料。
-
MozillaCookieJar (filename,delayload=None,policy=None):從FileCookieJar派生而來,建立與
Mozilla瀏覽器 cookies.txt相容
的FileCookieJar例項。 -
LWPCookieJar (filename,delayload=None,policy=None):從FileCookieJar派生而來,建立與
libwww-perl標準的 Set-Cookie3 檔案格式
相容的FileCookieJar例項。
-
- 大多數情況下,我們只需要用到CookieJar(),如果需要和本地檔案進行互動,就要用MozillaCookieJar()和LWPCookieJar(),下面就介紹幾種案例:
-
獲取cookie,並儲存到CookieJar()中
from http.cookiejar import CookieJar from urllib.request import Request,build_opener,HTTPCookieProcessor # 構建一個CookieJar物件例項來儲存cookie cookiejar = cookielib.CookieJar() # 使用HTTPCookieProcessor()來建立cookie處理器物件,引數為CookieJar()物件 handler=HTTPCookieProcessor(cookiejar) opener = build_opener(handler) # 4. 以get方法訪問頁面,訪問之後會自動儲存cookie到cookiejar中 resp = opener.open("http://www.baidu.com") ## 可以按標準格式將儲存的Cookie列印出來 cookieStr = "" for item in cookiejar: cookieStr = cookieStr + item.name + "=" + item.value + ";" ## 捨去最後一位的分號 print cookieStr[:-1]
-
訪問網站獲得cookie,並將cookie儲存在本地檔案中
from http.cookiejar import MozillaCookieJar from urllib.request import Request,build_opener,HTTPCookieProcessor # 儲存cookie的本地磁碟檔名 filename = 'cookie.txt' #宣告一個MozillaCookieJar(有save實現)物件例項來儲存cookie,之後寫入檔案 cookiejar = MozillaCookieJar(filename) # 使用HTTPCookieProcessor()來建立cookie處理器物件,引數為CookieJar()物件 handler = HTTPCookieProcessor(cookiejar) opener = build_opener(handler) response = opener.open("https://www.baidu.com/") # 儲存cookie到本地檔案 cookiejar.save()
-
從檔案中獲取cookie
from http.cookiejar import MozillaCookieJar from urllib.request import Request,build_opener,HTTPCookieProcessor #建立MozillaCookieJar(有load實現)例項物件 cookiejar = MozillaCookieJar(filename) #從檔案中讀取cookie內容到物件 cookiejar.load('cookie.txt') # 使用HTTPCookieProcessor()來建立cookie處理器物件,引數為CookieJar()物件 handler = HTTPCookieProcessor(cookiejar) opener = build_opener(handler) response = opener.open("https://www.baidu.com/")
8.處理HTTPS請求SSL證照驗證
- 最簡單的方法就是通過新增忽略ssl證照驗證關閉證照驗證,由於urllib並沒有很好的處理ssl的物件,所以在這裡我們需要用到一個別的庫,即ssl庫,如下:
import ssl from urllib.request import urlopen,Request # 表示忽略未經核實的SSL證照認證 context = ssl._create_unverified_context() url = "https://www.12306.cn/mormhweb/" headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} request = Request(url,headers=headers) # 在urlopen()方法裡 指明新增 context 引數 resp = urlopen(request, context=context) print(resp.read().decode())
二、error模組
- 在urllib中主要設定了兩個異常,一個是URLError,一個是HTTPError,HTTPError是URLError的子類。
1.URLError
- URLError產生的原因主要有:
- 沒有網路連線
- 伺服器連線失敗
- 找不到指定的伺服器
- 下面訪問一個不存在的域名:
from urllib.error import URLError from urllib.request import Request,urlopen request = Request('http://www.fafafasfdaffaf.com/') try: resp = urlopen(request) except URLError as e: print(e)
2.HTTPError
- HTTPError包含了三個屬性:
- code:請求的狀態碼
- reason:錯誤的原因
- headers:響應的報頭
from urllib.error import HTTPError from urllib.request import Request,urlopen requset = Request('http://www.baidu.com/lfafdaflafapae.html') try: resp = urlopen(requset) except HTTPError as e: print(e) print(e.code) print(e.reason) print(e.headers)
三、parse模組
data引數需要用urllib.parse模組對其進行資料格式處理。
- urllib.parse.quote(url):(URL編碼處理)主要對URL中的非ASCII碼編碼處理
- urllib.parse.unquote(url):(URL解碼處理)URL上的特殊字元還原
- urllib.parse.urlencode(data):對請求資料data進行格式轉換