urllib 是 Python 自带的网络请求标准库,包含了多个处理 URL 功能的模块。
urllib.request 和 urllib.error 是我们常用的两个库,这两个库也是在爬虫程序中使用频繁的库。
通过 urllib.request 模块可以发送 http 请求,并读取请求结果。
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
参数信息如下:
使用 urllib.request.urlopen 可以很方便的获取网页内容,我们以获取 httpbin.org 内容为例,介绍 urlopen 的使用方法
from urllib import request
response = request.urlopen('http://httpbin.org')
data = response.read()
print("HTTP Status:", response.status, response.reason)
for k, v in response.headers:
print("%s %s" % (k, v))
运行结果如下:
HTTP Status: 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Date: Thu, 28 Feb 2019 08:17:13 GMT
Server: nginx
Content-Length: 9593
Connection: Close
DATA: <!DOCTYPE html>
<html lang="en">
.....
</body>
</html>
网络请求难免会遇到长时间无法正常连接的问题,此时可以通过设置超时时间「timeout」,使 urlopen 方法在一定时间内无法连接时自动退出,以免影响整个程序的运行。我们可以通过以下方式来设置超时时间
request.urlopen("http://httpbin.org", timeout = 5)
以上代码设置 5 秒钟内无法正常连接,则退出 urlopen 方法。
向服务器提交数据或请求某些需要携带数据的网页时,需要用到 POST 请求,此时只需要将数据以 bytes 的格式传入参数 data 即可。
使用 POST 提交数据的示例如下
# -*- coding:utf-8 -*-
from urllib import request, parse
data = parse.urlencode([
('name', 'keinYe'),
('age', '30'),
])
response = request.urlopen('http://httpbin.org/post', data = data.encode('utf-8'))
print('HTTP Status:', response.status, response.reason)
print('HTTP Headers:', response.headers)
print('Data:', response.read().decode('utf-8'))
执行结果如下
HTTP Status: 200 OK
HTTP Headers: Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Thu, 28 Feb 2019 13:53:58 GMT
Server: nginx
Content-Length: 417
Connection: Close
Data: {
"args": {},
"data": "",
"files": {},
"form": {
"age": "30",
"name": "keinYe"
},
"headers": {
"Accept-Encoding": "identity",
"Content-Length": "18",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.7"
},
"json": null,
"origin": "121.35.186.172, 121.35.186.172",
"url": "https://httpbin.org/post"
}
在前面使用 urlopen 方法完成了简单的 get 和 post 请求,但是仅仅 urlopen 方法中的几个参数不足以构建完整的请求,完整的请求通常包含有 header 等信息,我们可以使用 urllib.request.Request 类来构建含有 header 以及请求方法的网络请求。
一个完整的 HTTP 请求通常包含以下内容:
以下是 urllib.request.Request 的定义:
class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
参数信息如下:
现在我们使用 urllib.request 模拟使用 mac 上的 chrome 浏览器。
# -*- coding:utf-8 -*-
from urllib import request
url = 'https://httpbin.org/get'
headers = {
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36"
}
req = request.Request(url=url, headers=headers)
response = request.urlopen(req)
print('HTTP Status:', response.status, response.reason)
print('HTTP Headers:', response.headers)
print('Data:', response.read().decode('utf-8'))
运行结果
HTTP Status: 200 OK
HTTP Headers: Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Fri, 01 Mar 2019 07:09:14 GMT
Server: nginx
Content-Length: 324
Connection: Close
Data: {
"args": {},
"headers": {
"Accept-Encoding": "identity",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36"
},
"origin": "119.137.3.11, 119.137.3.11",
"url": "https://httpbin.org/get"
}
从运行结果中可以看出,httpbin.org 的放回数据中包含有我们提交给 httpbin.org 的浏览器信息。
网络通信是一个异步的通信过程,不可避免的会出现异常,此时就要用到 urllib.error 来处理错误『若不处理错误会造成程序中断执行』,这个会增加程序的健壮性。
urlib.error 中有三个异常处理类,分别是 URLError、HTTPError 和 ContentToolShortError。
URLError 是 urllib.error 异常的类的基类,URLError 是 OSError 的子类,当程序在运行过程中出现错误时会触发该异常。URLError 类带有一个 reason 属性,返回异常的原因,reason 是一个消息字符串或者是一个异常实例。
URLError 示例代码:
from urllib import request
from urllib import error
url = "http://www.google.com"
try:
response = request.urlopen(url, timeout = 5)
print(response.read().decode('utf-8'))
except error.URLError as e:
print("Exception: ", e.reason)
HTTPError 是专门用于处理 http 和 https 请求错误的异常类,HTTPError 也可以作为一个特殊的文件返回值「它与 URLopen 的返回相同」。HTTPError 是 URLError 的子类,它有 code、reason 和 headers 三个属性,code 是 HTTP 请求的返回吗,reason 同 URLError 中相同是一个表示异常原因的消息字符串,headers 是 HTTP 请求返回的请求头信息。
HTTPError 示例代码:
# -*- coding:utf -*-
from urllib import request
from urllib import error
url = "http://www.keinye.com/122323b"
try:
response = request.urlopen(url, timeout = 5)
print(response.read().decode('utf-8'))
except error.HTTPError as e:
print("Exception code:", e.code)
print("Exception reason:", e.reason)
print("Exception headers:", e.headers)
由于 HTTPError 是 URLError 的子类,因此在 HTTPError 和 URLError 混合使用时要将 HTTPError 放在 URLError 前面。
ContentToolShortError 是用于处理下载异常的异常类,当 urlretrieve 下载文件不完整时会抛出该异常。