在python3中爬蟲常用基本庫為urllib以及requests 本文主要描述urllib的相關內容 urllib包含四個模塊:requests——模擬發送請求 error——異常處理模塊 parse——關於URL處理方法的工具模塊 robotparser——通過識別網站robot.txt判斷網站 ...
在python3中爬蟲常用基本庫為urllib以及requests
本文主要描述urllib的相關內容
urllib包含四個模塊:requests——模擬發送請求
error——異常處理模塊
parse——關於URL處理方法的工具模塊
robotparser——通過識別網站robot.txt判斷網站的可爬取內容
一、發送請求
urllib庫發送請求主要使用request模塊中的兩個內容:urlopen()方法以及Requests類,其中Requests類是結合urlopen()方法來使用的。
首先,看一下urlopen()方法的API:
urllib.request.urlopen(url,data=None,[timeout,]*,cafile=None,capath=None,context=None)
參數詳細介紹:url——必填內容
data——POST方式請求時,需要傳遞該參數。傳遞該參數時需要註意要將參數轉化為位元組流編碼格式(bytes類型)
timeout——設置超時時間,當超出該時間時,拋出超時異常。使用該參數有兩種方式:timeout=5或者timeout=(5,30),前者表示connect+read時間為5s,後者表示connect時間為5s+read時間30s
context——參數值必須是ssl.SSLContext類型
cafile,capath——指定CA整數以及路徑
註:bytes()方法的使用——bytes(string,code) 第一個參數用來指定字元串,第二個參數用來指定編碼格式
將dict轉化為string的方法 urllib.parse.urlencode(dict)
實例應用:
1 import urllib.parse 2 import urllib.request 3 4 url = 'http://httpbin.org/post' 5 data = bytes(urllib.parse.urlencode({'name':'value'}), encoding='utf8') 6 timeout = (3, 10) 7 8 response = urllib.request.urlopen(url,data=data,timeout=timeout) 9 10 # 輸出response的類型 11 print(type(response)) 12 # 輸出網頁內容 13 print(response.read().decode('utf8'))
通過type(response),我們發現urlopen()是返回一個HTTPResponse類型對象,該對象主要包括以下方法和屬性
read()——返回網頁內容
getheaders()——返迴響應頭信息
getheader(name)——返回屬性名為name的響應頭中name對應的屬性值
msg、version、status(狀態碼)、reason、debuglevel、closed
接下來,看一下Request類構建方法,該方法主要是解決urlopen()方法不容易解決的請求構建問題,例如添加Headers等信息
Request類的API:
urllib.request.Request(url,data=None,headers={},origin_req_host=None,unverifiable=False,method=None)
url——必傳參數
data——bytes()類型
headers——字典,請求頭信息,常用User-Agent信息來偽裝請求頭
origin_req_host——請求方的host方法或者IP地址
unverifiable——指請求是否是無法認證的,當我們沒有抓取許可權時,該參數的值為True,預設為False
method——參數值為字元串,指定請求使用的方法,比如GET、POST等
實例應用:
1 from urllib import request,parse 2 3 url = 'http://httpbin.org/post' 4 headers = { 5 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; WIndows NT)' 6 'Host': 'httpbin.org' 7 } 8 dict = { 9 'name': 'Germey' 10 } 11 data = bytes(parse.urlcode(dict), encoding='utf8') 12 13 req = request.Request(url=url,data=data,headers=headers,method='POST') 14 response = request.urlopen(req)
此外,對於一些更高級的操作(Cookies處理、代理設置等)需要藉助Handler工具
在urllib.request模塊中BaseHandler類提供了幾種最基本的方法:default_open()、protocol_request()等,其他各種Handler子類都會繼承該類。
HTTPDefaultErrorHandler:處理HTTP響應錯誤,錯誤拋出HTTPError類型異常
HTTPRedirectHandler:處理重定向
HTTPCookieProcessor:用於處理Cookies
ProxyHandler:用於設置代理,預設代理為空
HTTPPasswordMgr:用於管理密碼,維護了用戶名和密碼的表
HTTPBasicAuthHandler:用於管理認證,打開一個鏈接時需要認證時則使用該子類
使用以上子類時,需要藉助OpenerDirector類,可以稱為Opener。上面講述的urlopen()方法實際上就是urllib為我們提供的Opener,當我們使用上述子類的操作時,就需要藉助Handler來構建Opener
實例應用:
# 認證 from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener from urllib.error import URLError username = 'username' password = 'password' url = 'http://localhost:5000/' # 構建密碼管理 p = HTTPPasswordMgrWithDefaultRealm() p.add_password(None, url, username, paaword) # 構建認證管理 auth_handler = HTTPBasicAuthHandler(p) opener = build_opener(auth_handler) try: response = opener.open(url) html = response.read(),decode('utf8') print(html) except URLError as e: print(e.reason) # 代理 from urllib.request import ProxyHandler, build_opener proxy_handler = ProxyHandler({ 'http': 'http://127.0.0.1:9743' 'https': 'https://127.0.0.1:9743' }) opener = builder_opener(proxy_handler) # Cookies獲取 import http.cookiejar, urllib.request cookie = http.cookiejar.CookieJar() handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open(url) for item in cookie: print(item.name+'='+item.value) # Cookie輸出到文件 filename = 'cookies.txt' cookie = http.cookiejar.MozillaCookieJar(filename) #保存成Mozilla型瀏覽器的Cookie格式 cookie = http.cookiejar.LWPCookieJar(filename) #保存為LWP格式 handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open(url) cookie.save(ignore_discard=True, ignore_expires=True) # 從文件中讀取cookie cookie = http.cookiejar.LWPCookieJar() cookie.load(filename, ignore_discard=True, ignore_expires=True) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open(url)
二、異常處理
通過合理的捕獲異常可以做出更準確的異常判斷,使得程式更加穩健。
常用的異常處理類有URLError類和HTTPError類,其中HTTPError類是URLError類的子類。有request模塊產生的異常都可以通過捕獲URLError類來實現,它有一個屬性reason,返回錯誤的原因。HTTPError專門用來處理HTTP請求錯誤,它有三個屬性:code、reason以及headers,code返回HTTP狀態碼,reason返回錯誤原因,headers返回請起頭。
reason屬性返回可能是字元串,也可能是對象。
在具體使用時,我們可以先選擇捕獲子類錯誤,再選擇捕獲父類錯誤。
實例應用:
1 from urllib import request,error 2 ''' 3 上述引用就相當於 4 import urllib.request 5 import urllib.error 6 ''' 7 8 url = 'http://www.baidu.com' 9 try: 10 response = request.urlopen(url) 11 except error.HTTPError as e: 12 print(e.reason, e.code, e.headers, sep='\n') 13 except error.URLError as e: 14 print(e.reason) 15 else: 16 print('Reuqest Successfully')
三、url鏈接解析
urllib庫裡面提供的parse模塊,它定義了處理URL標準介面,下麵我們介紹一下該模塊的常用方法。
urlparse()——實現URL識別和分段,該方法會將url拆分成6個部分。分別是:scheme(協議)、netloc(功能變數名稱)、path(訪問路徑)、params(參數)、query(參數)以及fragment(錨點),這六個元素構成的url鏈接格式為
scheme://netloc/path;params?query#fragment
urlparse()的api用法如下:
urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
參數詳解:
urlstring:必填項,待解析的URL
scheme:選填項,預設的協議,當鏈接沒有協議信息是,會使用該預設協議
allow_fragments:選填項,該參數為是否fragment。當fragment=False時,原有的fragement部分就會被解析為 path、params或者query的一部分,而fragment部分會變為空
此外,urlparse()的返回值是一個元組,我們可以根據索引順序來獲取我們需要的內容,也可以根據屬性名來獲取
實例應用:
1 from urllib.parse import urlparse 2 3 url = 'http://www.baidu.com/index.html#comment' 4 result = urlparse(url,allow_fragments=False) 5 6 print(result.scheme, result[0], sep='\n')
接下來,我們看一下有關鏈接解析的其他方法:
urlunparse()——根據參數的到鏈接,相當於urlparse()方法的逆轉。值得註意的是,此方法的可迭代對象參數的長度必須為6
from urllib.parse import urlunparse data = ['http',www.baidu.com','index.html','user','a=6','comment'] print(urlunparse(data))
urlsplit()——與urlparse()類似,也是用來分解url的。不同的是,該方法的返回值長度僅為5,其中,不再單獨解析params,而是歸到path裡面
urlunsplit()——與urlunparse()類似,是urlsplit()的逆轉,參數長度為5
urljoin()——生成鏈接的另外一種方法,API如下:
urllib.parse.urljoin(base_url,url)
base_url:基礎鏈接。該方法會解析base_url的scheme、netlocal以及path
url:待處理的新鏈接。其形式多樣化,可包含url的6個部分的全部內容,也可以是僅包含其中某幾個連續的內容。
當新鏈接內容缺失時,該方法會根據base_url的解析信息對其缺失部分進行補充,並返回補充後的新鏈接或不需補充的待處理鏈接
應用實例:
from urllib.parse import urljoin urljoin('http://baidu.com/index.html','FAQ.html')
值得註意的是,即使base_url中包含params、query以及fragment部分,也是不起任何作用的
urlencode()——序列化GET請求參數。所謂序列化就是將字典轉化為參數所需的字元串
1 from urllib.parse import urlencode 2 3 params = { 4 'name': 'germey' 5 'age': 22 6 } 7 base_url = 'http://www.baidu.com' 8 url = base_url+urlencode(params) 9 print(url)
parse_qs()——反序列化
parse_qsl()——將參數化為元組組成的列表
1 from urllib.parse import parse_qs,parse_qsl 2 3 query = 'name=germey&age=22' 4 print(parse_qs(query)) 5 print(parse_qsl(query))
quote()——將中文字元轉化為URL編碼
unquote()——將URL解碼
1 from urllib.parse import quote 2 3 keyword = '壁紙' 4 url = 'http://www.baidu.com/s?wd=' + quote(keyword) 5 print(url) 6 print(unquote(url))
四、Robots協議
經過這麼久的學習,終於到了urllib庫的最後一個模塊robotparser模塊,通過該模塊我們可以實現網站Robots協議的分析
首先,我們瞭解一下什麼是Robots協議
Robots協議也稱為爬蟲協議,全名是網路爬蟲排除標準。用途是來告訴爬蟲和搜索引擎哪些頁面可以抓取,而哪些不可以。通常是一個叫做robots.txt的文本文件。通常放在網站的根目錄下。當搜索爬蟲訪問站點時,會首先檢查是否存在該文件,若存在,再根據定義的爬取範圍來爬取信息。
robots.txt範例
User-agent: *
Disallow: /
Allow: /public/
其中,User-agent描述了搜索爬蟲的名稱,其值也可以是BaiduSpider、Googlebot等;Disallow指定了不允許抓取的目錄,‘/’表示不允許抓取所有頁面;Allow用來排除某些例外,通常和Disallow結合使用,/public/表示可以抓取public目錄,相當於白名單的作用
瞭解Robots協議後,我們可以通過robotparser模塊來解析robots.txt。robotparser模塊API如下:
urllib.robotparser.RobotFileParser(url='')
我們可以在使用該模塊時,直接傳入url,也可以通過set_url方法來設置。我們看一下該模塊的常用方法:
set_url()——設置robots.txt文件位置鏈接
read()——讀取robots.txt併進行分析,值得註意的是,我們一定要執行該方法以完成對文件的讀取,雖然該方法並沒有返回值
parse()——解析robots.txt文件,傳入參數是robots.txt某些行的內容
can_fetch()——該方法傳入兩個參數,第一個是User-agent,第二個是要抓取的URL。返回布爾型結果,表示User-agent是否可以抓取該頁面
mtime()——上次抓取和分析robots.txt的時間,目的在於定期檢查robots.txt文件
modtime()——將當前時間設置為上次抓取和分析時間
實例應用:
1 from urllib.robotparser import RobotFileParser 2 3 rp = RobotFileParser() 4 rp.set_url('http://www.jianshu.com/robots.txt') 5 rp.read() 6 # rp.parse(rp.read().decode('utf8').split('\n')) 7 print(rp.can_fetch('*','http://www.jianshu.com/p/b67554025d7d')) 8 print(rp.can_fetch('*','http://www.jianshu.com/search?q=python&page=1&type=collections'))
小編終於寫完該部分的內容了,準備去休息啦。
在這裡,小編推一下自己新建的公眾號,歡迎大家積極前來探討問題。