一.urlib异常处理
1、URLError异常
通常引起URLError的原因是:无网络连接(没有到目标服务器的路由)、访问的目标服务器不存在。在这种情况下,异常对象会有reason属性(是一个(错误码、错误原因)的元组)
1)访问成功时:
from urllib import request, error
try:
url = 'https://www.baidu.com/hello.html'
response = request.urlopen(url)
print(response.read().decode('utf-8'))
except error.HTTPError as e:
print(e.reason, e.code, e.headers, sep='\n')
except error.URLError as e:
print(e.reason)
else:
print("成功")
我们可以成功的访问到百度页面
2)有异常时
from urllib import request, error
url = 'https://www.baidu.com/hello.html'
response = request.urlopen(url)
print(response.read().decode('utf-8'))
这里我断开了网络,出现了URLError
2、HTTPError
每一个从服务器返回的HTTP响应都有一个状态码。其中,有的状态码表示服务器不能完成相应的请求,默认的处理程序可以为我们处理一些这样的状态码(如返回的响应是重定向,urllib2会自动为我们从重定向后的页面中获取信息)。有些状态码,urllib2模块不能帮我们处理,那么urlopen函数就会引起HTTPError异常,其中典型的有404/401
##因为URLError是HTTPError的父类,所以在捕获异常的时候可以先找子类是否异常,如果子类找不到,再找父类即可
from urllib import request, error
try:
url = 'http://www.douban.com/hello89.html'
response = request.urlopen(url)
print(response.read().decode('utf-8'))
except error.HTTPError as e:
print(e.reason, e.code, e.headers, sep='\n')
except error.URLError as e:
print(e.reason)
else:
print("成功")
上例是我访问一个豆瓣不存在的网页
常见状态返回码
100:继续 客户端应当继续发送请求。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。
101: 转换协议 在发送完这个响应最后的空行后,服务器将会切换到在Upgrade 消息头中定义的那些协议。只有在切换新的协议更有好处的时候才应该采取类似措施。
102:继续处理 由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行。
200:请求成功 处理方式:获得响应的内容,进行处理 201:请求完成,结果是创建了新资源。新创建资源的URI可在响应的实体中得到 处理方式:爬虫中不会遇到
202:请求被接受,但处理尚未完成 处理方式:阻塞等待
204:服务器端已经实现了请求,但是没有返回新的信 息。如果客户是用户代理,则无须为此更新自身的文档视图。 处理方式:丢弃
300:该状态码不被HTTP/1.0的应用程序直接使用, 只是作为3XX类型回应的默认解释。存在多个可用的被请求资源。 处理方式:若程序中能够处理,则进行进一步处理,如果程序中不能处理,则丢弃
301:请求到的资源都会分配一个永久的URL,这样就可以在将来通过该URL来访问此资源 处理方式:重定向到分配的URL
302:请求到的资源在一个不同的URL处临时保存 处理方式:重定向到临时的URL
304:请求的资源未更新 处理方式:丢弃 400:非法请求 处理方式:丢弃
401:未授权 处理方式:丢弃
403:禁止 处理方式:丢弃
404:没有找到 处理方式:丢弃
500:服务器内部错误 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器端的源代码出现错误时出现。
501:服务器无法识别 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。
502:错误网关 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
503:服务出错 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。
3、超时异常处理
为了捕获超时异常,我在这里设置了时间限制,当响应超过0.01s时,就会认为超时。
from urllib import request, error
import socket
try:
url = 'https://www.baidu.com'
response = request.urlopen(url, timeout=0.01)
print(response.read().decode('utf-8'))
except error.HTTPError as e:
print(e.reason, e.code, e.headers, sep='\n')
except error.URLError as e:
print(e.reason)
if isinstance(e.reason, socket.timeout):
print("超时")
else:
print("成功")
二.urlib解析
'https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=hello&rsv_pq=d0f841b10001fab6&rsv_t=2d43603JgfgVkvPtTiNX%2FIYssE6lWfmSKxVCtgi0Ix5w1mnjks2eEMG%2F0Gw&rqlang=cn&rsv_enter=1&rsv_sug3=6&rsv_sug1=4&rsv_sug7=101&rsv_sug2=0&inputT=838&rsv_sug4=1460'
一般一个完整的url地址包括以下部分:
1.协议部分(scheme):该URL的协议部分为“https:”,这代表网页使用的是HTTP协议。在Internet中可以使用多种协议,如HTTP,FTP等等本例中使用的是HTTP协议。
2.域名+端口部分(netloc):该URL的域名部分为“www.baidu.com”。一个URL中,也可以使用IP地址作为域名使用。跟在域名后面的是端口,域名和端口之间使用“:”作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口(这里没显示端口,所以采用了默认端口)
3.虚拟目录部分(path):从域名后的第一个“/”开始到最后一个“/“为止,是虚拟目录部分。虚拟目录也不是一个URL必须的部分。本例中的虚拟目录是path=’/s’
4.文件名部分(params):从域名后的最后一个“/”开始到“?”为止,是文件名部分,如果没有“?”,则是从域名后的最后一个“/”开始到“#”为止,是文件部分,如果没有“?”和“#”,那么从域名后的最后一个“/”开始到结束,都是文件名部分。本例中没有文件名。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名
5.锚部分(fragment):从“#”开始到最后,都是锚部分。本例中没有锚部分。锚部分也不是一个URL必须的部分
6.参数部分(query):从“?”开始到“#”为止之间的部分为参数部分,又称搜索部分、查询部分。本例中的参数部分为“ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=hello&rsv_pq=d0f841b10001fab6&rsv_t=2d43603JgfgVkvPtTiNX%2FIYssE6lWfmSKxVCtgi0Ix5w1mnjks2eEMG%2F0Gw&rqlang=cn&rsv_enter=1&rsv_sug3=6&rsv_sug1=4&rsv_sug7=101&rsv_sug2=0&inputT=838&rsv_sug4=1460’”。参数可以允许有多个参数,参数与参数之间用“&”作为分隔符。
代码实现对url的解析
这里我们要调用urllib模块中的parse类,再通过parse.urlparse构造一个实例化对象。即可进行解析。
from urllib import parse
url = 'https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=hello&rsv_pq=d0f841b10001fab6&rsv_t=2d43603JgfgVkvPtTiNX%2FIYssE6lWfmSKxVCtgi0Ix5w1mnjks2eEMG%2F0Gw&rqlang=cn&rsv_enter=1&rsv_sug3=6&rsv_sug1=4&rsv_sug7=101&rsv_sug2=0&inputT=838&rsv_sug4=1460'
parsed_tuple = parse.urlparse(url)
print(parsed_tuple)
print(parsed_tuple.scheme)
print(parsed_tuple.netloc)
print(parsed_tuple.path)
print(parsed_tuple.params)
print(parsed_tuple.query)
print(parsed_tuple.fragment)
通过字典编码的方式构造url地址
这里我们要用到urlencode方法
from urllib.parse import urlencode
params = {
'name':'westos',
'age':20
}
base_url = 'http://www.baidu.com?'
url = base_url + urlencode(params) ###将域名与文件名联结起来构成新的url
print(url)