python爬蟲必學標准模塊——urllib和urllib3詳解


一、urllib

urllib是Python中請求url連接的官方標准庫,在Python2中主要為urllib和urllib2,在Python3中整合成了urllib。urllib中一共有四個模塊,分別如下:

  •  request:主要負責構造和發起網絡請求,定義了適用於在各種復雜情況下打開 URL (主要為 HTTP) 的函數和類
  • error:處理異常
  • parse:解析各種數據格式
  • robotparser:解析robot.txt文件

1. urllib.request模塊

模塊中最常用的函數為urllib.request.urlopen(),參數如下:

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
  •  url:  請求的網址
  •  data:要發送到服務器的數據
  •  timeout:設置網站的訪問超時時間

urlopen返回對象提供方法:

  • read() , readline() ,readlines() , fileno() , close() :對HTTPResponse類型數據進行操作
  • info():返回HTTPMessage對象,表示遠程服務器返回的頭信息
  • getcode():返回Http狀態碼。如果是http請求,200請求成功完成 ; 404網址未找到
  • geturl():返回請求的url

(1)發送簡單的GET請求:

from urllib import request response = reqeust.urlopen('https://www.baidu.com') print(response.read().decode())

在urlopen()方法中,直接寫入要訪問的url地址字符串,該方法就會主動的訪問目標網址,然后返回訪問結果,返回的訪問結果是一個    http.client.HTTPResponse對象,使用該對象的read()方法即可獲取訪問網頁獲取的數據,這個數據是二進制格式的,所以我們還需要使用decode()方法來將獲取的二進制數據進行解碼,轉換成我們可以看的懂得字符串。

(2)發送簡單的POST請求:

from urllib import reuqest response = request.urlopen('http://httpbin.org/post', data=b'word=hello') print(response.read().decode()) #decode()解碼

urlopen()方法中,urlopen()默認的訪問方式是GET,當在urlopen()方法中傳入data參數時,則會發起POST請求。注意:傳遞的data數據需要為bytes格式

(3)復雜的請求——請求頭

當我們需要模擬一些其他的參數的時候,簡單的urlopen() 方法已經無法滿足我們的需求了,這個時候我們就需要使用urllib.request中的Request對象來幫助我們實現一些其它參數的模擬,比如請求頭。

Request對象如下所示:

# Request對象實例化 req  = urllib.request.Request(url, data=None, headers={},origin_req_host=None,unverifiable=False, method=None)

舉例如下: 

  from urllib import request url = 'http://httpbin.org/get' headers = {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) \ AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'} # 需要使用url和headers生成一個Request對象,然后將其傳入urlopen方法中 req = request.Request(url, headers=headers) resp = request.urlopen(req) print(resp.read().decode())

 

(4)復雜的請求—代理IP

使用爬蟲來爬取數據的時候,如果過於頻繁的訪問,而且網站還設有限制的話,很有可能會禁封我們的ip地址,這個時候就需要設置代理,來隱藏我們的真實IP。

代理IP的原理:以本機先訪問代理IP,再通過代理IP地址訪問服務器,這樣服務器接受到的訪問IP就是代理IP地址。

urllib提供了urllib.request.ProxyHandler()方法可動態的設置代理IP池。將代理IP以字典形式傳入該方法,然后通過urllib.reques.build_opener()創建opener對象,用該對象的open()方法向服務器發送請求。

 from urllib import request url = 'http://httpbin.org/ip' proxy = {'http': '218.18.232.26:80', 'https': '218.18.232.26:80'} proxies = request.ProxyHandler(proxy) # 創建代理處理器 opener = request.build_opener(proxies) # 創建opener對象 resp = opener.open(url) print(resp.read().decode()) 

在上述的方法中我們還用到了一個新的東西,即request.build_opener()方法,其實urlopen()就是通過構造好了的opener對象發送請求,在這里我們使用request.build_opener()方法重構了一個opener()對象,我們可以通過這個對象實現urlopen()實現的任何東西。

(5)復雜的請求—cookies

有時候當我們訪問一些網站的時候需要進行翻頁或者跳轉等其它操作,為了防止無法訪問我們想要的數據,需要讓網站識別我們是同一個用戶。這個時候我們就需要帶上cookie進行訪問。

在設置cookie的時候由於urllib並沒有很好的處理cookie的對象,所以在這里我們需要用到一個別的庫,即http庫,並使用里面的cookiejar來進行cookie的管理:

from http import cookiejar from urllib import request url = 'https://www.baidu.com' # 創建一個cookiejar對象 cookie = cookiejar.CookieJar() # 使用HTTPCookieProcessor創建cookie處理器 cookies = request.HTTPCookieProcessor(cookie) # 並以它為參數創建Opener對象 opener = request.build_opener(cookies) # 使用這個opener來發起請求 resp = opener.open(url) # 查看之前的cookie對象,則可以看到訪問百度獲得的cookie for i in cookie: print(i) 

  當然,如果把上面這個生成的opener對象使用install_opener方法來設置為全局的,opener對象之后的每次訪問都會帶上這個cookie。設置全局后既可以用urlopen()方法, 也可以用opener.open() ,不安裝的話只能用opener.open()方法

# 將這個opener設置為全局的opener,之后所有的,不管是opener.open()還是urlopen() 發送請求,都將使用自定義 request.install_opener(opener) resp = request.urlopen(url)

(6)復雜的請求—證書驗證

CA(Certificate Authority)是數字證書認證中心的簡稱,是指發放、管理、廢除數字證書的受信任的第三方機構。

