人生苦短, 我用 Python
前文传送门:
小白学 Python 爬虫(1): 开篇 https://www.geekdigging.com/2019/11/13/3303836941/
小白学 Python 爬虫 (2): 前置准备(一) 基本类库的安装 https://www.geekdigging.com/2019/11/20/2586166930/
小白学 Python 爬虫(3): 前置准备(二)Linux 基础入门 https://www.geekdigging.com/2019/11/21/1005563697/
小白学 Python 爬虫(4): 前置准备(三)Docker 基础入门 https://www.geekdigging.com/2019/11/22/3679472340/
小白学 Python 爬虫 (5): 前置准备(四) 数据库基础 https://www.geekdigging.com/2019/11/24/334078215/
小白学 Python 爬虫 (6): 前置准备(五) 爬虫框架的安装 https://www.geekdigging.com/2019/11/25/1881661601/
小白学 Python 爬虫(7):HTTP 基础 https://www.geekdigging.com/2019/11/26/1197821400/
小白学 Python 爬虫(8): 网页基础 https://www.geekdigging.com/2019/11/27/101847406/
小白学 Python 爬虫(9): 爬虫基础 https://www.geekdigging.com/2019/11/28/1668465912/
小白学 Python 爬虫(10):Session 和 Cookies https://www.geekdigging.com/2019/12/01/2475257648/
小白学 Python 爬虫(11):urllib 基础使用(一) https://www.geekdigging.com/2019/12/02/2333822325/
小白学 Python 爬虫(12):urllib 基础使用(二) https://www.geekdigging.com/2019/12/03/819896244/
前面两篇基础, 我们介绍请求发送的过程.
不知道各位同学有没有想过这样一个问题, 如果在爬虫运行的过程中, 网络突然波动了下, 比如突然网速很慢很慢, 造成当前的请求超时, 程序很可能会直接挂掉.
这种处理方式显然不是我们希望看到的, 我们希望看到的肯定是如果当前的请求挂掉, 那就挂掉, 不要影响其他的请求或者是下一次的请求.
那么, 我们在发送请求的时候, 异常处理就显得十分有必要.
urllib 的 error 模块定义了由 request 模块产生的异常, 如果出现问题, request 模块便会抛出 error 模块中定义的异常.
URLError
URLError 这个类来自于 urllib 库的 error 模块, 它继承自 OSError , 是 error 异常模块的基类, 由 request 模块产生的异常都可以通过捕获这个类来处理.
它只有一个属性 reason , 即返回错误的原因.
我们来写一个简单的示例大家看一下:
- from urllib import request, error
- # 访问明显不存在的地址, 报错: Not Found
- try:
- response = request.urlopen('https://www.geekdigging.com/aa')
- except error.URLError as e:
- print(e.reason)
- # 访问超时, 报错: timed out
- try:
- response = request.urlopen('https://www.baidu.com', timeout=0.001)
- except error.URLError as e:
- print(e.reason)
这里我们访问了一个明显不存在的链接和限定了极短的超时时间, 这里会抛出异常, 但是我们捕获了 URLError 这个异常, 运行结果如下:
- Not Found
- timed out
程序没有直接抛出异常终止运行, 而是输出了上面这个异常, 通过这样的操作, 我们可以避免程序异常终止, 同时还可以对这个异常做出针对性的处理.
此外, 异常捕捉抛出的异常不一定都是字符串类型, 比如访问超时的报错, 我们将打印结果的代码稍作改动:
- from urllib import request, error
- import socket
- # 异常类型示例
- try:
- response = request.urlopen('https://www.baidu.com', timeout=0.001)
- except error.URLError as e:
- print(type(e.reason))
- if isinstance(e.reason, socket.timeout):
- print('TIME OUT')
结果如下:
- <class 'socket.timeout'>
- TIME OUT HTTPError
它是 URLError 的子类, 专门用来处理 HTTP 请求错误, 比如认证请求失败等. 它有如下 3 个属性.
code: 返回 HTTP 状态码, 比如 404 表示网页不存在, 500 表示服务器内部错误等.
reason: 同父类一样, 用于返回错误的原因.
headers: 返回请求头.
还是先看一个最简单的示例:
- from urllib import request, error
- # 访问明显不存在的地址, 使用 HTTPError 捕捉异常
- try:
- response = request.urlopen('https://www.geekdigging.com/aa')
- except error.HTTPError as e:
- print(e.reason, e.code, e.headers, sep='\n')
运行结果如下:
- Not Found
- 404
- Date: Sun, 01 Dec 2019 15:11:48 GMT
- Content-Type: text/html
- Content-Length: 49307
- Connection: close
- Server: tencent-cos
- Last-Modified: Sun, 01 Dec 2019 15:03:24 GMT
- X-NWS-UUID-VERIFY: c89959eb27b89a0fb1c0326d1b2e7171
- Accept-Ranges: bytes
- ETag: "1bb6cc2c28a5621cf0c3238107edc229"
- x-cos-error-code: NoSuchKey
- x-cos-error-detail-Key: aa
- x-cos-error-message: The specified key does not exist.
- x-cos-request-id: NWRlM2Q4MzRfMzNhNzAzMDlfYTljZl8yNGU1NTgx
- x-cos-trace-id: OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTQ5YWUxMjNkYTk3NzdjZmZlMDQzOTgxOThkOTNlOWFkOGJiN2YzOGQ5MDdjNGY0ODQ1MGIzYjUyMzg2NjFhNzc=
- X-Daa-Tunnel: hop_count=2
- X-NWS-LOG-UUID: 7c3fe80b-af9a-4e59-969b-10c8b3963a1d
- X-Cache-Lookup: Hit From Upstream
- X-Cache-Lookup: Hit From Upstream
因为 URLError 是 HTTPError 的父类, 所以可以先选择捕获子类的错误, 再去捕获父类的错误, 这样对异常的处理更具针对性.
注意: 捕捉异常一般先捕捉子类异常, 再捕捉父类异常.
所以我们可以更改下前面的异常捕捉的代码进行一些优化:
- # 优化异常捕捉代码
- try:
- response = request.urlopen('https://www.geekdigging.com/aa')
- 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 Success!')
示例代码
本系列的所有代码小编都会放在代码管理仓库 GitHub 和 Gitee 上, 方便大家取用.
示例代码 - GitHub
示例代码 - Gitee
参考
https://www.cnblogs.com/zhangxinqi/p/9170312.html
来源: https://www.cnblogs.com/babycomeon/p/12008967.html