python爬蟲之urllib(一)
Python 3 中的 urllib 庫有四個模組,分別是urllib.request
,urllib.error
,urllib.parse
,urllib.robotparser。接下來我們對這四個模組做詳細介紹 參考:
https://docs.python.org/3/library/
一,
urllib.request
1.1 urllib.request.urlopen
request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None
引數含義:
url: 開啟一個url,該url可以是一個字串或者一個 Request 物件
data: 引數必須是一個位元組物件 ,該物件指明發送到伺服器的附加資料。如果不需要傳送資料,可以是None]
timeout: 可選的引數 timeout 引數在秒的級別規定了一個連線嘗試的阻塞等待時間(如果沒有指定該引數,
全域性的預設的超時時間將被啟用),這個引數實際上只對http,https,ftp連結有效
cafile和capath: 可選的 cafile 和 capath 引數用來為https請求指明一套可信的CA證書。cafile 必須是包含了
一套證書的單獨的檔案,capath則應該指定這些證書檔案的目錄。
ssl.SSLContext.load_verify_locations()函式中可以找到更多資訊
context: 如果 context 引數被指定,它必須是一個帶有各樣SLL選項的ssl.SSLContext例項
cadefault: 引數已經被棄用,可以不用管了。
接下來讓我看看怎麼應用
我們使用 urllib.request.urlopen() 去請求百度貼吧,並獲取到它頁面的原始碼。
import urllib.request
url = "http://tieba.baidu.com"
response = urllib.request.urlopen(url)
html = response.read() # 獲取到頁面的原始碼
print(html.decode('utf-8')) # 轉化為 utf-8 編碼
設定請求超時,有些請求可能因為網路原因無法得到響應。因此,我們可以手動設定超時時間。
當請求超時,我們可以採取進一步措施,例如選擇直接丟棄該請求或者再請求一次。
import urllib.request
url = "http://tieba.baidu.com"
response = urllib.request.urlopen(url, timeout=1)
print(response.read().decode('utf-8'))
使用 data 引數提交資料,在請求某些網頁時需要攜帶一些資料,我們就需要使用到 data 引數params 需要被轉碼成位元組流。而 params 是一個字典。我們需要使用 urllib.parse.urlencode() 將字典轉化為字串。再使用 bytes() 轉為位元組流。最後使用 urlopen() 發起請求,請求是模擬用 POST 方式提交表單資料。
import urllib.parse
import urllib.request
url = "http://xx.xx.xx.xx/chitchat"
params = { "session":"1111","question":"你好" }
data = bytes(urllib.parse.urlencode(params), encoding='utf8')
response = urllib.request.urlopen(url, data=data)
print(response.read().decode('utf-8'))
1.2 urllib.request.Request
由上我們知道利用 urlopen() 方法可以發起簡單的請求。但這幾個簡單的引數並不足以構建一個完整的請求,如果請求中需要加入headers(請求頭)、指定請求方式等資訊,我們就可以利用更強大的Request類來構建一個請求。 按照國際慣例,先看下 Request 的構造方法:
urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
url: 引數
是請求連結,這個是必傳引數,其他的都是可選引數。
data: 引數
跟 urlopen() 中的 data 引數用法相同。
headers: 引數
是指定發起的 HTTP 請求的頭部資訊。headers 是一個字典。它除了在 Request 中新增,還可以
通過呼叫 Request例項的 add_header() 方法來新增請求頭。
origin_req_host: 引數
指的是請求方的 host 名稱或者 IP 地址。
unverifiable: 引數
表示這個請求是否是無法驗證的,預設值是False。意思就是說使用者沒有足夠許可權來選擇接收
這個請求的結果。例如我們請求一個HTML文件中的圖片,但是我們沒有自動抓取影象的許可權,
我們就要將 unverifiable 的值設定成 True。
method: 引數
指的是發起的 HTTP 請求的方式,有 GET、POST、DELETE、PUT等
接下來看一個demo吧:
import urllib.parse
import urllib.request
url = 'https://fanyi.baidu.com/'
headers = {
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
}
values = {
'from': 'zh',
'to':'en',
'query':'肥豬',
'transtype':'translang',
'simple_means_flag':'3'
}
data = urllib.parse.urlencode(values).encode("utf-8")
request = urllib.request.Request(url,data,headers)
response = urllib.request.urlopen(request).read().decode("utf-8")
print(response)
1.3 urllib.request.install_opener(opener)
urllib.request.build_opener
([handler, ...])
urllib.request.
ProxyHandler
(proxies=None)
在抓取一個網站的資訊時,如果我們進行頻繁的訪問,就很有可能被網站檢測到而被遮蔽,解決這個問題的方法就是使用ip代理 。在我們接入因特網進行上網時,我們的電腦都會被分配一個全球唯一地ip地址供我們使用,而當我們頻繁訪問一個網站時,網站也正是因為發現同一個ip地址訪問多次而進行遮蔽的,所以這時候如果我們使用多個ip地址進行隨機地輪流訪問,這樣被網站檢測的概率就很小了,這時候如果我們再使用多個不同的headers,這時候就有多個ip+主機的組合,訪問時被發現率又進一步減小了
步驟:
1、ProxyHandler類可以使用ip代理訪問網頁
proxy_support = urllib.request.ProxyHandler({}),其中引數是一個字典{‘型別’:'代理ip:埠號'}
2、定製、建立一個opener
opener = urllib.request.build_opener(proxy_support)
3、安裝opener
urllib.request.install_opener(opener)
呼叫預設的opener
opener.open(url)
對於沒有設定反爬蟲機制的網站,我們只需要直接像上面那樣引入ProxyHandler類進行處理,不需要考慮模仿瀏覽器
接下來看段例子:
import urllib.request
url="https://www.baidu.com"
for i in range(0,10000):
html = urllib.request.urlopen(url)
print(html.info())
print(i)
上面程式行351行就出錯了這是由於我們在訪問的時候,網站會記下我們的ip,當我們的ip訪問量在一段時間內超過網站設定的上限值的時候,這個請求就會被拒絕了
改進後代碼:
#coding:utf-8
from urllib.request import Request
from urllib.request import urlopen
import urllib
import random
def gethtml(url,proxies):
proxy = random.choice(proxies)
proxy_support = urllib.request.ProxyHandler({"http":proxy})
opener = urllib.request.build_opener(proxy_support)
urllib.request.install_opener(opener)
html = urlopen(url)
return html
url = "https://www.baidu.com"
proxies=["101.53.101.172:9999","171.117.93.229:8118","119.251.60.37:21387","58.246.194.70:8080"]
for i in range(100):
try:
html = gethtml(url,proxies)
print(html.info())
print(i)
except:
print("故障")
1.4 urllib.request.pathname2url
(path)
urllib.request.url2pathname
(path)
暫還未研究透
1.5 urllib.request.getproxies
()
這個helper函式返回一個日程表dictionary 去代理伺服器的URL對映。掃描指定的環境變數 _proxy大小寫不敏感的方法,對所有的作業系統,當它不能找到它,從Mac OS X的Mac OSX系統配置和Windows系統登錄檔中尋找代理資訊。如果兩個大寫和小寫環境變數存在(或不一樣),小寫優先。
請注意,如果環境變數 REQUEST_METHOD已被設定,這通常表明你在CGI指令碼執行環境,此時環境變數 HTTP_PROXY(大寫 _PROXY)將被忽略。這是因為該變數可以被客戶端使用注射“代理:”HTTP頭。如果你需要使用一個HTTP代理在CGI環境中,要麼使用 ProxyHandler明確,或者確保變數名小寫(或至少是 _proxy字尾)。
1.6 urllib.request.OpenerDirector
OpenerDirector類開啟url並通過 BaseHandler連線在一起。它管理處理程式的連線,和恢復錯誤。
1.7 urllib.request.BaseHandler
這是對於所有已註冊的處理程式的基類
1.8 urllib.request.HTTPRedirectHandler
一個類來處理重定向
1.9 urllib.request.HTTPCookieProcessor(cookiejar=None)
一個類來處理HTTP cookie。
1.10 urllib.request.HTTPPasswordMgr
保持一個數據庫 (realm, uri) -> (user, password)對映。
1.11 urllib.request.HTTPPasswordMgrWithDefaultRealm
保持一個數據庫 (realm, uri) -> (user, password)對映。一個領域 None被認為是一個全方位領域,如果沒有其他搜尋領域
1.12 urllib.request.HTTPPasswordMgrWithPriorAuth
一個變體 HTTPPasswordMgrWithDefaultRealm還有一個數據庫 uri -> is_authenticated的對映。可以使用BasicAuth處理程式來確定當傳送身份驗證憑證立即而不是等待 401響應。
1.13 urllib.request.AbstractBasicAuthHandler(password_mgr=None)
這是mixin類,幫助與HTTP身份驗證,遠端主機和代理。果有password_mgr,應該是相容 HTTPPasswordMgr的。請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊。如果passwd_mgr還提供了 is_authenticated和 update_authenticated方法(見 HTTPPasswordMgrWithPriorAuth物件),然後處理程式將使用 is_authenticated結果對於一個給定的URI來決定是否傳送請求的身份驗證憑證。如果 is_authenticated返回 TrueURI,憑證傳送。如果 is_authenticated是 False憑證不傳送,然後如果 401收到響應請求傳送身份驗證憑證。如果身份驗證成功, update_authenticated被稱為設定 is_authenticated TrueURI,這樣後續請求的URI或任何super-URIs將自動包括身份驗證憑證。
在新的3.5版本:新增 is_authenticated支援。
1.14 urllib.request.HTTPBasicAuthHandler(password_mgr=None)
與遠端主機處理身份驗證。如果有password_mgr,應該是相容HTTPPasswordMgr的。請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊。HTTPBasicAuthHandler將提高 ValueError當面對一個錯誤的身份驗證方案。
1.15 urllib.request.ProxyBasicAuthHandler(password_mgr=None)
處理與代理身份的驗證。如果有password_mgr,應該是相容 HTTPPasswordMgr的。請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊。
1.16 urllib.request.AbstractDigestAuthHandler(password_mgr=None)
這是mixin類,幫助與HTTP身份驗證,遠端主機和代理。password_mgr,如果有,應該是相容的 HTTPPasswordMgr;請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊
1.17 urllib.request.HTTPDigestAuthHandler(password_mgr=None)
與遠端主機處理身份驗證。如果有password_mgr,應該是相容 HTTPPasswordMgr的;請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊。摘要式身份驗證處理程式和基本身份驗證處理器都是補充說,摘要式身份驗證總是嘗試第一次。如果主機返回一個40 x再次迴應,它傳送到基本身份驗證處理程式來處理。這個處理程式方法將提高 ValueError當面對除了消化或基本身份驗證方案。
3.3版本的變化:提高 ValueError不支援的身份驗證方案。
1.18 urllib.request.ProxyDigestAuthHandler(password_mgr=None)
處理與代理身份驗證。如果有password_mgr,應該是相容 HTTPPasswordMgr的;請參閱部分 HTTPPasswordMgr物件必須支援的介面資訊
1.19 urllib.request.HTTPHandler
一個類來處理HTTP url
1.20 urllib.request.HTTPSHandler(debuglevel=0, context=None, check_hostname=None)
一個類來處理開放的HTTPS url。在context 文和check_hostname有相同的意義 http.client.HTTPSConnection.
3.2版本的變化:context and check_hostname被補充。
1.21 urllib.request.FileHandler
開啟本地檔案
1.22 urllib.request.DataHandler
開放資料的url
1.23 urllib.request.FTPHandler
開放的FTP url
1.24 urllib.request.CacheFTPHandler
開啟FTP url,保持開啟的FTP連線快取來減少延遲
1.25 urllib.request.UnknownHandler
全方位類處理未知的url。
1.26 urllib.request.HTTPErrorProcessor
HTTP錯誤響應過程。