CA的作用是檢查證書持有者身份的合法性,並簽發證書,以防證書被偽造或篡改,以及對證書和密鑰進行管理。現實生活中可以用身份證來證明身份, 那么在網絡世界里,數字證書就是身份證。和現實生活不同的是,並不是每個上網的用戶都有數字證書的,往往只有當一個人需要證明自己的身份的時候才需要用到數字證書。普通用戶一般是不需要,因為網站並不關心是誰訪問了網站,現在的網站只關心流量。但是反過來,網站就需要證明自己的身份了。比如說現在釣魚網站很多的,比如你想訪問的是www.baidu.com,但其實你訪問的是www.daibu.com”,所以在提交自己的隱私信息之前需要驗證一下網站的身份,要求網站出示數字證書。一般正常的網站都會主動出示自己的數字證書,來確保客戶端和網站服務器之間的通信數據是加密安全的。

最簡單的方法就是通過添加忽略ssl證書驗證關閉證書驗證,由於urllib並沒有很好的處理ssl的對象,所以在這里我們需要用到一個別的庫,即ssl庫,如下:

import ssl from urllib import request context = ssl._create_unverified_context() res = urllib.request.urlopen(request, context=context)

2. urllib.error 模塊

urllib中主要設置了兩個異常,一個是URLError,一個是HTTPErrorHTTPErrorURLError的子類。

HTTPError還包含了三個屬性:

  • code:請求的狀態碼
  • reason:錯誤的原因
  • headers:響應的報頭
from urllib.error import HTTPError try: request.urlopen('https://www.jianshu.com') except HTTPError as e: print(e.code) 

3.urllib.parse 模塊

data參數需要用urllib.parse模塊對其進行數據格式處理。

urllib.parse.quote(url):(URL編碼處理)主要對URL中的非ASCII碼編碼處理

urllib.parse.unquote(url):(URL解碼處理)URL上的特殊字符還原

urllib.parse.urlencode:對請求數據data進行格式轉換

 

二、urllib3

來自官方網站的解釋:

urllib3是一個功能強大,對SAP 健全的 HTTP客戶端。許多Python生態系統已經使用了urllib3,你也應該這樣做。                    

通過urllib3訪問一個網頁,那么必須首先構造一個PoolManager對象,然后通過PoolMagent中的request方法或者 urlopen()方法來訪問一個網頁,兩者幾乎沒有任何區別。

class urllib3.poolmanager.PoolManager(num_pools = 10,headers = None,** connection_pool_kw )

生成一個PoolManager所需要的參數:

  • num_pools 代表了緩存的池的個數,如果訪問的個數大於num_pools,將按順序丟棄最初始的緩存,將緩存的個數維持在池的大小。
  • headers 代表了請求頭的信息,如果在初始化PoolManager的時候制定了headers,那么之后每次使用PoolManager來進行訪問的時候,都將使用該headers來進行訪問。
  • ** connection_pool_kw 是基於connection_pool 來生成的其它設置

當訪問網頁完成之后,將會返回一個HTTPResponse對象,可以通過如下的方法來讀取獲取GET請求的響應內容:

import urllib3 http = urllib3.PoolManager(num_pools=5, headers={'User-Agent': 'ABCDE'}) resp1 = http.request('GET', 'http://www.baidu.com', body=data) # resp2 = http.urlopen('GET', 'http://www.baidu.com', body=data) print(resp2.data.decode()) 

除了普通的 GET 請求之外,你還可以使用request()或者urlopen()進行 POST 請求:

import urllib3 import json data = json.dumps({'abc': '123'}) http = urllib3.PoolManager(num_pools=5, headers={'User-Agent': 'ABCDE'}) resp1 = http.request('POST', 'http://www.httpbin.org/post', body=data,timeout=5,retries=5) #resp2 = http.urlopen('POST', 'http://www.httpbin.org/post', body=data,timeout=5,retries=5) print(resp1.data.decode()) 

注意事項

  • urllib3 並沒有辦法單獨設置cookie,所以如果你想使用cookie的話,可以將cookie放入到headers中

 

request()和urlopen()方法:

request(self, method, url, fields=None, headers=None, **urlopen_kw) urlopen(self, method, url, redirect=True, **kw):

差距還是很明顯的,urlopen()比request()有三個參數是不一樣的,你會發現request()具有fields,headers兩個參數。而且相比之下 reuqest() 方法還是比較符合人們的使用方式的,所以更多的也就使用 request() 方法了。

推薦使用request()來進行訪問的,因為使用request()來進行訪問有兩點好處,

  • 可以直接進行post請求,不需要將 data參數轉換成JSON格式
  • 直接進行GET請求,不需要自己拼接url參數
import urllib3 import json data = {'abc': '123'} http = urllib3.PoolManager(num_pools=5, headers={'User-Agent': 'ABCDE'}) resp1 = http.request('POST', 'http://www.httpbin.org/post', fields=data) # resp1 = http.request('GET', 'http://www.httpbin.org/post', fields=data) print(resp1.data.decode()) 

 

雖然urlopen()沒有fields,但這並不代表它不能進行POST訪問,相反,兩個方法都有一個body屬性,這個屬性就是我們平時POST請求時所熟知的data參數,只不過你需要將data字典先轉換成JSON格式再進行傳輸。

不過特別要聲明的一點是 fielder 和 body 中只能存在一個。

2.2 urllib3 ProxyManager

如果你需要使用代理來訪問某個網站的話, 那么你可以使用 ProxyManager 對象來進行設置

def __init__(self, proxy_url, num_pools=10, headers=None,proxy_headers=None, **connection_pool_kw): 

ProxyManager和PoolManager的方法基本完全相同,這里舉個簡單的小例子,就不再贅述了:

import urllib3 import json data = {'abc': '123'} proxy = urllib3.ProxyManager('http://50.233.137.33:80', headers={'connection': 'keep-alive'}) resp1 = proxy.request('POST', 'http://www.httpbin.org/post', fields=data) print(resp1.data.decode())


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM