共计 5330 个字符,预计需要花费 14 分钟才能阅读完成。
请求头中的内容:
- Date: 标识 响应产生 的时间。
- Last-Modified: 指定资源的最后修改时间。
- Content-Encoding: 指定 响应 内容的编码。
- Server: 包含服务器的信息,比如名称、版本号等。
- Content-Type: 文档类型,指定返回的数据类型是什么,如 text/html 代表返回 HTML 文档,
- application/x-javascript !J!U 代表返回 JavaScript 文件,image/jpeg 则代表返回图片。
- Set-Cookie: 设置 Cookies。响应头 中的 Set-Cookie 告诉浏览器需要将此内容放在 Cookies 中,下次请求携带 Cookies 请求。
- Expires: 指定响应的过期时间,可以使代理服务器或浏览器将加载的内容更新到缓存。如果再次访问时,就可以直接从缓存中加载,降低服务器负载,缩短加载时间。
1.urllib.request 模块
request: 最基本的 HTTP 请求模块,可以用来模拟发送请求。就像在浏览器里输入网址然后回车一样,只需要给库方法传入 URL 以及额外的参数,就可以模拟实现这个过程了 , 同时它还带有 处理授权验证 (authenticaton)、 重定向 (redirection)、 浏览器 Cookies 以及其他内容。
- error: 异常处理模块,如果出现请求错误,我们可以捕获这些异常,然后进行重试或其他操作以保证程序不会意外终止。
- parse: 一个工具模块,提供了许多 URL 处理方法,比如拆分,解析,合并等。
- robotparser: 主要是用来识别网站的 robots.txt 文件,然后判断哪些网站可以爬,哪些网站不可以爬,它其实用得比较少。
urllib.request.urlopen() 为最基本 HTTP 请求的方法
import urllib.request
response= urllib.request.urlopen('https://www.python.org')
print(response.read().decode ('utf-8')) // 打印出网页的源代码
print(type(response)) //<class’http.client.HTTPResponse’> 说明该对象类型为 HTTPResponse 类型。print(response.status) //200
print(response.getheaders()) //
[('Server', 'nginx'), ('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'DENY'),
('Via', '1.1 vegur'), ('Via', '1.1 varnish'), ('Content-Length', '48995'), ('Accept-Ranges', 'bytes'),
('Date', 'Mon, 13 May 2019 09:23:37 GMT'), ('Via', '1.1 varnish'), ('Age', '3595'), ('Connection', 'close'),
('X-Served-By', 'cache-iad2139-IAD, cache-tyo19927-TYO'), ('X-Cache', 'HIT, HIT'),
('X-Cache-Hits', '1, 6071'), ('X-Timer', 'S1557739417.434556,VS0,VE0'), ('Vary', 'Cookie'),
('Strict-Transport-Security', 'max-age=63072000; includeSubDomains')]
print(response.getheader('Server')) //nginx
HTTPResposne类型的对象,主要包含
read()、readinto()、getheader(name)、getheaders()、fileno()等方法,以及 msg、version、status、reason、debuglevel、closed 等属性。
如果想给链接传递一些参数,该怎么实现呢? 首先看一下 urlopen()
函数的 API:
urllib.request.urlopen(url, data=None, timeout=<object object at 0x1102821a0>, *, cafile=None, capath=None, cadefault=False, context=None)
• data
参数
data 参数是可选的。如果要添加该参数,并且如果它是字节流编码格式的内容,即 bytes 类型,则需要通过 bytes() 方法转化。另外,如果传递了这个参数,则它的请求方式就不再是 GET 方式,而是 POST 方式。
import urllib
data = bytes(urllib.parse.urlencode({'word':'hello'}), encoding='utf8') // 通过 utf8 的格式将字典进行字节流的编码,response= urllib.request.urlopen('http://httpbin.org/post', data=data) // 将编码后的字节流数据传输到指定 URL
print(response.read().decode('utf-8'))// 这里存在一个 bug,要进行指定方式解码。
Result:
{"args": {},
"data": "","files": {},"form": {"word":"hello"},"headers": {"Accept-Encoding":"identity","Content-Length":"10","Content-Type":"application/x-www-form-urlencoded","Host":"httpbin.org","User-Agent":"Python-urllib/3.6"},"json": null,"origin":"171.81.189.140, 171.81.189.140","url":"https://httpbin.org/post"
}
• timeout 参数
timeout 参数用于设置超时时间,单位为秒,意思就是如果请求超出了设置的这个时间,还没有得到响应,就会抛出异常。如果不指定该参数,就会使用全局默认时间。它支持 HTTP,HTTPS,FTP 请求。
import socket
import urllib
try:
response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1) // 如果时间超过 0.1S 不响应就报错。except urllib.error.URLError as e:
if isinstance(e.reason,socket.timeout):
print("TIME OUT!")
• 其他参数
除了 data 参数和 timeout 参数外,还有 context 参数,它必须是 ssl.SSLContext 类型,用来指定 SSL 设置。此外,cafile 和 capath 这两个参数分别指定 CA 证书和它的路径,这个在请求 HTTPS 链接时会有用。
cadefault 参数现在已经弃用了,其默认值为 False。
2.Request 类
import urllib.request
request = urllib.request.Request("https://python.org")
response = urllib .request.urlopen(request)
print(response.read().decode ('utf-8'))
依然是用 urlopen()方法来发送这个请求,只不过该方法的参数不再是 URL, 而是一个 Request 类型的对象。通过构造这个数据结构,一方面我们可以将请求独立成一个对象,另 一方面可更加丰富和灵活地配置参数。
class urllib. request. Request (url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
- 第一个参数 url 用于请求 URL,这是必传参数, 其余可选。
- 第二个参数 data 如果要传,必须传 bytes (字节流)类型的。如果它是字典,可以先用 urllib.parse 模块里的 urlencode()编码。将字典里面所有的键值转化为 query-string 格式(key=value&key=value),并且将中文转码。
- 第三个参数 headers 是一个字典,它就是请求头,我们可以在构造请求时通过 headers 参数直 接构造,也可以通过调用请求实例的 add_header()方法添加。
添加请求头最常用的用法就是通过修改 User-Agent 来伪装浏览器,默认的 User-Agent 是 Python-urllib,我们可以通过修改它来伪装浏览器。比如要伪装火狐浏览器,你可以把它设置为:Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:66.0) Gecko/20100101 Firefox/66.0
- 第四个参数 origin_req_host 指的是请求方的 host 名称或者 IP 地址。
- 第五个参数 unverifiable 表示这个请求是否是无法验证 的,默认是 False,意思就是说用户没有足够权限来选择接收这个请求的结果。例如,我们请求一个 HTML 文档中的图片,但是我 们没有向动抓取图像的权限,这时 unverifiable 的值就是 True。
-
第六个参数 method 是一个字符串,用来指示请求使用的方法,比如 GET、POST 和 PUT 等
from urllib import parse,request url = 'http://httpbin.org/post' headers = {'User-Agent':'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)', 'Host' :'httpbin.org' } dict={'name':'Gremey'} data= bytes(parse.urlencode(dict), encoding='utf-8') #req = request.Request(url=url, data=data, headers=headers, method='POST') // 上面是直接写好 headers 传递参数传递给对象,下面是单独的通过对象的方法传递 req=request.Request(url=url, data=data, method='POST') req.add_header('User-Agent','Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)') response = request.urlopen(req) print(response.read().decode('utf-8'))
3. 高级用法
在上面的过程中,我们虽然可以构造请求,但是对于一些更高级的操作 (比如 Cookies 处理、代理设置等),该如何处理?
就需要更强大的工具 Handler 登场了。简而言之,我们可以把它理解为各种处理器,有专门处理登录验证的,有处理 Cookies 的,有处理代理设置的。利用它们,我们几乎可以做到 HTTP 请求中所有的事。urllib .request
模块里的 BaseHandler
类,它是所有其他 Handler 的父类,它提 供了最基本的方法,例如 default_open()、protocol_request()
等。
接下来,就有各种 Handler 子类继承这个 BaseHandler 类,举例如下。
- HITPDefaultErrorHandler: 用于处理 HTTP 响应错误,错误都会抛出 HTTPError 类型的异常。
- HTTPRedirectHandler: 用于处理重定向。
- HTTPCookieProcessor: 用于处理 Cookies。
- ProxyHandler: 用于设置代理,默认代理为空。
- HπPPasswordMgr: 用于管理密码,它维护了用户名和密码的表。
- HTTPBasicAuthHandler: 用于管理认证,如果一个链接打开时需要认证,那么可以用它来解决认证问题。
另一个比较重要的类就是 OpenerDirector,我们可以称为 Opener。我们之前用过 urlopen()这个方法,实际上它就是 urllib 为我们提供的一个 Opener。
那么,为什么要引人 Opener 呢? 因为需要实现更高级的功能。之前使用的 Request 和 urlopen() 相当于类库为你封装好了极其常用的请求方法,利用它们可以完成基本的请求,但是现在不一样了,我们需要实现更高级的功能,所以需要深入一层进行配置,使用更底层的实例来完成操作,所以这里就用到了 Opener。
Opener 可以使用 open()方法,返回的类型和 urlopen()如出一辙。那么,它和 Handler 有什么关 系呢? 简而言之,就是利用 Handler 来构建 Opener。