urllib是python內置的HTTP請求庫,無需安裝便可使用,它包含了4個模塊:html
request:它是最基本的http請求模塊,用來模擬發送請求python
error:異常處理模塊,若是出現錯誤能夠捕獲這些異常json
parse:一個工具模塊,提供了許多URL處理方法,如:拆分、解析、合併等瀏覽器
robotparser:主要用來識別網站的robots.txt文件,而後判斷哪些網站能夠爬服務器
urllib.request.urlopen(url,data=None,[timeout,],cafile=None,capath=None,cadefault=False,context=None)cookie
請求對象,返回一個HTTPResponse類型的對象,包含的方法和屬性:網絡
方法:read()、readinto()、getheader(name)、getheaders()、fileno()app
屬性:msg、version、status、reason、bebuglevel、closedssh
import urllib.request response=urllib.request.urlopen('https://www.python.org') #請求站點得到一個HTTPResponse對象 #print(response.read().decode('utf-8')) #返回網頁內容 #print(response.getheader('server')) #返回響應頭中的server值 #print(response.getheaders()) #以列表元祖對的形式返回響應頭信息 #print(response.fileno()) #返回文件描述符 #print(response.version) #返回版本信息 #print(response.status) #返回狀態碼200,404表明網頁未找到 #print(response.debuglevel) #返回調試等級 #print(response.closed) #返回對象是否關閉布爾值 #print(response.geturl()) #返回檢索的URL #print(response.info()) #返回網頁的頭信息 #print(response.getcode()) #返回響應的HTTP狀態碼 #print(response.msg) #訪問成功則返回ok #print(response.reason) #返回狀態信息
urlopen()方法可傳遞參數:socket
url:網站地址,str類型,也能夠是一個request對象
data:data參數是可選的,內容爲字節流編碼格式的即bytes類型,若是傳遞data參數,urlopen將使用Post方式請求
from urllib.request import urlopen import urllib.parse data = bytes(urllib.parse.urlencode({'word':'hello'}),encoding='utf-8')
#data須要字節類型的參數,使用bytes()函數轉換爲字節,使用urllib.parse模塊裏的urlencode()方法來說參數字典轉換爲字符串並指定編碼 response = urlopen('http://httpbin.org/post',data=data) print(response.read()) #output b'{ "args":{}, "data":"", "files":{},
"form":{"word":"hello"}, #form字段代表模擬以表單的方法提交數據,post方式傳輸數據 "headers":{"Accept-Encoding":"identity",
"Connection":"close",
"Content-Length":"10",
"Content-Type":"application/x-www-form-urlencoded",
"Host":"httpbin.org",
"User-Agent":"Python-urllib/3.5"}, "json":null, "origin":"114.245.157.49", "url":"http://httpbin.org/post"}\n'
timeout參數:用於設置超時時間,單位爲秒,若是請求超出了設置時間還未獲得響應則拋出異常,支持HTTP,HTTPS,FTP請求
import urllib.request response=urllib.request.urlopen('http://httpbin.org/get',timeout=0.1) #設置超時時間爲0.1秒,將拋出異常 print(response.read()) #output urllib.error.URLError: <urlopen error timed out> #可使用異常處理來捕獲異常 import urllib.request import urllib.error import socket try: response=urllib.request.urlopen('http://httpbin.org/get',timeout=0.1) print(response.read()) except urllib.error.URLError as e: if isinstance(e.reason,socket.timeout): #判斷對象是否爲類的實例 print(e.reason) #返回錯誤信息 #output timed out
其餘參數:context參數,她必須是ssl.SSLContext類型,用來指定SSL設置,此外,cafile和capath這兩個參數分別指定CA證書和它的路徑,會在https連接時用到。
urllib.request.Request(url,data=None,headers={},origin_req_host=None,unverifiable=False,method=None)
參數:
url:請求的URL,必須傳遞的參數,其餘都是可選參數
data:上傳的數據,必須傳bytes字節流類型的數據,若是它是字典,能夠先用urllib.parse模塊裏的urlencode()編碼
headers:它是一個字典,傳遞的是請求頭數據,能夠經過它構造請求頭,也能夠經過調用請求實例的方法add_header()來添加
例如:修改User_Agent頭的值來假裝瀏覽器,好比火狐瀏覽器能夠這樣設置:
{'User-Agent':'Mozilla/5.0 (compatible; MSIE 5.5; Windows NT)'}
origin_req_host:指請求方的host名稱或者IP地址
unverifiable:表示這個請求是不是沒法驗證的,默認爲False,如咱們請求一張圖片若是沒有權限獲取圖片那它的值就是true
method:是一個字符串,用來指示請求使用的方法,如:GET,POST,PUT等
#!/usr/bin/env python #coding:utf8 from urllib import request,parse 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的方法來添加
response = request.urlopen(req)
print(response.read())
在urllib.request模塊裏的BaseHandler類,他是全部其餘Handler的父類,他是一個處理器,好比用它來處理登陸驗證,處理cookies,代理設置,重定向等
它提供了直接使用和派生類使用的方法:
add_parent(director):添加director做爲父類
close():關閉它的父類
parent():打開使用不一樣的協議或處理錯誤
defautl_open(req):捕獲全部的URL及子類,在協議打開以前調用
Handler的子類包括:
HTTPDefaultErrorHandler:用來處理http響應錯誤,錯誤會拋出HTTPError類的異常
HTTPRedirectHandler:用於處理重定向
HTTPCookieProcessor:用於處理cookies
ProxyHandler:用於設置代理,默認代理爲空
HTTPPasswordMgr:永遠管理密碼,它維護用戶名和密碼錶
HTTPBasicAuthHandler:用戶管理認證,若是一個連接打開時須要認證,可使用它來實現驗證功能
OpenerDirector類是用來處理URL的高級類,它分三個階段來打開URL:
在每一個階段中調用這些方法的順序是經過對處理程序實例 進行排序來肯定的;每一個使用此類方法的程序都會調用protocol_request()方法來預處理請求,而後調用protocol_open()來處理請求,最後調用protocol_response()方法來處理響應。
以前的urlopen()方法就是urllib提供的一個Opener,經過Handler處理器來構建Opener實現Cookies處理,代理設置,密碼設置等
Opener的方法包括:
add_handler(handler):添加處理程序到連接中
open(url,data=None[,timeout]):打開給定的URL與urlopen()方法相同
error(proto,*args):處理給定協議的錯誤
密碼驗證:
#!/usr/bin/env python #coding:utf8 from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener from urllib.error import URLError username='username' passowrd='password' url='http://localhost' p=HTTPPasswordMgrWithDefaultRealm() #構造密碼管理實例 p.add_password(None,url,username,passowrd) #添加用戶名和密碼到實例中 auth_handler=HTTPBasicAuthHandler(p) #傳遞密碼管理實例構建一個驗證明例 opener=build_opener(auth_handler) #構建一個Opener try: result=opener.open(url) #打開連接,完成驗證,返回的結果是驗證後的頁面內容 html=result.read().decode('utf-8') print(html) except URLError as e: print(e.reason)
代理設置:
#!/usr/bin/env python #coding:utf8 from urllib.error import URLError from urllib.request import ProxyHandler,build_opener proxy_handler=ProxyHandler({ 'http':'http://127.0.0.1:8888', 'https':'http://127.0.0.1:9999' }) opener=build_opener(proxy_handler) #構造一個Opener try: response=opener.open('https://www.baidu.com') print(response.read().decode('utf-8')) except URLError as e: print(e.reason)
Cookies:
獲取網站的Cookies
#!/usr/bin/env python #coding:utf8 import http.cookiejar,urllib.request cookie=http.cookiejar.CookieJar() #實例化cookiejar對象 handler=urllib.request.HTTPCookieProcessor(cookie) #構建一個handler opener=urllib.request.build_opener(handler) #構建Opener response=opener.open('http://www.baidu.com') #請求 print(cookie) for item in cookie: print(item.name+"="+item.value)
Mozilla型瀏覽器的cookies格式,保存到文件:
#!/usr/bin/env python #coding:utf8 import http.cookiejar,urllib.request fielname='cookies.txt' cookie=http.cookiejar.MozillaCookieJar(filename=fielname) #建立保存cookie的實例,保存瀏覽器類型的Mozilla的cookie格式 #cookie=http.cookiejar.CookieJar() #實例化cookiejar對象 handler=urllib.request.HTTPCookieProcessor(cookie) #構建一個handler opener=urllib.request.build_opener(handler) #構建Opener response=opener.open('http://www.baidu.com') #請求 cookie.save(ignore_discard=True,ignore_expires=True)
也能夠保存爲libwww-perl(LWP)格式的Cookies文件
cookie=http.cookiejar.LWPCookieJar(filename=fielname)
從文件中讀取cookies:
#!/usr/bin/env python #coding:utf8 import http.cookiejar,urllib.request #fielname='cookiesLWP.txt' #cookie=http.cookiejar.MozillaCookieJar(filename=fielname) #建立保存cookie的實例,保存瀏覽器類型的Mozilla的cookie格式 #cookie=http.cookiejar.LWPCookieJar(filename=fielname) #LWP格式的cookies #cookie=http.cookiejar.CookieJar() #實例化cookiejar對象 cookie=http.cookiejar.LWPCookieJar() cookie.load('cookiesLWP.txt',ignore_discard=True,ignore_expires=True) handler=urllib.request.HTTPCookieProcessor(cookie) #構建一個handler opener=urllib.request.build_opener(handler) #構建Opener response=opener.open('http://www.baidu.com') #請求 print(response.read().decode('utf-8'))
urllib的error模塊定義了由request模塊產生的異常,若是出現問題,request模塊便會拋出error模塊中定義的異常。
1)URLError
URLError類來自urllib庫的error模塊,它繼承自OSError類,是error異常模塊的基類,由request模塊產生的異常均可以經過捕獲這個類來處理
它只有一個屬性reason,即返回錯誤的緣由
#!/usr/bin/env python #coding:utf8 from urllib import request,error try: response=request.urlopen('https://hehe,com/index') except error.URLError as e: print(e.reason) #若是網頁不存在不會拋出異常,而是返回捕獲的異常錯誤的緣由(Not Found)
reason如超時則返回一個對象
#!/usr/bin/env python #coding:utf8 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請求錯誤,好比認證請求失敗,它有3個屬性:
code:返回HTTP的狀態碼,如404頁面不存在,500服務器錯誤等
reason:同父類,返回錯誤的緣由
headers:返回請求頭
#!/usr/bin/env python #coding:utf8 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庫提供了parse模塊,它定義了處理URL的標準接口,如實現URL各部分的抽取,合併以及連接轉換,它支持以下協議的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
urllib.parse.urlparse(urlstring,scheme='',allow_fragments=True)
經過urlparse的API能夠看到,它還能夠傳遞3個參數
urlstring:待解析的URL,字符串
scheme:它是默認的協議,如http或者https,URL若是不帶http協議,能夠經過scheme來指定,若是URL中制定了http協議則URL中生效
allow_fragments:是否忽略fragment即錨點,若是設置爲False,fragment部分會被忽略,反之不忽略
1)urlparse()
該方法能夠實現URL的識別和分段,分別是scheme(協議),netloc(域名),path(路徑),params(參數),query(查詢條件),fragment(錨點)
#!/usr/bin/env python #coding:utf8 from urllib.parse import urlparse result=urlparse('http://www.baidu.com/index.html;user?id=5#comment') print(type(result),result,sep='\n') #返回的是一個元祖 print(result.scheme,result[0]) #能夠經過屬性或者索引來獲取值 print(result.netloc,result[1]) print(result.path,result[2]) print(result.params,result[3]) print(result.query,result[4]) print(result.fragment,result[5]) #output #返回結果是一個parseresult類型的對象,它包含6個部分, #分別是scheme(協議),netloc(域名),path(路徑),params(參數),query(查詢條件),fragment(錨點) <class 'urllib.parse.ParseResult'> ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment') http http www.baidu.com www.baidu.com /index.html /index.html user user id=5 id=5 comment comment
指定scheme協議,allow_fragments忽略錨點信息:
from urllib.parse import urlparse result=urlparse('www.baidu.com/index.html;user?id=5#comment',scheme='https',allow_fragments=False) print(result) #output ParseResult(scheme='https', netloc='', path='www.baidu.com/index.html', params='user', query='id=5#comment', fragment='')
2)urlunparse()
與urlparse()相反,經過列表或者元祖的形式接受一個可迭代的對象,實現URL構造
#!/usr/bin/env python #coding:utf8 from urllib.parse import urlunparse data=['http','www.baidu.com','index.html','user','a=6','comment'] print(urlunparse(data)) #構造一個完整的URL #output http://www.baidu.com/index.html;user?a=6#comment
3)urlsplit()
與urlparse()方法相似,它會返回5個部分,把params合併到path中
#!/usr/bin/env python #coding:utf8 from urllib.parse import urlsplit result=urlsplit('http://www.baidu.com/index.html;user?id=5#comment') print(result) #output SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment')
4)urlunsplit()
與urlunparse()相似,它也是將連接的各部分組合完整的連接的方法,傳入的參數也是可迭代的對象,如列表元祖等,惟一的區別是長度必須是5個,它省略了params
#!/usr/bin/env python #coding:utf8 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
5)urljoin()
經過將基本URL(base)與另外一個URL(url)組合起來構建完整URL,它會使用基本URL組件,協議(schemm)、域名(netloc)、路徑(path)、來提供給URL中缺失的部分進行補充,最後返回結果
#!/usr/bin/env python #coding:utf8 from urllib.parse import urljoin print(urljoin('http://www.baidu.com','index.html')) print(urljoin('http://www.baidu.com','http://cdblogs.com/index.html')) print(urljoin('http://www.baidu.com/home.html','https://cnblog.com/index.html')) print(urljoin('http://www.baidu.com?id=3','https://cnblog.com/index.html?id=6')) print(urljoin('http://www.baidu.com','?id=2#comment')) print(urljoin('www.baidu.com','https://cnblog.com/index.html?id=6')) #output http://www.baidu.com/index.html http://cdblogs.com/index.html https://cnblog.com/index.html https://cnblog.com/index.html?id=6 http://www.baidu.com?id=2#comment https://cnblog.com/index.html?id=6
base_url提供了三項內容scheme,netloc,path,若是這3項在新的連接中不存在就給予補充,若是新的連接存在就使用新的連接部分,而base_url中的params,query和fragment是不起做用的。經過urljoin()方法能夠實現連接的解析、拼接和生成
6)urlencode()
urlencode()在構造GET請求參數時頗有用,它能夠將字典轉化爲GET請求參數
#!/usr/bin/env python #coding:utf8 from urllib.parse import urlencode params = {'username':'zs','password':'123'} base_url='http://www.baidu.com' url=base_url+'?'+urlencode(params) #將字典轉化爲get參數 print(url) #output http://www.baidu.com?password=123&username=zs
7)parse_qs()
parse_qs()與urlencode()正好相反,它是用來反序列化的,如將GET參數轉換回字典格式
#!/usr/bin/env python #coding:utf8 from urllib.parse import urlencode,parse_qs,urlsplit params = {'username':'zs','password':'123'} base_url='http://www.baidu.com' url=base_url+'?'+urlencode(params) #將字典轉化爲get參數 query=urlsplit(url).query #獲去URL的query參數條件 print(parse_qs(query)) #根據獲取的GET參數轉換爲字典格式
#output
{'username': ['zs'], 'password': ['123']}
8)parse_qsl()它將參數轉換爲元祖組成的列表
#!/usr/bin/env python #coding:utf8 from urllib.parse import urlencode,urlsplit,parse_qsl params = {'username':'zs','password':'123'} base_url='http://www.baidu.com' url=base_url+'?'+urlencode(params) #將字典轉化爲get參數 query=urlsplit(url).query #獲去URL的query參數條件 print(parse_qsl(query)) #將轉換成列表形式的元祖對 #output [('username', 'zs'), ('password', '123')]
9)quote():該方法能夠將內容轉換爲URL編碼的格式,如參數中帶有中文時,有時會致使亂碼的問題,此時用這個方法將中文字符轉化爲URL編碼
#!/usr/bin/env python #coding:utf8 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
10)unquote():與quote()相反,他用來進行URL解碼
#!/usr/bin/env python #coding:utf8 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] #獲取參數值 print(unquote(unq)) #解碼參數
利用urllib的robotparser模塊,咱們能夠實現網站Robots協議的分析
1)Robots協議
Robots協議也稱爲爬蟲協議、機器人協議,它的全名叫作網絡爬蟲排除標準(Robots Exclusion Protocol),用來告訴爬蟲和搜索引擎哪些網頁能夠抓取,哪些不能夠抓取,它一般是一個robots.txt的文本文件,通常放在網站的根目錄下。
當搜索爬蟲訪問一個站點時,它首先會檢查這個站點根目錄下是否存在robots.txt文件,若是存在,搜索爬蟲會根據其中定義的爬去範圍來爬取,若是沒有找到,搜索爬蟲會訪問全部可直接訪問的頁面
咱們來看下robots.txt的樣例:
User-agent: * Disallow: / Allow: /public/
它實現了對全部搜索爬蟲只容許爬取public目錄的功能,將上述內容保存爲robots.txt文件放在網站根目錄下,和網站的入口文件(index.html)放在一塊兒
User-agent描述了搜索爬蟲的名稱,將其設置爲*則表明協議對任何爬蟲有效,如設置爲Baiduspider則表明規則對百度爬蟲有效,若是有多條則對多個爬蟲受到限制,但至少須要指定一條
一些常見的搜索爬蟲名稱:
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
Disallow指定了不容許抓取的目錄,如上例中設置的/則表明不容許抓取全部的頁面
Allow通常和Disallow一塊兒使用,用來排除單獨的某些限制,如上例中設置爲/public/則表示全部頁面不容許抓取,但能夠抓取public目錄
設置示例:
#禁止全部爬蟲 User-agent: * Disallow: / #容許全部爬蟲訪問任何目錄,另外把文件留空也能夠 User-agent: * Disallow: #禁止全部爬蟲訪問某那些目錄 User-agent: * Disallow: /home/ Disallow: /tmp/ #只容許某一個爬蟲訪問 User-agent: BaiduSpider Disallow: User-agent: * Disallow: /
2)robotparser
rebotparser模塊用來解析robots.txt,該模塊提供了一個類RobotFileParser,它能夠根據某網站的robots.txt文件來判斷一個抓取爬蟲時都有權限來抓取這個網頁
urllib.robotparser.RobotFileParser(url='')
robotparser類經常使用的方法:
set_url():用來設置robots.txt文件的鏈接,若是在建立RobotFileParser對象是傳入了鏈接,就不須要在使用這個方法設置了
read():讀取reobts.txt文件並進行分析,它不會返回任何內容,但執行那個了讀取和分析操做
parse():用來解析robots.txt文件,傳入的參數是robots.txt某些行的內容,並安裝語法規則來分析內容
can_fetch():該方法傳入兩個參數,第一個是User-agent,第二個是要抓取的URL,返回的內容是該搜索引擎是否能夠抓取這個url,結果爲True或False
mtime():返回上次抓取和分析robots.txt的時間
modified():將當前時間設置爲上次抓取和分析robots.txt的時間
#!/usr/bin/env python #coding:utf8 from urllib.robotparser import RobotFileParser rp = RobotFileParser() #建立對象 rp.set_url('https://www.cnblogs.com/robots.txt') #設置robots.txt鏈接,也能夠在建立對象時指定 rp.read() #讀取和解析文件 print(rp.can_fetch('*','https://i.cnblogs.com/EditPosts.aspx?postid=9170312&update=1')) #堅持連接是否能夠被抓取