爬虫第七节 异常处理神器 URLError

# 异常处理神器====URLError
#程序在执行的过程中,难免会发生异常,发生异常不要紧,关键是要能合理地处理异常,
# 在Python爬虫中,经常要处理一些与URL相关的异常。此时,我们可以使用,URL异常处理神器 URLError类进行相应的处理,
# 使用URLError类,我们首先要导入urllib. error模块。
# 进行异常处理,我们经常使用try-•-except语句,在try中执行主要代码,在except中捕 获异常信息,并进行相应的异常处理。
# 这一节我们主要介绍两个类,第一个类是URLError类,第二个类是URLError类的一个子类——HTTPError类。
# 首先,我们来看第一个实例
import urllib.request
import urllib.error #判断urlerror错误

try:
urllib.request.urlopen("https://www.bilibili.com")
except urllib.error.URLError as e:
print(e.code)
print(e.reason)
"""
在该实例中,我们要对网址“http://blog.csdn.net”进行爬取,CSDN博客是禁止对文章 进行爬取的,而在这里,
没有模拟浏览器去爬取,所以必然会出现403的错误,此时会引发 except部分,
并通过urllib.error.URLError as e捕获异常信息e,
然后进行相应的异常处理。 这里的异常处理会输出对应的异常状态和异常原因。

运行结果;
403
Forbidden

我们可以看到,其输岀了对应的异常状态码和异常原因。
一般来说,产生uRLError的原因有如下几种可能:
1)连接不上服务器
2)远程URL不存在
3)无网络
4)触发了 HTTPError
"""

# 显然,刚才产生URLError异常不属于前三种情况,
# 而是由于触发了 HTTPError。所以, 以上代异常处理我们可以直接用HTTPError代替URLError。
import urllib.request
import urllib.error

try:
urllib.request.urlopen("https://www.bilibili.com")
except urllib.error.HTTPError as e:
print(e.code)
print(e.reason)
# 这里可以看出此时直接用子类HTTPError进行异常处理,同样可以输出如下结果:
"""
运行结果;
403
Forbidden

这里的状态码为403,这个状态码是服务器返回给客户端的一个编码,不同的编码具有 不同的含义。
"""





"""
HTTP状态码汇总
http状态码可以让我很方便的了解到请求的所在状态,当然其也是大厂笔试的必考题。

所以很有必要总结一下,对今后的学习也是很有帮助的。

HTTP状态码总的分为五类:

1开头: 信息状态码

2开头: 成功状态码

3开头: 重定向状态码

4开头: 客户端错误状态码

5开头: 服务端错误状态码

1XX:信息状态码

状态码 含义 描述
100 继续 初始的请求已经接受,请客户端继续发送剩余部分
101 切换协议 请求这要求服务器切换协议,服务器已确定切换




2XX:成功状态码
状态码 含义 描述
200 成功 服务器已成功处理了请求
201 已创建 请求成功并且服务器创建了新的资源
202 已接受 服务器已接受请求,但尚未处理
203 非授权信息 服务器已成功处理请求,但返回的信息可能来自另一个来源
204 无内容 服务器成功处理了请求,但没有返回任何内容
205 重置内容 服务器处理成功,用户终端应重置文档视图
206 部分内容 服务器成功处理了部分GET请求


3XX:重定向状态码

状态码 含义 描述
300 多种选择 针对请求,服务器可执行多种操作
301 永久移动 请求的页面已永久跳转到新的url
302 临时移动 服务器目前从不同位置的网页响应请求,但请求仍继续使用原有位置来进行以后的请求
303 查看其他位置 请求者应当对不同的位置使用单独的GET请求来检索响应时,服务器返回此代码
# 304 未修改 自从上次请求后,请求的网页未修改过
305 使用代理 请求者只能使用代理访问请求的网页
307 临时重定向 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求



4XX:客户端错误状态码

状态码 含义 描述
# 400 错误请求 服务器不理解请求的语法
401 未授权 请求要求用户的身份演验证
403 禁止 服务器拒绝请求
# 404 未找到 服务器找不到请求的页面
405 方法禁用 禁用请求中指定的方法
406 不接受 无法使用请求的内容特性响应请求的页面
407 需要代理授权 请求需要代理的身份认证
408 请求超时 服务器等候请求时发生超时
409 冲突 服务器在完成请求时发生冲突
410 已删除 客户端请求的资源已经不存在
411 需要有效长度 服务器不接受不含有效长度表头字段的请求
412 未满足前提条件 服务器未满足请求者在请求中设置的其中一个前提条件
413 请求实体过大 由于请求实体过大,服务器无法处理,因此拒绝请求
414 请求url过长 请求的url过长,服务器无法处理
415 不支持格式 服务器无法处理请求中附带媒体格式
416 范围无效 客户端请求的范围无效
417 未满足期望 服务器无法满足请求表头字段要求

5XX:服务端错误状态码

状态码 含义 描述
# 500 服务器错误 服务器内部错误,无法完成请求
501 尚未实施 服务器不具备完成请求的功能
502 错误网关 服务器作为网关或代理出现错误
503 服务不可用 服务器目前无法使用
504 网关超时 网关或代理服务器,未及时获取请求
505 不支持版本 服务器不支持请求中使用的HTTP协议版本
"""

