urllib库是Python内置的HTTP请求库,包含4个模块html
1)request:它是最基本的HTTP请求模板,能够用来模拟发送请求浏览器
2)error:异常处理模块,若是出现请求错误,咱们能够捕获这些异常,而后能够进行重试或其余操做来保证程序不会意外终止服务器
3)parse:一个工具模块,提供许多URL处理方法,如拆分,解析合并等cookie
4)robotparser:主要用来识别网站的robots.txt文件,而后判断哪些网站能够爬,哪些网站不能够爬网络
使用urllib的request模块,能够方便地实现请求的发送并获得响应ide
urlopen()方法除了第一个参数能够传递URL外,还能够传递其余内容,好比data,timeout等工具
A.data参数post
data参数是可选的。若是要添加该参数,而且若是它是字节流编码格式的内容,即bytes类型,则须要经过bytes()方法转化。若是传递了这个参数,则它的请求方式再也不是GET方式,而是POST方式fetch
B.timeout参数网站
timeout参数用于设置超时时间,单位为秒,若是请求超出了设置时间,尚未获得响应,就会抛出异常,若是不知道该参数,就会使用全局默认时间,它支持HTTP,HTTPS,FTP请求
C.其余参数
context参数,它是必须是ssl.SSLContext类型用来指定SSL设置
此外,cafile和capath这两个参数用来指定CA证书和他的路径,这个在请求HTTPS连接时有用
urlopen()方法能够实现最基本请求的发起,但其简单的参数并不足以构建一个完整的请求,若是须要在请求中/加入Headers等信息,则须要利用强大的Request来构建
Request参数构造方法
1)第一个参数url用于请求URL,这是必传参数,其余都是可选参数 2)第二个参数data若是要传,必须传bytes(字节流)类型的,若是它是字典,能够先用urllib。parse模块里的urlencode()编码 3)第三个参数headers是一个字典,它就是请求头,能够在构造请求时经过headers参数直接构造,也能够经过调用请求实例的add_header()方法调用 4)第四个参数origin_req_host指的是请求方的host名称或者IP地址 5)第五个参数unverifiable表示这个请求是不是没法验证的,默认为false,意思是用户没有足够的权限来选择接收这个请求的结果 6)第六个参数method是一个字符串,用来指示请求使用的方法,如GET,POST和PUT等
from urllib import request,parse url="http://httpbin.org/post" headers={ 'User-Agent':'Mozilla/4.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') response=request.urlopen(req) print(response.read().decode("utf-8"))
对于一些高级操做,如Cookies处理,代理设置等,就要用到Handler,能够把它理解为各类处理器,有专门处理登陆验证的,有处理Cookies的,有处理代理设置的
urllib.request模块里的BaseHandler类是全部其余Handler的父类,它提供了最基本的方法
下面是各类Handler子类继承这个BaseHandler类
1)HTTPDefaultErroeHandler: 用于处理HTTP响应错误,错误都会抛出HTTPError类型的异常 2)HTTPRedirectHandler: 用于处理重定向 3)HTTPCookieProcessor: 用于处理Cookies 4)ProxyHandler:用于设置代理,默认代理为空 5)HTTPPasswordMgr:用于管理密码,它维护了用户名和密码的表 6)HTTPBasicAuthHandler:用于管理认证,若是一个连接打开时须要认证,那么能够用它来解决认证问题
另一个比较重要的类是OpenerDirector,咱们能够称为Opener,以前用过的urlopen()实际上就是urllib为咱们提供的一个Opener
咱们须要实现更高级的功能,因此须要深刻一层进行配置,使用更底层的实例来完成操做,因此就用到Opener,Opener可使用open()方法,返回类型和urlopen()同样
利用Hanler来构建Opener
用法:
A.验证
有些网站须要输入用户名和密码,验证成功后才能查看页面,要请求这样的页面,须要借助HTTPBasicAuthHandler就能够完成
from urllib.request import HTTPPasswordWithDefaultRealm,HTTPBasicAuthHandler,build_opener from urllib.error import URLError username='username' password='password' url='http://localhost:5000/' p=HTTPPasswordWithDefaultRealm() p.add_passsword(None,url,username,password) auth_handler=HTTPBasicAuthHandler(p) opener=built_opener(auth_handler) try: result=opener.open(url) html=result.read().decode('utf-8') print(html) except URLError as e: print(e.reason)
B.代理
在作爬虫时,若是要添加代理,能够这样作
from urllib.error import URLError 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=build_opener(proxy_handler) try: response=opener.open('https://www.baidu.com') print(resposne.read().decode("urtf-8")) except URLError as e: print(e.reason)
使用ProxyHandler,其参数是一个字典,键名是协议类型(如HTTP或HTTTPS),键值是代理连接,能够添加多个代理
C.Cookies
Cookies的处理就须要相关的Handler
from urllib.request import HTTPCookieProcessor,build_opener import http.cookiejar cookie=http.cookiejar.CookieJar() handler=HTTPCookieProcessor(cookie) opener=build_opener(handler) response=opener.open("https://www.baidu.com") for i in cookie: print(i.name+'='+i.value)
这样能够看到每条Cookie的名称和值
将cookie以文本形式保存代码以下
import http.cookiejar,urllib.request filename='Cookies.text' cookie=http.cookiejar.MozillaCookieJar(filename) handler=urllib.request.HTTPCookieProcessor(cookie) opener=urllib.request.build_opener(handler) response=opener.open("https://www.baidu.com") cookie.save(ignore_discard=True,ignore_expires=True)
MozillaCookieJar才生成文件时会用到,时CookieJar的子类。能够用来处理Cookies和文件相关的事件,好比读取和保存Cookies,能够将Cookies保存成Mozilla型浏览器的Cookies格式
LWPCookieJar也能够读取和保存Cookies,可是保存的格式和MozillaCookieJar的不同,它会保存成libwww-perl(LWP)格式的Cookies文件
从文件中读取:
import http.cookiejar,urllib.request cookie=http.cookiejar.MozillaCookieJar() cookie.load('Cookies.txt',ignore_discard=True,ignore_expires=True) handler=urllib.request.HTTPCookieProcessor(cookie) opener=urllib.request.build_opener(handler) response=opener.open("https://www.baidu.com") print(response.read().decode('utf-8'))
urllib的error模块定义了由request模块产生的异常。若是出现了问题,request模块便会抛出error中定义的异常
A.URLError
URLError类来自urllib库的error模块,它继承自OSError类,是error异常模块的基类,有request模块生的异常均可以经过这个类来处理
from urllib import request,error try: response=request.urlopen("https://www.dengwenxiong.com") except error.URLError as e: print(e.reason)
B.HTTPError
它是URLError的子类,专门用来处理HTTP请求错误,好比认证请求失败,它有三个属性
1)code:返回HTTP状态码,好比404表示网页不存在,500表示服务器内部错误 2)reason:同父类同样,用于返回错误的缘由 3)headers:返回请求头
from urllib import request,error try: response=request.urlopen("https://cuiqingcai.com/index.htm") except error.HTTPError as e: print(e.code,e.reason,e.headers)
urllib库还提供了parse模块,它定义了处理URL的标准接口,例如实现URL各部分的抽取,合并以及连接转换
该方法能够实现URL的识别和分段
from urllib.parse import urlparse result=urlparse("https://www.dengwenxiong/index.html;user?id=5#comment") print(result)
ParseResult(scheme='https', netloc='www.dengwenxiong', path='/index.html', params='user', query='id=5', fragment='comment')
其将url分为6部分scheme表示协议,netloc表示域名,path表示访问路径,params表示参数,query表示查询条件,fragment表示锚点,用于直接定位页面内部的下拉位置
urlparse()有三个参数:urlstring,scheme和allow_fragments
uslstring是必填项,即待解析的URL
scheme:它是默认的协议,假如连接没有协议,会将这个做为默认的协议
allow_fragments:便是否忽略fragment,若是它被设置为false,fragment部分被忽略,它会被解析成path,parameters或者query的一部分,而fragment部分为空
它接受的参数是一个可迭代对象,可是它的长度必须是6,不然会抛出参数数量不足或者过多的问题
from urllib.parse import urlunparse data=('https','www.baidu.com','index.html','user','a=6','comment') print(urlunparse(data))
这个方法和urlparse()方法很是类似,只不过它不在单独解析params这一部分,只返回5个结果,params会合并到path中,能够用属性获取值,也能够用索引来获取
与urlunparse()相似,也是将连接各个部分组合成完整连接的方法,传入的参数也是一个可迭代对象,惟一的区别是长度必须为5
生成连接除了上面两个方法,还有就是urljoin()方法,能够提供一个base_url(基础连接)做为第一个参数,将新的连接做为第二个参数,该方法会分析base_url的scheme,netloc和path这三个内容并对新连接缺失的部分进行补充
base_url提供三项内容scheme,netloc和path,若是这3项在新的连接里不存在,就予以补充,若是新的连接存在,就使用新的连接的部分,而base_url中的params,query和fragment是不起做用的
from urllib.parse import urljoin print(urljoin('http://www.baidu.com','FAQ.html'))
它在构造get请求参数的时候很是有用
from urllib.parse import urlencode params={ 'name':'dwx', 'age':22 } base_url='http://www.baidu.com?' url=base_url+urlencode(params) print(url)
有了序列化就要有反序列化,若是有一串GET请求参数,利用parse_qs()方法能将其转回字典
from urllib.parse import parse_qs query="name=dengwenxiong&age=22" print(parse_qs(query))
它用于将参数转化为元组组成的列表
该方法能够将内容转化为URL格式
from urllib.parse import quote key="邓文雄" url="http://www.baidu.com/s?wd="+quote(key) print(url)
能够对URL进行解码
from urllib.parse import unquote key="%E9%82%93%E6%96%87%E9%9B%84" print(unquote(key))
利用urllib的robotparser模块,咱们能够实现网站Robots协议的分析
Robots协议也称为爬虫协议,机器人协议,全名为网络爬虫排除标准(Robots Exclusion Protocol),用来告诉爬虫和搜索引擎哪些页面能够抓取,哪些页面不可抓取。它一般是一个叫做robots.txt的文本文件,通常放在网站的根目录下。
当搜索爬虫访问一个站点时,它会首先检查这。个站点根目录下是否存在robots.txt文件,若是存在,搜索爬虫会根据其中定义的爬取范围来爬取,若是没有找到这个文件,搜索爬虫便会访问因此可直接访问的页面
下面是一个robot.txt的样例
A.对全部搜索爬虫只容许爬取public目录
User-agent:* Disallow:/ Allow:/public/
User-agent描述了搜索爬虫的名称,这里设置为*则表明该协议对任何爬取爬虫有效
Disallow指定了不容许抓取的目录,设置为/则表明不容许抓取全部页面
Allow通常和Disallow一块儿使用,通常不会单独使用,用来排除某些限制,这里设置为/public/则表示全部页面不容许抓取,但能够抓取public目录
B.禁止全部爬虫访问任何目录
User-agent:*
Disallow:/
C.容许全部爬虫访问任何目录
User-agent:*
Disallow:
D.禁止全部爬虫访问网站某些目录
User-agent:* Disallow:/private/ Disallow:/tmp/
E.只容许某一个爬虫访问
User-agent:WebCrawler Disallow: User-agent:* Disallow:/
一些常见搜索爬虫的名称即其对应的网站
爬虫名称 | 名称 | 网站 |
BaiduSpider | 百度 | www.baidu.com |
Googlebor | 谷歌 | www.google.com |
360Spider | 360搜索 | www.so.com |
YodaoBor | 有道 | www.youdao.com |
ia_archiver | Alexa | www.alexa.cn |
Scooter | altavista | www.altavista.com |
能够用robotparser模块来解析robots.txt;该模块提供了一个类RobotFileParser,它能够根据某网站的robots.txt文件来判断一个爬取爬虫是否有权限来爬取这个网页;这个类用起来很是简单,只须要在构造方法里传入robots.txt的连接便可,其声明以下:
urllib.robotparser.RobotFileParser(url=' ')
也能够在声明时不传入,默认为空,使用set_url()方法设置也行;
这个类经常使用的几个方法:
1)set_url():用来设置robots.txt文件的连接。若是在建立RobotFileParser对象时传入了连接,那么就不须要再使用这个方法设置了 2)read():读取robots.txt文件并进行分析,这个方法执行一个读取和分析操做,若是不调用这个方法,接下来的判断都会为false,因此必定要调用这个方法,这个方法不返回任何内容,可是执行了读取操做 3)parse():用来解析robots.txt文件,传入的参数是robots.txt某些行的内容,它会按照robots.txt的语法规则来分析这些内容 4)can_fetch():该方法传入两个参数,第一个是User-agent,第二个是要抓取的URL。返回的内容是该搜索引擎是否能够抓取这个URL,返回的结果是True或False 5)mtime():返回的是上次抓取和分析robots.txt的时间,这对于长时间分析和抓取的搜索爬虫是颇有必要的,你可能须要按期检查来抓取最新的robots.txt 6)modified():它对长时间分析和抓取的搜索爬虫颇有帮助,将当前时间设置为上次抓取和分析robots.txt的时间
from urllib.robotparser import RobotFileParser rp=RobotFileParser() rp.set_url('http://www.jianshu.com/robots.txt') rp.read()#也可用parse()读取和分析rp.parse(urlopen('http://www.jianshu.com/robots.txt').read().decode('utf-8').split('\n')) print(rp.can_fetch('*','http://www.jianshu.com/'))