Python網(wǎng)絡(luò)編程之HTTP客戶端模塊urllib與urllib3
一、urllib
概述:
urllib
是Python中請求url連接的官方標(biāo)準(zhǔn)庫,就是你安裝了python,這個(gè)庫就已經(jīng)可以直接使用了,基本上涵蓋了基礎(chǔ)的網(wǎng)絡(luò)請求功能。在Python2中主要為urllib和urllib2,在Python3中整合成了urllib。
Python3.x中將urllib2
合并到了urllib
,之后此包分成了以下四個(gè)模塊:
- urllib.request: 它是最基本的http請求模塊,用來模擬發(fā)送請求
- urllib.error: 異常處理模塊,如果出現(xiàn)錯(cuò)誤可以捕獲這些異常
- urllib.parse: 一個(gè)工具模塊,提供了許多URL處理方法,如:拆分、解析、合并等
- urllib.robotparser:主要用來識(shí)別網(wǎng)站的robots.txt文件,然后判斷哪些網(wǎng)站可以爬
二、urllib.parse模塊
它支持如下協(xié)議的URL處理:file,ftp,gopher,hdl,http,https,imap,mailto,mms,news,nntp,prospero,rsync,rtsp,rtspu,sftp,sip,sips,snews,svn,snv+ssh,telnet,wais
1、urlparse()、urlunparse():將url字符串解析成元組
語法:urllib.parse.urlparse(urlstring,scheme='',allow_fragments=True)
可以傳遞3個(gè)參數(shù)
- urlstring:待解析的URL,字符串
- scheme:它是默認(rèn)的協(xié)議,如http或者h(yuǎn)ttps,URL如果不帶http協(xié)議,可以通過scheme來指定,如果URL中制定了http協(xié)議則URL中生效
- allow_fragments:是否忽略fragment即錨點(diǎn),如果設(shè)置為False,fragment部分會(huì)被忽略,反之不忽略
該方法可以實(shí)現(xiàn)URL的識(shí)別和分段,分別是scheme(協(xié)議),netloc(域名),path(路徑),params(參數(shù)),query(查詢條件),fragment(錨點(diǎn))
import urllib.parse url = "http://www.baidu.com" parsed = urllib.parse.urlparse(url) print(parsed) # 輸出:ParseResult(scheme='http', netloc='www.baidu.com', path='', params='', query='', fragment='') #返回的是一個(gè)parseresult類型的元組對象,可以通過屬性或者索引來獲取值
與urlparse()相反,urlunparse通過列表或者元祖的形式接受一個(gè)可迭代的對象,實(shí)現(xiàn)URL構(gòu)造
from urllib.parse import urlunparse data=['http','www.baidu.com','index.html','user','a=6','comment'] print(urlunparse(data)) #構(gòu)造一個(gè)完整的URL #output #http://www.baidu.com/index.html;user?a=6#comment
2、urlsplit()、urlunsplit():URL分割與組合
與urlparse()方法類似,它會(huì)返回5個(gè)部分,只是把params合并到path中。
from urllib.parse import urlsplit result = urlsplit('http://www.baidu.com/index.html;user?id=5#comment') print(result) print(result.query) # output # SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment') # id=5
與urlunparse()類似,它也是將鏈接的各部分組合完整的鏈接的方法,傳入的參數(shù)也是可迭代的對象,如列表元祖等,唯一的區(qū)別是長度必須是5個(gè),它省略了params
from urllib.parse import urlsplit,urlunsplit data=['http','www.baidu.com','index.html','a=5','comment'] result=urlunsplit(data) print(result) #output #http://www.baidu.com/index.html?a=5#comment
3、urlencode()、parse_qs():查詢字符串與字典類型轉(zhuǎn)換
urlencode() 將dict中的鍵值對以連接符&劃分。
urlencode()在構(gòu)造GET請求參數(shù)時(shí)很有用,可以將字典類型的請求數(shù)據(jù)轉(zhuǎn)變?yōu)閡rl編碼
import urllib.parse dic = {'name':'melon','age':18} data = urllib.parse.urlencode(dic) print(data) #age=18&name=melon
parse_qs()與urlencode()正好相反,它是用來反序列化的,如將GET參數(shù)轉(zhuǎn)換回字典格式
from urllib.parse import urlencode,parse_qs,urlsplit params = {'username':'zs','password':'123'} base_url='http://www.baidu.com' url=base_url+'?'+urlencode(params) #將字典轉(zhuǎn)化為get參數(shù) query=urlsplit(url).query #獲去URL的query參數(shù)條件 print(parse_qs(query)) #根據(jù)獲取的GET參數(shù)轉(zhuǎn)換為字典格式 #output #{'username': ['zs'], 'password': ['123']}
4、quote()、unquote():URL編碼與解碼
quote:URL編碼處理,該方法可以將內(nèi)容轉(zhuǎn)換為URL編碼的格式。
如參數(shù)中帶有中文等非ASCII碼時(shí),有時(shí)會(huì)導(dǎo)致亂碼的問題,此時(shí)用這個(gè)方法將中文字符轉(zhuǎn)化為URL編碼
from urllib.parse import quote key='中文' url='https://www.baidu.com/s?key='+quote(key) print(url) #output #https://www.baidu.com/s?key=%E4%B8%AD%E6%96%87
unquote(url):URL解碼處理,與quote()相反,URL上的特殊字符還原
from urllib.parse import quote, urlsplit, unquote key = '中文' url = 'https://www.baidu.com/s?key=' + quote(key) print(url) unq = urlsplit(url).query.split('=')[1] # 獲取參數(shù)值 print(unquote(unq)) # 解碼參數(shù)
5、urljoin():將url的根域名和新url拼合成一個(gè)完整的url
格式:urljoin(baseurl,newurl,allowFrag=None)
通過將基本URL(base)與另一個(gè)URL(url)組合起來構(gòu)建完整URL,它會(huì)使用基本URL組件,協(xié)議(schemm)、域名(netloc)、路徑(path)、來提供給URL中缺失的部分進(jìn)行補(bǔ)充,最后返回結(jié)果。
base_url提供了三項(xiàng)內(nèi)容scheme,netloc,path,如果這3項(xiàng)在新的鏈接中不存在就給予補(bǔ)充,如果新的鏈接存在就使用新的鏈接部分,而base_url中的params,query和fragment是不起作用的。
通過urljoin()方法可以實(shí)現(xiàn)鏈接的解析、拼接和生成。
import urllib.parse url = "http://www.baidu.com" new_path = urllib.parse.urljoin(url, "index.html") print(new_path) # 輸出:<a rel="external nofollow" target="_blank">http://www.baidu.com/index.html</a>
三、urllib.request模塊
1、urlretrieve():下載url到html文件。
urlretrieve(url,filename,reporthook,data)
不寫路徑filename則會(huì)被存為臨時(shí)文件,可以用 urllib.urlcleanup() 來清理緩存
file_name = urllib.request.urlretrieve('http://www.baidu.com','%s/baidu.html'%BASE_DIR)
2、urlopen():打開一個(gè)url的方法,返回一個(gè)文件對象,然后可以進(jìn)行類似文件對象的操作
模塊中最常用的函數(shù)為urlopen():
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
參數(shù)如下:
- url: 請求的網(wǎng)址,str類型,也可以是一個(gè)request對象
- data:要發(fā)送到服務(wù)器的數(shù)據(jù),data參數(shù)是可選的,內(nèi)容為字節(jié)流編碼格式的即bytes類型,如果傳遞data參數(shù),urlopen將使用Post方式請求。
- timeout:設(shè)置網(wǎng)站的訪問超時(shí)時(shí)間,單位為秒,如果請求超出了設(shè)置時(shí)間還未得到響應(yīng)則拋出異常,支持HTTP,HTTPS,FTP請求。
- 其他參數(shù):context參數(shù),她必須是ssl.SSLContext類型,用來指定SSL設(shè)置,此外,cafile和capath這兩個(gè)參數(shù)分別指定CA證書和它的路徑,會(huì)在https鏈接時(shí)用到。
1、urlopen的方法:
urlopen返回http.client.HTTPResponse對象,提供方法:
- read():獲取響應(yīng)返回的數(shù)據(jù),只能使用一次。
- readline():返回得是二進(jìn)制格式得頁面中得第一行
- readlines() :以二進(jìn)制格式 返回所有得數(shù)據(jù) 以列表格式保存
- fileno():
- close() :
- info():返回一個(gè)httplib.HTTPMessage 對象,表示遠(yuǎn)程服務(wù)器返回的頭信息。
- getcode():返回Http狀態(tài)碼,如果是http請求,200表示請求成功完成;404表示網(wǎng)址未找到。
- getheaders():獲取返回響應(yīng)的響應(yīng)報(bào)頭。
- geturl():返回請求的url。
在urlopen()方法中,直接寫入要訪問的url地址字符串,該方法就會(huì)主動(dòng)的訪問目標(biāo)網(wǎng)址,然后返回訪問結(jié)果。
返回的訪問結(jié)果是一個(gè)http.client.HTTPResponse對象,使用該對象的read()方法即可獲取訪問網(wǎng)頁獲取的數(shù)據(jù),這個(gè)數(shù)據(jù)是二進(jìn)制格式的,所以我們還需要使用decode()方法來將獲取的二進(jìn)制數(shù)據(jù)進(jìn)行解碼,轉(zhuǎn)換成我們可以看的懂得字符串。
import urllib.request req = urllib.request.urlopen('http://www.baidu.com') print(req.read().decode()) print(req.getheaders()) # 以列表元祖對的形式返回響應(yīng)頭信息 print(req.getheader('Content-Type')) # 返回響應(yīng)頭中的Content-Type值 print(req.info()) # 返回網(wǎng)頁的頭信息 print(req.info()['Content-Type']) # 返回響應(yīng)頭中的Content-Type值
2、for循環(huán)讀取
不需要使用read()方法 。
for line in urlopen('https://。。.html'): line = line.decode('utf-8') # Decoding the binary data to text. if 'EST' in line or 'EDT' in line: # look for Eastern Time print(line)
3、GET請求
GET請求和我們平常get訪問方式一樣,直接把參數(shù)寫到網(wǎng)址上面就好了。
import urllib.request import urllib.parse dic = {'name':'melon','age':18} data = urllib.parse.urlencode(dic) req = urllib.request.urlopen('http://127.0.0.1:8000/index?%s'%data) #通過urlopen方法訪問拼接好的url content = req.read()
4、POST請求
在urlopen()
方法中,urlopen()
默認(rèn)的訪問方式是GET,當(dāng)在urlopen()
方法中傳入data參數(shù)時(shí),則會(huì)發(fā)起POST請求。
注意:傳遞的data數(shù)據(jù)需要為bytes格式,如data=b'word=hello'。
import urllib.request import urllib.parse import json dic = {'name':'melon','age':18} data = urllib.parse.urlencode(dic) req = urllib.request.Request('http://127.0.0.1:8000/index', data.encode()) #encode:將url編碼類型的請求數(shù)據(jù)轉(zhuǎn)變?yōu)閎ytes類型 opener = urllib.request.urlopen(req) content = json.loads(opener.read().decode()) #read()方法是讀取返回bytes數(shù)據(jù)內(nèi)容,decode轉(zhuǎn)換后為str
5、請求頭參數(shù)模擬
當(dāng)我們需要模擬一些其他的參數(shù)的時(shí)候,簡單的urlopen()
方法已經(jīng)無法滿足我們的需求了,這個(gè)時(shí)候我們就需要使用下面的urllib.request
中的Request
對象來幫助我們實(shí)現(xiàn)一些其它參數(shù)的模擬,比如請求頭。
Request
對象如下所示:
# Request對象實(shí)例化 req = urllib.request.Request(url, data=None, headers={},origin_req_host=None,unverifiable=False, method=None)
- url:請求的URL,必須傳遞的參數(shù),其他都是可選參數(shù)
- data:上傳的數(shù)據(jù),必須傳bytes字節(jié)流類型的數(shù)據(jù),如果它是字典,可以先用urllib.parse模塊里的urlencode()編碼
- headers:它是一個(gè)字典,傳遞的是請求頭數(shù)據(jù),可以通過它構(gòu)造請求頭,也可以通過調(diào)用請求實(shí)例的方法add_header()來添加
例如:修改User_Agent頭的值來偽裝瀏覽器,比如火狐瀏覽器可以這樣設(shè)置:
{'User-Agent':'Mozilla/5.0 (compatible; MSIE 5.5; Windows NT)'} - origin_req_host:指請求方的host名稱或者IP地址
- unverifiable:表示這個(gè)請求是否是無法驗(yàn)證的,默認(rèn)為False,如我們請求一張圖片如果沒有權(quán)限獲取圖片那它的值就是true
- method:是一個(gè)字符串,用來指示請求使用的方法,如:GET,POST,PUT等
from urllib import request url='http://httpbin.org/post' headers={ 'User-Agent':'Mozilla/5.0 (compatible; MSIE 5.5; Windows NT)', 'Host':'httpbin.org' } #定義頭信息 dict={'name':'germey'} data = bytes(parse.urlencode(dict),encoding='utf-8') req = request.Request(url=url,data=data,headers=headers,method='POST') #req.add_header('User-Agent','Mozilla/5.0 (compatible; MSIE 8.4; Windows NT') #也可以request的方法來添加 resp = request.urlopen(req) print(resp.read().decode())
3、urllib.request的高級類
BaseHandler類:
在urllib.request模塊里的BaseHandler類,他是所有其他Handler的父類,他是一個(gè)處理器,比如用它來處理登錄驗(yàn)證,處理cookies,代理設(shè)置,重定向等
BaseHandler的子類包括:
- HTTPDefaultErrorHandler:用來處理http響應(yīng)錯(cuò)誤,錯(cuò)誤會(huì)拋出HTTPError類的異常
- HTTPRedirectHandler:用于處理重定向
- HTTPCookieProcessor:用于處理cookies
- ProxyHandler:用于設(shè)置代理,默認(rèn)代理為空
- HTTPPasswordMgr:永遠(yuǎn)管理密碼,它維護(hù)用戶名和密碼表
- HTTPBasicAuthHandler:用戶管理認(rèn)證,如果一個(gè)鏈接打開時(shí)需要認(rèn)證,可以使用它來實(shí)現(xiàn)驗(yàn)證功能
build_opener(*handlers)方法用于構(gòu)建一個(gè)自定義的OpenerDirector對象。
build.opener(handler1,handler2…)
之前的urlopen()方法就是urllib提供的一個(gè)Opener,通過Handler處理器來構(gòu)建Opener實(shí)現(xiàn)Cookies處理,代理設(shè)置,密碼設(shè)置等
Opener的方法包括:
- add_handler(handler):添加處理程序到鏈接中
- open(url,data=None[,timeout]):打開給定的URL與urlopen()方法相同
- error(proto,*args):處理給定協(xié)議的錯(cuò)誤
設(shè)置全局后既可以用urlopen()方法, 也可以用opener.open() ,不安裝的話只能用opener.open()方法
# 將這個(gè)opener設(shè)置為全局的opener,之后所有的,不管是opener.open()還是urlopen() 發(fā)送請求,都將使用自定義 request.install_opener(opener) resp = request.urlopen(url)
1、密碼驗(yàn)證:HTTPBasicAuthHandler和ProxyBasicAuthHandler
HTTPPasswordMgrWithDefaultRealm()類創(chuàng)建一個(gè)密碼管理對象,用來保存HTTP請求相關(guān)的用戶名和密碼,主要應(yīng)用兩個(gè)場景:
- 驗(yàn)證代理授權(quán)的用戶名和密碼(ProxyBasicAuthHandler())
- 驗(yàn)證web客戶端的用戶名和密碼(HTTPBasicAuthHandler())
在下面的方法中我們還用到了一個(gè)新的東西,即request.build_opener()方法,其實(shí)urlopen()就是通過構(gòu)造好了的opener對象發(fā)送請求,在這里我們使用request.build_opener()方法重構(gòu)了一個(gè)opener()對象,我們可以通過這個(gè)對象實(shí)現(xiàn)urlopen()實(shí)現(xiàn)的任何東西。
from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener from urllib.error import URLError username='username' passowrd='password' url='http://localhost' p=HTTPPasswordMgrWithDefaultRealm() #構(gòu)造密碼管理實(shí)例 p.add_password(None,url,username,passowrd) #添加用戶名和密碼到實(shí)例中 auth_handler=HTTPBasicAuthHandler(p) #傳遞密碼管理實(shí)例構(gòu)建一個(gè)驗(yàn)證實(shí)例 opener=build_opener(auth_handler) #構(gòu)建一個(gè)Opener try: result=opener.open(url) #打開鏈接,完成驗(yàn)證,返回的結(jié)果是驗(yàn)證后的頁面內(nèi)容 html=result.read().decode('utf-8') print(html) except URLError as e: print(e.reason)
2、設(shè)置Proxy代理:ProxyHandler
使用爬蟲來爬取數(shù)據(jù)的時(shí)候,如果過于頻繁的訪問,而且網(wǎng)站還設(shè)有限制的話,很有可能會(huì)禁封我們的ip地址,這個(gè)時(shí)候就需要設(shè)置代理,來隱藏我們的真實(shí)IP。
urllib提供了urllib.request.ProxyHandler()方法可動(dòng)態(tài)的設(shè)置代理IP池。將代理IP以字典形式傳入該方法,然后通過urllib.reques.build_opener()創(chuàng)建opener對象,用該對象的open()方法向服務(wù)器發(fā)送請求。
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) # 創(chuàng)建代理處理器 opener = request.build_opener(proxies) # 創(chuàng)建opener對象 resp = opener.open(url) print(resp.read().decode())
3、添加Cookie:HTTPCookieProcessor
有時(shí)候當(dāng)我們訪問一些網(wǎng)站的時(shí)候需要進(jìn)行翻頁或者跳轉(zhuǎn)等其它操作,為了防止無法訪問我們想要的數(shù)據(jù),需要讓網(wǎng)站識(shí)別我們是同一個(gè)用戶。這個(gè)時(shí)候我們就需要帶上cookie進(jìn)行訪問。
在設(shè)置cookie的時(shí)候由于urllib并沒有很好的處理cookie的對象,所以在這里我們需要用到一個(gè)別的庫,即http庫,并使用里面的cookiejar來進(jìn)行cookie的管理:
CookieJar類關(guān)系:CookieJar —-派生—->FileCookieJar —-派生—–>MozillaCookieJar和LWPCookieJar
from http import cookiejar from urllib import request cookie = cookiejar.CookieJar() # 創(chuàng)建一個(gè)cookiejar對象 cookies = request.HTTPCookieProcessor(cookie) # 使用HTTPCookieProcessor創(chuàng)建cookie處理器 opener = request.build_opener(cookies) # 并以它為參數(shù)創(chuàng)建Opener對象 resp = opener.open('https://www.baidu.com') # 使用這個(gè)opener來發(fā)起請求 # 查看之前的cookie對象,則可以看到訪問百度獲得的cookie for i in cookie: print(i)
cookies保存到文件:
1、以Mozilla型瀏覽器的cookies格式:
cookie=http.cookiejar.MozillaCookieJar(filename=fielname)
import http.cookiejar,urllib.request fielname='cookies.txt' cookie=http.cookiejar.MozillaCookieJar(filename=fielname) #創(chuàng)建保存cookie的實(shí)例,保存瀏覽器類型的Mozilla的cookie格式 handler=urllib.request.HTTPCookieProcessor(cookie) #構(gòu)建一個(gè)handler opener=urllib.request.build_opener(handler) #構(gòu)建Opener response=opener.open('http://www.baidu.com') #請求 cookie.save(ignore_discard=True,ignore_expires=True)
從文件中讀取cookies:
2、也可以保存為libwww-perl(LWP)格式的Cookies文件
cookie=http.cookiejar.LWPCookieJar(filename=fielname)
import http.cookiejar,urllib.request #fielname='cookiesLWP.txt' #cookie=http.cookiejar.LWPCookieJar(filename=fielname) #LWP格式的cookies cookie=http.cookiejar.LWPCookieJar() cookie.load('cookiesLWP.txt',ignore_discard=True,ignore_expires=True) handler=urllib.request.HTTPCookieProcessor(cookie) #構(gòu)建一個(gè)handler opener=urllib.request.build_opener(handler) #構(gòu)建Opener response=opener.open('http://www.baidu.com') #請求 print(response.read().decode('utf-8'))
當(dāng)然,如果把上面這個(gè)生成的opener對象使用install_opener方法來設(shè)置為全局的,opener對象之后的每次訪問都會(huì)帶上這個(gè)cookie。
4、證書驗(yàn)證
通過添加忽略ssl證書驗(yàn)證關(guān)閉證書驗(yàn)證,由于urllib并沒有很好的處理ssl的對象,所以在這里我們需要用到一個(gè)別的庫,即ssl庫,如下:
import ssl from urllib import request context = ssl._create_unverified_context() res = urllib.request.urlopen(request, context=context)
當(dāng)你 urllib.urlopen一個(gè) https 的時(shí)候會(huì)驗(yàn)證一次 SSL 證書,當(dāng)目標(biāo)使用的是自簽名的證書時(shí)就會(huì)出現(xiàn)一個(gè)URLError,如果是這樣可以在開頭加上
import ssl ssl._create_default_https_context = ssl._create_unverified_context
四、urllib.error模塊
urllib的error模塊定義了由request模塊產(chǎn)生的異常,如果出現(xiàn)問題,request模塊便會(huì)拋出error模塊中定義的異常。
在urllib中主要設(shè)置了兩個(gè)異常,一個(gè)是URLError,一個(gè)是HTTPError,HTTPError是URLError的子類。
1、URLError基類
URLError類來自urllib庫的error模塊,它繼承自O(shè)SError類,是error異常模塊的基類,由request模塊產(chǎn)生的異常都可以通過捕獲這個(gè)類來處理
它只有一個(gè)屬性reason,即返回錯(cuò)誤的原因
from urllib import request,error try: response=request.urlopen('https://hehe,com/index') except error.URLError as e: print(e.reason) #如果網(wǎng)頁不存在不會(huì)拋出異常,而是返回捕獲的異常錯(cuò)誤的原因(Not Found)
reason如超時(shí)則返回一個(gè)對象
import socket import urllib.request import urllib.error try: response=urllib.request.urlopen('https://www.baidu.com',timeout=0.001) except urllib.error.URLError as e: print(e.reason) if isinstance(e.reason,socket.timeout): print('time out')
2、HTTPError
它是URLError的子類,專門用來處理HTTP請求錯(cuò)誤,比如認(rèn)證請求失敗,它有3個(gè)屬性:
- code:返回HTTP的狀態(tài)碼,如404頁面不存在,500服務(wù)器錯(cuò)誤等
- reason:同父類,返回錯(cuò)誤的原因
- headers:返回請求頭
舉例:
from urllib import request,error try: response=request.urlopen('http://cuiqingcai.com/index.htm') except error.HTTPError as e: #先捕獲子類異常 print(e.reason,e.code,e.headers,sep='\n') except error.URLError as e: #再捕獲父類異常 print(e.reason) else: print('request successfully')
五、urllib.robotparser模塊
利用urllib的robotparser模塊,我們可以實(shí)現(xiàn)網(wǎng)站Robots協(xié)議的分析
1、Robots協(xié)議
也稱為爬蟲協(xié)議、機(jī)器人協(xié)議,它的全名叫做網(wǎng)絡(luò)爬蟲排除標(biāo)準(zhǔn)(Robots Exclusion Protocol),用來告訴爬蟲和搜索引擎哪些網(wǎng)頁可以抓取,哪些不可以抓取,它通常是一個(gè)robots.txt的文本文件,一般放在網(wǎng)站的根目錄下。
當(dāng)搜索爬蟲訪問一個(gè)站點(diǎn)時(shí),它首先會(huì)檢查這個(gè)站點(diǎn)根目錄下是否存在robots.txt文件,如果存在,搜索爬蟲會(huì)根據(jù)其中定義的爬去范圍來爬取,如果沒有找到,搜索爬蟲會(huì)訪問所有可直接訪問的頁面
我們來看下robots.txt的樣例:
User-agent: * Disallow: / Allow: /public/
它實(shí)現(xiàn)了對所有搜索爬蟲只允許爬取public目錄的功能,將上述內(nèi)容保存為robots.txt文件放在網(wǎng)站根目錄下,和網(wǎng)站的入口文件(index.html)放在一起
1、User-agent描述了搜索爬蟲的名稱,將其設(shè)置為*則代表協(xié)議對任何爬蟲有效,如設(shè)置為Baiduspider則代表規(guī)則對百度爬蟲有效,如果有多條則對多個(gè)爬蟲受到限制,但至少需要指定一條
一些常見的搜索爬蟲名稱:
- BaiduSpider 百度爬蟲 www.baidu.com
- Googlebot Google爬蟲 www.google.com
- 360Spider 360爬蟲 www.so.com
- YodaoBot 有道爬蟲 www.youdao.com
- ia_archiver Alexa爬蟲 www.alexa.cn
- Scooter altavista爬蟲 www.altavista.com
2、Disallow指定了不允許抓取的目錄,如上例中設(shè)置的/則代表不允許抓取所有的頁面
3、Allow一般和Disallow一起使用,用來排除單獨(dú)的某些限制,如上例中設(shè)置為/public/則表示所有頁面不允許抓取,但可以抓取public目錄
設(shè)置示例:
#禁止所有爬蟲 User-agent: * Disallow: / #允許所有爬蟲訪問任何目錄,另外把文件留空也可以 User-agent: * Disallow: #禁止所有爬蟲訪問某那些目錄 User-agent: * Disallow: /home/ Disallow: /tmp/ #只允許某一個(gè)爬蟲訪問 User-agent: BaiduSpider Disallow: User-agent: * Disallow: /
2、rebotparser模塊
用來解析robots.txt,該模塊提供了一個(gè)類RobotFileParser,它可以根據(jù)某網(wǎng)站的robots.txt文件來判斷一個(gè)抓取爬蟲時(shí)都有權(quán)限來抓取這個(gè)網(wǎng)頁
urllib.robotparser.RobotFileParser(url='')
robotparser類常用的方法:
- set_url():用來設(shè)置robots.txt文件的連接,如果在創(chuàng)建RobotFileParser對象是傳入了連接,就不需要在使用這個(gè)方法設(shè)置了
- read():讀取reobts.txt文件并進(jìn)行分析,它不會(huì)返回任何內(nèi)容,但執(zhí)行那個(gè)了讀取和分析操作
- parse():用來解析robots.txt文件,傳入的參數(shù)是robots.txt某些行的內(nèi)容,并安裝語法規(guī)則來分析內(nèi)容
- can_fetch():該方法傳入兩個(gè)參數(shù),第一個(gè)是User-agent,第二個(gè)是要抓取的URL,返回的內(nèi)容是該搜索引擎是否可以抓取這個(gè)url,結(jié)果為True或False
- mtime():返回上次抓取和分析robots.txt的時(shí)間
- modified():將當(dāng)前時(shí)間設(shè)置為上次抓取和分析robots.txt的時(shí)間
from urllib.robotparser import RobotFileParser rp = RobotFileParser() #創(chuàng)建對象 rp.set_url('https://www.cnblogs.com/robots.txt') #設(shè)置robots.txt連接,也可以在創(chuàng)建對象時(shí)指定 rp.read() #讀取和解析文件 print(rp.can_fetch('*','https://i.cnblogs.com/EditPosts.aspx?postid=9170312&update=1')) #判斷鏈接是否可以被抓取
六、urllib3庫
urllib3增加了連接池等功能,兩者互相都有補(bǔ)充的部分。許多Python的原生系統(tǒng)已經(jīng)開始使用urllib3。
urllib3提供了很多python標(biāo)準(zhǔn)庫urllib里所沒有的重要特性:
- 線程安全
- 連接池
- 客戶端SSL/TLS驗(yàn)證
- 文件分部編碼上傳
- 協(xié)助處理重復(fù)請求和HTTP重定位
- 支持gzip和deflate壓縮編碼
- 支持HTTP和SOCKS代理
- 100%測試覆蓋率
urllib3是一個(gè)第三方庫,pip安裝:
pip install urllib3
通過urllib3訪問一個(gè)網(wǎng)頁,那么必須首先構(gòu)造一個(gè)PoolManager對象,然后通過PoolMagent中的request方法或者 urlopen()方法來訪問一個(gè)網(wǎng)頁,兩者幾乎沒有任何區(qū)別。
class urllib3.poolmanager.PoolManager(num_pools = 10,headers = None,** connection_pool_kw )
生成一個(gè)PoolManager所需要的參數(shù):
- num_pools 代表了緩存的池的個(gè)數(shù),如果訪問的個(gè)數(shù)大于num_pools,將按順序丟棄最初始的緩存,將緩存的個(gè)數(shù)維持在池的大小。
- headers 代表了請求頭的信息,如果在初始化PoolManager的時(shí)候指定了headers,那么之后每次使用PoolManager來進(jìn)行訪問的時(shí)候,都將使用該headers來進(jìn)行訪問。
- ** connection_pool_kw 是基于connection_pool 來生成的其它設(shè)置
當(dāng)訪問網(wǎng)頁完成之后,將會(huì)返回一個(gè)HTTPResponse對象。
使用request()或者urlopen(),獲取GET請求的響應(yīng)內(nèi)容:
import urllib3 data = json.dumps({'abc': '123'}) 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())
使用request()或者urlopen(),進(jìn)行 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())
注意事項(xiàng):urllib3 并沒有辦法單獨(dú)設(shè)置cookie,所以如果你想使用cookie的話,可以將cookie放入到headers中
1、request()和urlopen()方法的區(qū)別:
urlopen()比request()有三個(gè)參數(shù)是不一樣的,你會(huì)發(fā)現(xiàn)request()具有fields,headers兩個(gè)參數(shù)。所以更多的也就使用 request() 方法了。
推薦使用request()來進(jìn)行訪問的,因?yàn)槭褂胷equest()來進(jìn)行訪問有兩點(diǎn)好處,
- 可以直接進(jìn)行post請求,不需要將 data參數(shù)轉(zhuǎn)換成JSON格式
- 直接進(jìn)行GET請求,不需要自己拼接url參數(shù)
語法:
- request(self, method, url, fields=None, headers=None, **urlopen_kw)
- urlopen(self, method, url, redirect=True, **kw):
2、設(shè)置代理:ProxyManager
如果你需要使用代理來訪問某個(gè)網(wǎng)站的話, 那么你可以使用 ProxyManager 對象來進(jìn)行設(shè)置
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())
到此這篇關(guān)于Python網(wǎng)絡(luò)編程之HTTP客戶端模塊urllib與urllib3的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
TensorFlow查看輸入節(jié)點(diǎn)和輸出節(jié)點(diǎn)名稱方式
今天小編就為大家分享一篇TensorFlow查看輸入節(jié)點(diǎn)和輸出節(jié)點(diǎn)名稱方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01Python+Qt身體特征識(shí)別人數(shù)統(tǒng)計(jì)源碼窗體程序(使用步驟)
這篇文章主要介紹了Python+Qt身體特征識(shí)別人數(shù)統(tǒng)計(jì)源碼窗體程序(使用步驟),本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12python庫ggpy安裝使用實(shí)例(散點(diǎn)圖創(chuàng)建)
這篇文章主要為大家介紹了python庫ggpy安裝使用實(shí)例,如何創(chuàng)建簡單的散點(diǎn)圖及制作帶有趨勢線的散點(diǎn)圖詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01Pandas中如何對DataFrame列名進(jìn)行重命名
在做數(shù)據(jù)挖掘的時(shí)候,想改一個(gè)DataFrame的column名稱,所以就查了一下,下面這篇文章主要給大家介紹了關(guān)于Pandas中如何對DataFrame列名進(jìn)行重命名的相關(guān)資料,需要的朋友可以參考下2023-04-04python實(shí)現(xiàn)簡單坦克大戰(zhàn)
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)簡單坦克大戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03基于python的socket實(shí)現(xiàn)單機(jī)五子棋到雙人對戰(zhàn)
這篇文章主要為大家詳細(xì)介紹了基于python的socket實(shí)現(xiàn)單機(jī)五子棋到雙人對戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06Python識(shí)別驗(yàn)證碼的實(shí)現(xiàn)示例
這篇文章主要介紹了Python識(shí)別驗(yàn)證碼的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09初學(xué)python的操作難點(diǎn)總結(jié)(新手必看篇)
下面小編就為大家?guī)硪黄鯇W(xué)python的操作難點(diǎn)總結(jié)(新手必看篇)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08