# 以上我们总结了常见的状态码以及其对应含义,以后在遇到这些状态码的时候,就知道是什么原因所导致的异常了。
# HTTPError子类无法处理刚才所提到的产生URLError的前3种原因的异常,
# 即无法处理:连接不上服务器、远程URL不存在、无网络引起的异常。
# 比如,我们构造一个不存在的网址,引发远程URL不存在的异常,此时,不能够通过 HTTPError处理,但能通过URLError处理。
import urllib.request
import urllib.error
try:
urllib.request.urlopen("http://blog.baidusss.net")
except urllib.error.HTTPError as e :
print(e.reason)

# 可以发现,此时无法进行异常处理,
# 但是此时,如果使用URLError,是可以进行异常 处理的,比如,将代码改写成如下代码即可正确执行:


import urllib.request
import urllib.error
try:
urllib.request.urlopen("http://blog.baidusss.net")
except urllib.error.URLError as e:
print(e.reason)

"""
可以看到,成功进行了异常处理,同时输出了异常原因。
在实际处理异常时,我们并不知道使用HTTPError能不能处理。如果,异常处理中只有 HTTPError子类的话,
若发生连接不上服务器、远程URL不存在、无网络等异常,是无法处理的。
所以,我们可以对以上代码进行相应的优化,先让其用HTTPError子类进行处理,
若无法处理,再让其用URLError进行处理,优化后的代码如下所示:
"""
import urllib.request
import urllib.error

try:
urllib.request.urlopen("http://blog.baidusss.net")
except urllib.error.HTTPError as e:
print(e.code)
print(e.reason)
except urllib.error.URLError as e:
print(e.reason)

"""
在上述代码中,我们先用子类进行异常处理,若无法处理,再用父类进行异常处理,此 时,不管发生的是哪种异常,都能够进行完美处理。
上述代码的执行结果如下:
======================== RESTART: D:Python354.8.py ========================
[Errno 11004] getaddrinfo failed

可以看到,此时用子类无法处理,那么将自动交给父类进行相应处理。

然后进行思考:
1)URLError是HTTPError的父类,那么我们能不能用URLError直接代替HTTP-Error 呢?
2)以上程序中分别用了 HTTPError和URLError进行处理,我们能否整合一下,用其中的一个类就能处理完呢?
如果能,应该怎么改进?


首先,有时不能直接用URLError代替HTTPError,但改进后可以整合。为什么有时不 能直接代替呢?
我们知道,在本节的实例1中,用URLError代替HTTPError可以直接运行,我们将实例1中的代码拿过来,
但是改一下需要打开的URL:
"""
import urllib.request
import urllib.error
try:
urllib. request .urlopen ("http:// www.baidussssss.net")
except urllib.error.URLError as e:
print(e.code)
print(e.reason)
"""
可以发现,这个代码执行起来是有问题的,如下所示:
======================== RESTART: D:Python354.8.py ========================
Traceback (most recent call last):
File "D:Python35liburllib equest.py", line 1254, in do_open
h.request(req.get_method(), req.selector, req.data, headers)
File "D:Python35libhttpclient.py", line 1106, in request
self._send_request(method, url, body, headers)
因为此时触发的原因是连接不上服务器、远程URL不存在、无网络等异常中的一个, 即此时没有e.code,
只有e.reason,所以自然无法输出e.code,虽然我们把e.code部分去掉 就可以解决异常问题,但如果到时引发的是HTTPError,
我们又希望获取对应的状态码怎么 办?去掉了 e.code就无法获得状态码了,即“顾此失彼”。
那么,如果我们要整合,怎么平衡一下呢?
可以这样做,我们使用URLError进行异常处理,但是做一个判断,如果有e.code则输出对应信息,
如果没有则自动忽略。同理,如果有e.reason则输出e.reason,没有亦忽略该项。
可以使用hasattr()函数来判断是否有这些属性。加上这个判断之后,不管是何种原因引发的URL异常,
都能够通过URLError进行处理,代码改进如下:
"""
#整合后代码
import urllib.request
import urllib.error
try:
urllib. request. urlopen ("http:// blog. csdn. net")
except urllib.error.URLError as e:
if hasattr(e,"code"):
print(e.code)
if hasattr(e,"reason"):
print(e.reason)

"""
此时,如果是引发了 HTTPError异常,则判断出有e.code,就会既输出状态码也输出错误原因,
若引发异常的原因是连接不上服务器、远程URL不存在、无网络等异常中的一个, 则判断没有e.code,
所以此时只输出e.reason,不管是何种原因,都能解决。
通过前面的学习,相信大家对URLError异常处理已经有了较为深入的理解。
"""
原文地址:https://www.cnblogs.com/kwkk978113/p/12874782.html