網路爬蟲必備知識之urllib庫
就庫的範圍,個人認為網路爬蟲必備庫知識包括urllib、requests、re、BeautifulSoup、concurrent.futures,接下來將結合爬蟲示例分別對urllib庫的使用方法進行總結
1. urllib庫全域性內容
官方文件地址: ofollow,noindex" target="_blank">https://docs.python.org/3/library/urllib.html
urllib庫是python的內建HTTP請求庫,包含以下各個模組內容:
(1)urllib.request:請求模組
(2)urllib.error:異常處理模組
(3)urllib.parse:解析模組
(4)urllib.robotparser:robots.txt解析模組
以下所有示例都以 ping.com/" target="_blank" rel="nofollow,noindex">http://example.webscraping.com/ 網站為目標,網站預覽:
2. urllib.request.urlopen
(1)函式原型
def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, *, cafile=None, capath=None, cadefault=False, context=None):
該函式功能簡單,進行簡單的網站請求,不支援複雜功能如驗證、cookie和其他HTTP高階功能,若要支援這些功能必須使用build_opener()函式返回的OpenerDirector物件,後面介紹,埋個伏筆
(2)先寫個簡單的例子
import urllib.request url = "http://example.webscraping.com/" response = urllib.request.urlopen(url,timeout=1) print("http status:", response.status)
Line"/>
(3)data引數使用
data引數用於post請求,比如表單提交,如果沒有data引數則是get請求
import urllib.parse import urllib.request data = urllib.parse.urlencode({'name':'張三', 'password':'666777'}).encode('utf-8') print(data) response = urllib.request.urlopen('http://httpbin.org/post', data=data) print(response.read())
首先解釋下urlencode的用法,將key-value的鍵值對轉換為我們想要的格式,返回的是a=1&b=2這樣的字串,解碼使用unquote(),應為urltilib沒有提供urldecode
data1 = urllib.parse.urlencode({'name':'張三', 'password':'666777'}).encode('utf-8') print(data1) data2 = urllib.parse.unquote(data1.decode('utf-8')) print(data2)
(4)timeout引數
在某些網路情況不好或伺服器出現異常的情況下,這個時候我們需要設定一個超時時間,否則程式會一直等待下去
(5)urlopen函式返回響應物件
response = urllib.request.urlopen(url,timeout=1) for key,value in response.__dict__.items(): print(key,":", value)
返回<class 'http.client.httpresponse'="">物件,我們可以response.status獲取返回狀態,response.read()獲得響應題的內容
3. urllib.request.build_opener
前面說過了urlopen不支援headers、cookie和HTTP的高階用法,那解決的方法就是使用build_opener()函式來定義自己的opener物件
(1)函式原型
build_opener([handler1[,headler2[,....]]])
引數都是特殊處理程式物件的例項,下表列出了所有可用的處理程式物件:
CacheFTPHandler | 具有持久FTP連續的FTP處理程式 |
FileHandler | 開啟本地檔案 |
FTPHandler | 通過FTP開啟URL |
HTTPBasicAuthHandler | 基本的HTTP驗證處理 |
HTTPCookieProcessor | 處理HTTP cookie |
HTTPDefaultErrorHandler | 通過引發HTTPError異常來處理HTTP錯誤 |
HTTPDigestAuthHandler | HTTP摘要驗證處理 |
HTTPHandler | 通過HTTP開啟URL |
HTTPRedirectHandler | 處理HTTP重定向 |
HTTPSHandler | 通過安全HTTP開啟url |
ProxyHandler | 通過代理重定向請求 |
ProxyBasicAuthHandler | 基本的代理驗證 |
ProxyDigestAuthHandler | 摘要代理驗證 |
UnknownHandler | 處理所有未知URL的處理程式 |
(2)opener物件建立
這裡以設定cookie和新增代理伺服器為例進行說明
有時候爬取網站需要攜帶cookie資訊訪問,這個時候需要設定cookie,同時大多數網站都會檢測某一段事件某個IP的訪問次數,如果訪問次數過多,它會禁止你的訪問,這個時候需要設定代理伺服器來爬取資料。
proxy = urllib.request.ProxyHandler( { 'http': 'http://127.0.0.1:9743', 'https': 'https://127.0.0.1:9743' }) cjar = http.cookiejar.CookieJar() opener = urllib.request.build_opener(urllib.request.HTTPHandler, urllib.request.HTTPCookieProcessor(cjar))
(3)headers設定
headers即為請求頭,很多網站為了防止程式爬蟲爬網站照成網站癱瘓,會需要攜帶一些headers頭部資訊才能訪問,最常見的是user-agent引數
開啟網站,按F12,點網路我們會看到下面內容:
headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0)Gecko/20100101 Firefox/63.0)', 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Connection':'keep-alive', 'Host':'example.webscraping.com'}
header的設定這裡介紹兩種方法:
a. 通過urllib.request.Request物件
request = urllib.request.Request(url,headers=headers)
b. 通過OpenerDirector物件的add_headers屬性
headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0)', 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Connection':'keep-alive', 'Host':'example.webscraping.com'} cjar = http.cookiejar.CookieJar() opener = urllib.request.build_opener(urllib.request.HTTPHandler,urllib.request.HTTPCookieProcessor(cjar)) header_list = [] for key,value in headers.items(): header_list.append(key) header_list.append(value) opener.add_handler = [header_list]
(4)OpenDirector的open()函式
函式原型:
def open(self, fullurl, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
裡面有一部分程式碼:
if isinstance(fullurl, str): req = Request(fullurl, data) else: req = fullurl if data is not None: req.data = data
說明fullurl既可以是url,也可以是urllib.request.Request物件
使用:
request = urllib.request.Request(url) response = opener.open(request, timeout=1)
綜合程式碼:
def DownLoad(url): headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0)', 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Connection':'keep-alive', 'Host':'example.webscraping.com'} proxy = urllib.request.ProxyHandler( { 'http': 'http://127.0.0.1:9743', 'https': 'https://127.0.0.1:9743' }) cjar = http.cookiejar.CookieJar() opener = urllib.request.build_opener(urllib.request.HTTPHandler,urllib.request.HTTPCookieProcessor(cjar)) header_list = [] for key,value in headers.items(): header_list.append(key) header_list.append(value) opener.add_handler = [header_list] try: request = urllib.request.Request(url) response = opener.open(request, timeout=1) print(response.__dict__) except urllib.error.URLError as e: if hasattr(e, 'code'): print ("HTTPErro:", e.code) elif hasattr(e, 'reason'): print ("URLErro:", e.reason)
4. url.error異常處理
很多時候我們通過程式訪問網頁的時候,有的頁面可能會出錯,類似404,500的錯誤,這個時候就需要我們捕獲異常,從上面的最後程式碼已經看到了urllib.error的使用
except urllib.error.URLError as e: if hasattr(e, 'code'): print ("HTTPErro:", e.code) elif hasattr(e, 'reason'): print ("URLErro:", e.reason)
HTTPError是URLError的子類
URLError裡只有一個屬性:reason,即抓異常的時候只能列印錯誤資訊,類似上面的例子
HTTPError裡有三個屬性:code,reason,headers,即抓異常的時候可以獲得code,reson,headers三個資訊
5. urllib.parse
前面已經介紹過了urllib.parse.urlencode的使用,接下來再介紹三個函式:urlparse、urlunparse、urljoin
(1)urlparse
函式原型:
def urlparse(url, scheme='', allow_fragments=True):
"""Parse a URL into 6 components: <scheme>://<netloc>/<path>;<params>?<query>#<fragment> Return a 6-tuple: (scheme, netloc, path, params, query, fragment). Note that we don't break the components up in smaller bits (e.g. netloc is a single string) and we don't expand % escapes."""
意思就的對你傳入的url進行拆分,包括協議,主機地址,埠,路徑,字串,引數,查詢,片段
- protocol 協議,常用的協議是http
- hostname 主機地址,可以是域名,也可以是IP地址
- port 埠 http協議預設埠是:80埠,如果不寫預設就是:80埠
- path 路徑 網路資源在伺服器中的指定路徑
- parameter 引數 如果要向伺服器傳入引數,在這部分輸入
- query 查詢字串 如果需要從伺服器那裡查詢內容,在這裡編輯
- fragment 片段 網頁中可能會分為不同的片段,如果想訪問網頁後直接到達指定位置,可以在這部分設定
(2)urlunparse
功能和urlparse功能相反,用於將各組成成分拼接成URL
函式原型:
def urlunparse(components):
from urllib.parse import urlunparse print(urlunparse(('https','www.baidu.com','index.html','name','a=123','')))
(3)urljoin
函式的作用就是url拼接,後面的優先順序高於前面
函式原型:
def urljoin(base, url, allow_fragments=True): """Join a base URL and a possibly relative URL to form an absolute interpretation of the latter."""
例:
from urllib.parse import urljoin print(urljoin('http://www.baidu.com', 'FAQ.html')) print(urljoin('http://www.baidu.com', 'https://pythonsite.com/FAQ.html')) print(urljoin('http://www.baidu.com/about.html', 'https://pythonsite.com/FAQ.html')) print(urljoin('http://www.baidu.com/about.html', 'https://pythonsite.com/FAQ.html?question=2')) print(urljoin('http://www.baidu.com?wd=abc', 'https://pythonsite.com/index.php')) print(urljoin('http://www.baidu.com', '?category=2#comment')) print(urljoin('www.baidu.com', '?category=2#comment')) print(urljoin('www.baidu.com#comment', '?category=2'))
6. urllib.robotparser
該模組用於robots.txt內容解析
例:
from urllib.robotparser import RobotFileParser rp = RobotFileParser() rp.set_url('http://example.webscraping.com/robots.txt') print(rp.read()) url = 'http://example.webscraping.com' user_agent = 'BadCrawler' print(rp.can_fetch(user_agent,url)) user_agent = 'GoodCrawler' print(rp.can_fetch(user_agent,url))
輸出: