赞
踩
requests
模块是 python 基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP
库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP
测试需求。Requests
的哲学是以 PEP 20 的习语为中心开发的,所以它比 urllib 更加 Pythoner
通过 pip install requests
安装 requests 库
导包:import requests
超文本传输协议,是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法,HTTP是一种基于"请求与响应"模式的、无状态的应用层协议。HTTP协议采用URL作为定位网络资源的的标识符
统一资源定位符是互联网上标准资源地址。互联网上的每一个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它
URL 的一般语法格式为:
protocol://host[:port]/path/[?query]#fragment
http://www.itcast.cn/index.html?name=andy&age=18#link
组成 | 说明 |
---|---|
protocol | 通信协议,常用:http、https 等 |
host | 主机(域名) |
port | 端口号,可选,省略时候使用方案的默认端口,如:http的默认端口为80 |
path | 路径,由零或多个 ‘/’ 符号隔开的字符串,一般用来表示主机上的一个目录或文件地址 |
query | 参数,以键值对的形式通过 & 来连接 |
fragment | 片段,# 后面内容常见于链接 锚点 |
url是通过HTTP协议存取资源的的Internet路径,一个URL对应一个数据资源
方法 | 说明 |
---|---|
GET | 请求获取URL位置的资源 |
HEAD | 请求获取URL位置资源的响应消息报告,即获得资源的头部信息 |
POST | 请求向URL位置的资源后附加新的消息 |
PUT | 请求向URL位置存储一个资源,覆盖原URL位置的资源 |
PATCH | 请求局部更新URL位置的资源,即改变该处资源的部分内容 |
DELETE | 请求删除URL位置存储的资源 |
GET
,HEAD
是从服务器获取信息到本地,PUT
,POST
,PATCH
,DELETE
是从本地向服务器提交信息。通过URL和命令管理资源,操作独立无状态,网络通道及服务器成了黑盒子
方法 | 说明 |
---|---|
requests.requst() | 构造一个请求,最基本的方法,是下面方法的支撑 |
requests.get() | 获取网页,对应HTTP中的GET方法 |
requests.post() | 向网页提交信息,对应HTTP中的POST方法 |
requests.head() | 获取html网页的头信息,对应HTTP中的HEAD方法 |
requests.put() | 向html提交put方法,对应HTTP中的PUT方法 |
requests.patch() | 向html网页提交局部请求修改的的请求,对应HTTP中的PATCH方法 |
requests.delete() | 向html提交删除请求,对应HTTP中的DELETE方法 |
最常用的方法为get()和post()分别用于发送Get请求和Post请求
属性或方法 | 描述 |
---|---|
response.status_code | 响应状态码 |
response.content | 把response对象转换为二进制数据 |
response.text | 把response对象转换为字符串数据 |
response.encoding | 定义response对象的编码 |
response.cookie | 获取请求后的cookie |
response.url | 获取请求网址 |
response.json() | 内置的JSON解码器 |
Response.headers | 以字典对象存储服务器响应头,字典键不区分大小写 |
response = requests.request(method, url,
params=None, data=None, headers=None, cookies=None, files=None,
auth=None, timeout=None, allow_redirects=True, proxies=None,
stream=None, verify=None, cert=None, json=None)
response
是一个Response
对象,一个包含服务器资源的对象
参数说明
response = requests.get(url='http://', params=None, **kwargs)
参数 | 类型 | 作用 |
---|---|---|
params | 字典 | url为基准的url地址,不包含查询参数;该方法会自动对params字典编码,然后和url拼接 |
url | 字符串 | requests 发起请求的地址 |
headers | 字典 | 请求头,发送请求的过程中请求的附加内容携带着一些必要的参数 |
cookies | 字典 | 携带登录状态 |
proxies | 字典 | 用来设置代理 ip 服务器 |
timeout | 整型 | 用于设定超时时间, 单位为秒 |
response = requests.post(url='http://', data=None, json=None, **kwargs)
参数 | 类型 | 作用 |
---|---|---|
data | 字典 | 作为向服务器提供或提交资源时提交,主要用于 post 请求 |
json | 字典 | json格式的数据, json合适在相关的html |
注意:
其语法和 post 请求的语法类似
response = requests.put(url='http://', data=None, **kwargs)
put 和 post 区别:
其语法和 get 请求的语法类似
response = requests.delete(url='http://', **kwargs)
重定向就是网络请求被重新定个方向转到了其它位置
常见状态码
状态码 | 内容 |
---|---|
200 | 请求成功,服务器已经将请求的响应头和数据返回 |
201 | 请求成功,服务器已经创建新的资源,并将数据返回 |
202 | 请求成功,但是服务器尚未处理 |
301 | 请求成功,服务器将请求资源永久转移到新的位置,并且下次会自动转移到新的位置 |
302 | 请求成功,服务器将请求资源临时转移到新的位置,但是下次访问请求者会访问原来的位置 |
304 | 请求成功,但是服务器不会做任何的修改,也不会返回任何响应内容 |
401 | 服务器需要验证身份才能相应 |
403 | 服务器收到请求,但是拒绝返回信息 |
404 | 请求失败,服务器没有找到任何关于响应的内容 |
501 | 服务器无法完成对请求的处理 |
503 | 服务器无法完成对请求的处理,也许是过载的问题,但是一会儿就会恢复 |
重定向状态码:
禁止重定向( allow_redirects=False ,默认是True)
import requests
# allow_redirects= False 这里设置不允许跳转
# 实际url:'https://www.jd.com'
response = requests.get(url='http://jd.com/', allow_redirects=False)
print(response.headers)
print(response.status_code)
看结果 返回response header 中有一个属性 Location ,代表重定向了 'Location': 'https://www.jd.com'
在浏览器中 chrome network 面板 ,抓包观察。 注意把 preserve log 这个选项勾选上。
从浏览器的response header 中 我们可以看到 Location, 从 General 我们可以看到 status code 301 ,发生了跳转
重定向获取真实的URL
import requests
# allow_redirects= False 这里设置不允许跳转
# 实际url:'https://www.jd.com'
response = requests.get(url='http://jd.com/', allow_redirects=False)
print(response.headers['Location'])
import requests
# 默认allow_redirects= Ture 这里设置允许跳转
# 实际url:'https://www.jd.com'
response = requests.get(url='http://jd.com/')
print(response.url)
追踪重定向
import requests
response = requests.get(url='http://jd.com/')
print(response.history) # history追踪页面重定向历史
使用 Requests 模块上传文件,文件的类型会自动进行处理:
import requests
# 直接通过open函数打开文件并将文件对象存在字典中
files = {'file': open('D:/pycharm_mm/Framework_request/a.txt', 'rb')}
response = requests.post("http://httpbin.org/post", files=files)
print(response.text)
在进行爬虫爬取时,有时候爬虫会被服务器给屏蔽掉,这时采用的方法主要有降低访问时间,通过代理ip访问,网站面对多个不同的ip地址,就没有办法屏蔽。
正向代理:浏览器明确知道要访问的是什么服务器,只不过目前无法达到,需要通过代理来帮助完成这个请求操作。
反向代理:浏览器不知道任何关于要请求的服务器的信息,需要通过Nginx请求。
代理设置不同python版本有不同的写法
1. python3.8以下版本:
proxies{' 要请求网站的协议类型 ' , ' 代理服务器ip : 端口 '}
2. python3.8以上版本:
proxies{' 要请求网站的协议类型 ' , ' "代理服务器类型(http/https/socks5)://代理服务器ip : 端口 '}
import requests
proxies = {
"http": "http://10.10.1.10:3128",
"https": "http://10.10.1.10:1080"
}
try:
response = requests.get("http://example.org", proxies=proxies)
print(response.text)
except requests.exceptions.ConnectionError as e:
print('Error:', e.args)
访问有些网站时可能会超时,这时设置好timeout就可以解决这个问题
import requests
from requests.exceptions import ReadTimeout
try:
response = requests.get("http://httpbin.org/get", timeout = 0.5)
print(response.status_code)
except ReadTimeout:
print('Timeout')
cookie是一段不超过4KB的小型 文本 数据,由一个名称(Name)、一个值(Value)和其它几个用于控制Cookie有效期、安全性、使用范围的可选属性组成。
cookie 是 开发工程师,针对 http请求 无状态、无连接 特性,设计的技术。
cookie 看做一个容器。默认 4k。数据存储在 浏览器端。支持的数据类型,受浏览器限制。
只能存储 少量、不敏感的 用户信息,方便访问 服务器。
cookie 中的 数据,可以十分方便获取到。
import requests
response = requests.get("https://www.baidu.com/")
print(response.cookies)
for key, value in response.cookies.items():
print(key + '=' + value)
session 由服务端创建,当一个请求发送到服务端时,服务器会检索该请求里面有没有包含 sessionId 标识,如果包含了 sessionId,则代表服务端已经和客户端创建过 session,然后就通过这个 sessionId 去查找真正的 session,如果没找到,则为客户端创建一个新的 session,并生成一个新的 sessionId 与 session 对应,然后在响应的时候将 sessionId 给客户端,通常是存储在 cookie 中。如果在请求中找到了真正的 session,验证通过,正常处理该请求。Session用于存储用户的信息。
session位于服务器端。大小直接使用服务器存储空间
session中的数据,不能随意被访问,安全性较高
Session中存储的数据类型,受服务器影响,几乎能支持所有的数据类型
因为Cookie中的数据,都是Session传递的,因此,Session 可以直接自动管理cookie地
会话维持:
import requests
# 创建一个Session 实例
session = requests.session()
# 使用Session实例, 发送获取验证码请求(不需要获取cookie)
verify_url = "http://hmshop-test.itheima.net/index.php?m=Home&c=User&a=verify"
verify_resp = session.get(url=verify_url)
# 使用同一个Session实例,调用post方法,发送登录请求
login_url = "http://hmshop-test.itheima.net/index.php?m=Home&c=User&a=do_login"
login_header = {"Content-Type": "application/x-www-form-urlencoded"}
login_data = {"username": "13012345678", "password": "123456", "verify_code": "8888"}
login_resp = session.post(url=login_url, headers=login_header, data=login_data)
# 使用同一个Session实例,调用get方法,发送 查看我的订单请求
order_url = "http://hmshop-test.itheima.net/home/Order/order_list.html"
order_resp = session.get(url=order_url)
print(order_resp.headers)
为什么会有它们?
都知道 HTTP 协议是无状态的,所谓的无状态就是客户端每次想要与服务端通信,都必须重新与服务端链接,意味着请求一次客户端和服务端就连接一次,下一次请求与上一次请求是没有关系的。
这种无状态的方式就会存在一个问题:如何判断两次请求的是同一个人?就好比用户在页面 A 发起请求获取个人信息,然后在另一个页面同样发起请求获取个人信息,我们如何确定这俩个请求是同一个人发的呢?
为了解决这种问题,我们就迫切需要一种方式知道发起请求的客户端是谁?此时,cookie、token、session 就出现了,它们就可以解决客户端标识的问题,在扩大一点就是解决权限问题。
它们就好比让每个客户端或者说登录用户有了自己的身份证,我们可以通过这个身份证确定发请求的是谁!
什么是 cookie?
cookie 是保存在客户端或者说浏览器中的一小块数据,大小限制大致在 4KB 左右,在以前很多开发人员通常用 cookie 来存储各种数据,后来随着更多浏览器存储方案的出现,cookie 存储数据这种方式逐渐被取代,主要原因有如下:
cookie 主要有以下属性:
属性名称 | 属性含义 |
---|---|
name | cookie 的名称 |
value | cookie 的值 |
comment | cookie 的描述信息 |
domain | 可以访问该 cookie 的域名 |
expires | cookie 的过期时间,具体某一时间 |
maxAge | cookie 的过期时间,比如多少秒后 cookie 过期。 |
path | cookie 的使用路径 |
secure | cookie 是否使用安全协议传输,比如 SSL 等 |
version | cookie 使用的版本号 |
isHttpOnly | 指定该 Cookie 无法通过 JavaScript 脚本拿到,比如 Document.cookie 属性、XMLHttpRequest 对象和 Request API 都拿不到该属性。这样就防止了该 Cookie 被脚本读到,只有浏览器发出 HTTP 请求时,才会带上该 Cookie |
那么我们是如何通过 cookie 来实现用户确定或者权限的确定呢?
我们就以一个普通网站的用户登录操作以及后续操作为例,主要过程可以简单用下图表示:
从上图中可以看到使用 cookie 进行用户确认流程是比较简单的,大致分为以下几步:
1.客户端发送请求到服务端(比如登录请求)。
2.服务端收到请求后生成一个 session 会话。
3.服务端响应客户端,并在响应头中设置 Set-Cookie。Set-Cookie 里面包含了 sessionId,它的格式如下:
Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
。其中 sessionId 就是用来标识客户端的,类似于去饭店里面,服务 员给你一个号牌,后续上菜通过这个号牌来判断上菜到哪里。
4.客户端收到该请求后,如果服务器给了 Set-Cookie,那么下次浏览器就会在请求头中自动携带 cookie。
5.客户端发送其它请求,自动携带了 cookie,cookie 中携带有用户信息等。
6.服务端接收到请求,验证 cookie 信息,比如通过 sessionId 来判断是否存在会话,存在则正常响应。
cookie 主要有以下特点:
什么是 session?
在上一节中,我们通过 Cookie 来实现了用户权限的确认,在其中我们提到了一个词:session。顾名思义它就是会话的意思,session 主要由服务端创建,主要作用就是保存 sessionId,用户与服务端之间的权限确认主要就是通过这个 sessionId。
简单描述下 session:
session 由服务端创建,当一个请求发送到服务端时,服务器会检索该请求里面有没有包含 sessionId 标识,如果包含了 sessionId,则代表服务端已经和客户端创建过 session,然后就通过这个 sessionId 去查找真正的 session,如果没找到,则为客户端创建一个新的 session,并生成一个新的 sessionId 与 session 对应,然后在响应的时候将 sessionId 给客户端,通常是存储在 cookie 中。如果在请求中找到了真正的 session,验证通过,正常处理该请求。
总之每一个客户端与服务端连接,服务端都会为该客户端创建一个 session,并将 session 的唯一标识 sessionId 通过设置 Set-Cookie 头的方式响应给客户端,客户端将 sessionId 存到 cookie 中。
通常情况下,我们 cookie 和 session 都是结合着来用,当然你也可以单独只使用 cookie 或者单独只使用 session,这里我们就将 cookie 和 session 结合着来用。
我们可以在修改一下整个请求过程图,如下所示:
cookie 和 session 的区别?
前面两节我们介绍了 cookie 和 session,它们两者之间主要是通过 sessionId 关联起来的,所以我们总结出:sessionId 是 cookie 和 session 之间的桥梁。我们日常的系统中如果在鉴权方面如果使用的是 cookie 方式,那么大部分的原理就和我们前面说的一样。
或者我们可以换个说法,session 是基于 cookie 实现的,它们两个主要有以下特点:
系统想要实现鉴权,可以单独使用 cookie,也可以单独使用 session,但是建议结合两者使用。
token 是什么?
前面我们说的 sessionId 可以叫做令牌,令牌顾名思义就是确认身份的意思,服务端可以通过令牌来确认身份。
cookie+session 是实现认证的一种非常好的方式,但是凡事都有两面性,它们实现的认证主要有以下缺点:
那么为了避免这些缺点,token 方式的鉴权出现了,它可以说是一个民间的认证方式,但是不得不说它带来了非常多的好处。
token 的组成:
token 其实就是一串字符串而已,只不过它是被加密后的字符串,它通常使用 uid(用户唯一标识)、时间戳、签名以及一些其它参数加密而成。我们将 token 进行解密就可以拿到诸如 uid 这类的信息,然后通过 uid 来进行接下来的鉴权操作。
token 是如何生成的:
前面我们说 cookie 是服务端设置了 set-cookie 响应头之后,浏览器会自动保存 cookie,然后下一次发送请求的时候会自动把 cookie 携带上。但是我们说 cookie 算是一种民间的实现方式,所以说浏览器自然不会对它进行成么处理。token 主要是由服务器生成,然后返回给客户端,客户端手动把 token 存下来,比如利用 localstorage 或者直接存到 cookie 当中也行。
token 认证流程:
1.客户端发起登录请求,比如用户输入用户名和密码后登录。
2.服务端校验用户名和密码后,将用户 id 和一些其它信息进行加密,生成 token。
3.服务端将 token 响应给客户端。
4.客户端收到响应后将 token 存储下来。
5.下一次发送请求后需要将 token 携带上,比如放在请求头中或者其它地方。
6.服务端 token 后校验,校验通过则正常返回数据。
总结
虽然前面解释 cookie、session、token 用了不少口舌,但是归根结底啊,它们的目的都是一样的:鉴权和认证。
鉴权认证方式 | 特点 | 优点 | 缺点 |
---|---|---|---|
cookie | 1.存储在客户端。2.请求自动携带 cookie。3.存储大小 4KB。 | 1.兼容性好,因为是比较老的技术。2.很容易实现,因为 cookie 会自动携带和存储。 | 1.需要单独解决跨域携带问题,比如多台服务器如何共享 cookie。2.会遭受 CSRF 攻击。3.存储在客户端,不够安全。 |
session | 1.存储在服务端。2.存储大小无限制。 | 1.查询速度快,因为是个会话,相当于是在内存中操作。2.结合 cookie 后很容易实现鉴权。3.安全,因为存储在服务端。 | 1.耗费服务器资源,因为每个客户端都会创建 session。2.占据存储空间,session 相当于存储了一个完整的用户信息。 |
token | 1.体积很小。2.自由操作存储在哪里。 | 1.安全,因为 token 一般只有用户 id,就算被截取了也没什么用。2.无需消耗服务器内存资源,它相当于只存了用户 id,session 相当于存储了用户的所有信息。3.跨域处理较为方便,比如多台服务器之间可以共用一个 token。 | 1.查询速度慢,因为 token 只存了用户 id,每次需要去查询数据库。 |
总结下来就是:session 是空间换时间,token 是时间换空间。
最新的requests库是支持https请求的,但是一般写脚本时候,会用抓包工具fiddler,这时候会报SSLError
错误
import requests
# 正常情况能够直接支持https请求
response = requests.get('https://www.12306.cn')
print(response)
原因:
fiddler作为中间人获取了网站的公钥和客户端的密钥,然后伪装成客户端和服务端通信(使用网站公钥和自己的密钥),再伪装成服务端把收到的信息发送给客户端(使用自己的公钥和客户端的密钥)。fiddler的公钥不是ca认证的,所以requests就无法通过内置的ca公钥解密,验证就会失败。所以要不不验证,要不指定和特定的证书进行对比验证,就能解决问题。
解决方案:
关闭 fiddler
去掉requests的ssl验证(SSL证书认证参数 verify
默认为True)
requests.get(url, verify=False) # 发送https请求时,加入verify=False,忽略证书验证
但是依然会出现两行Warning,使用urllib3.disable_warnings()
解决
import urllib3
import requests
urllib3.disable_warnings() # 将这段代码放到调用https的代码段中,避免其他模块调用时仍报该错
response = requests.get('https://www.12306.cn', verify=False)
print(response)
保持fiddler和requests的证书一致
所有Requests显式抛出的异常都继承自 requests.exceptions.RequestException
异常 | 说明 |
---|---|
request.exceptions.ConnectTimeout | 连接超时 |
requests.exceptions.ConnectionError | 网络连接错误异常,如DNS查询失败、拒绝连接等 |
requests.exceptions.ProxyError | 代理服务器拒绝建立连接,端口拒绝连接或未开放 |
requests.exceptions.HTTPError | HTTP错误异常 |
requests.exceptions.TooManyRedirects | 超过做大重定向次数,产生重定向异常 |
requests.exceptions.Timeout | 请求URL超时,产生超时异常 |
Response.raise_for_status() | 如果不是200,产生异常requests.HTTPError |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。