Requests

Requests 官方说它是一个简单而优雅的 HTTP 库

Requests官方文档

Requests使用大纲

image-20201222183136947

HTTP形式的API的请求方式

  • GET:GET 方法请求一个指定资源的表示形式,使用 GET 的请求应该只被用于获取数据。
  • HEAD:HEAD 方法请求一个与 GET 请求的响应相同的响应,但没有响应体。
  • POST:POST 方法用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用。
  • PUT:PUT 方法用请求有效载荷替换目标资源的所有当前表示。
  • DELETE:DELETE 方法删除指定的资源。
  • CONNECT:CONNECT 方法建立一个到由目标资源标识的服务器的隧道。
  • OPTIONS:OPTIONS 方法用于描述目标资源的通信选项。
  • TRACE:TRACE 方法沿着到目标资源的路径执行一个消息环回测试。
  • PATCH:PATCH 方法用于对资源应用部分修改。

一般情况下,在测试中使用最多的请求方式是 GET、POST、PUT、DELETE 这四种。并且如果是通过代码方式发送请求,在 Python 里我们最经常用的就是 Requests 库。

Requests安装

Requests 的安装非常简单,只要在命令行里输入如下命令即可:

1
2
3
4
# 安装
python -m pip install requests / pip install request
# 安装完成后,查看
python -m pip show requests

Requests 使用

发送请求

发送get请求

1
2
3
4
5
import requests

if __name__ == '__main__':
# 发送get请求
requests.get('https://httpbin.org/ip')

是不是非常简单?但在实际应用中,GET 接口请求常常要带参数 query string,而且有时候需要加 Header,鉴权(OAuth)甚至代理(Proxy),那么这部分接口请求如何发送呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests

if __name__ == '__main__':
# 发送get请求 --带参数
# 等同于直接访问https://httpbin.org/get?kevin=hello
requests.get('https://httpbin.org/get', params={'test': 'hello'})
# 当访问接口发生301跳转时,可以设置允许或者禁止跳转
requests.get('http://github.com/', allow_redirects=False)
# 发送get请求, 加proxy
proxies = {'http': 'http://10.10.1.10:3128',
'https': 'http://10.10.1.10:1080'}
requests.get('https://httpbin.org/get', proxies=proxies)
# 发送get请求,加鉴权 -- Basic Auth
# 首先导入HTTPBasicAuth,一般导入语句写在py文件的最前面。
from requests.auth import HTTPBasicAuth

requests.get('https://api.github.com/user', auth=HTTPBasicAuth('user', 'password'))
# 发送get请求,加鉴权 -- Digest Auth
# 首先导入HTTPDigestAuth,一般导入语句写在py文件的最前面。
from requests.auth import HTTPDigestAuth

requests.get('https://api.github.com/user', auth=HTTPDigestAuth('user', 'password'))

OAuth 1 Authentication

  • 安装requests-oauthlib

    1
    pip install requests-oauthlib
  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    import requests
    from requests_oauthlib import OAuth1

    if __name__ == '__main__':
    url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
    auth = OAuth1('YOUR_APP_KEY', 'YOUR_APP_SECRET', 'USER_OAUTH_TOKEN', 'USER_OAUTH_TOKEN_SECRET')
    requests.get(url, auth=auth)

发送post请求

post 请求通常都会带数据 Payloads,当然也会需要 Header、OAuth,发送方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests
from requests.auth import HTTPBasicAuth

if __name__ == '__main__':
url = 'https://httpbin.org/anything'
headers = {'user-agent': 'my-app/ 0.0.1'}
payloads = {'testing': 'better to follow'}
auth = {"username": "testing", "password": "123123"}
# 直接post
r = requests.post(url, data=payloads)
# post带header
r = requests.post(url, headers=headers, data=payloads)
# post带鉴权, auth类型跟get请求支持的auth类型相同。
r = requests.post(url, headers=headers, data=payloads, auth=HTTPBasicAuth('user', 'password'))

发送put请求

1
2
3
4
5
6
7
8
import requests

if __name__ == '__main__':
# 直接发送put请求
# 如需要加header,auth,即参考post请求
r = requests.put('https://httpbin.org/put', data={'hello': 'test'})
print(r.text)

发送delete请求

1
2
3
4
5
6
7
import requests

if __name__ == '__main__':
# 直接发送delete请求
r = requests.delete('https://httpbin.org/anything', data={'hello': 'test'})
print(r.text)

requests统一的request方法来发送各种请求

1
2
3
4
5
6
r = requests.request('get', 'https://httpbin.org/ip')
r = requests.request('post', 'http://httpbin.org/post', data = {'key':'value'})
r = requests.request('put', 'http://httpbin.org/put', data = {'key':'value'})
r = requests.request('delete', 'http://httpbin.org/delete')
r = requests.request('head', 'http://httpbin.org/get')
r = requests.request('options', 'http://httpbin.org/get')

获取接口返回值

接口的请求通常会有返回值,在接口测试中,特别是在顺序访问多个接口,并且前一个接口的返回是后一个接口的入参时,常常需要把接口返回的结果保持下来解析,那么如何保持接口请求呢?

Requests 中提供了以下方式来保存接口返回值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests

if __name__ == '__main__':
s = requests.session()
r = s.post('https://httpbin.org/anything', data={'hello': 'kevin'})
# 返回文本型response
print(r.text)
# #返回文本型response,并用utf-8格式编码
# # 当你用r.text得出的结果是不可读的内容例如包括类似xu'\xe1'或者有错误提示“'ascii' codec can't encode characters in position”时,可以用encode
print(r.text.encode('utf-8'))
# # 获取二进制返回值
print(r.content)
# # 获取请求返回码
print(r.status_code)
# 获取response的headers
print(r.headers)
# 获取请求返回的cookies
s.get('http://google.com')
print(r.cookies.get_dict())

获取接口返回值后,如果你的前一个接口的返回是下一个接口的入参,那么就可以根据需要采用以上方式的任意一个解析出你需要的返回值,然后传递给下一个接口即可。

Requests 保存 Session

以上 4 种 Requests 使用方式是直接发送接口请求,我们知道 HTTP 协议是无状态的协议,这也就导致每次接口请求都是独立的,也就意味着你的多个接口请求之间不能共用数据,比如登录态、cookie 等都是不能共用,这显然不符合我们的需求。

基于此,Requests 库提供了 Session 会话对象, 用来帮我们跨请求保持参数,使用 requests.Session() , 可以在一个 Session 实例的所有请求中保留 cookie,下面我们来看下 requests.Session() 的基本用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests

if __name__ == '__main__':
# 初始化一个session对象
s = requests.Session()
# 第一个get,先设置一个session
# httpbin这个网站允许我们通过如下方式设置,在set后写你需要的值即可
s.get('https://httpbin.org/cookies/set/sessioncookie/testing')
# 设置好后获取所有的cookies
r = s.get('https://httpbin.org/cookies')
# 打印,确定我们的cookies被保存了
print(r.text)
# 结果如下
# '{"cookies": {"sessioncookie": "testing"}}'

requests.Session() 的使用非常简单,首先你初始化一个 session 对象,接着你使用这个初始化后对象实例直接发起请求,在整个 session 内的所有请求之间是可以共享状态的。上个例子中我们就先初始化了 Session() 对象,假设是 s,然后通过 s.get() 方法去设置了一个 cookie,它的名字是 sessioncookie,它的值是 testing。最后,我们去访问 cookies 接口,就拿到了我们刚设置的 cookie。通过 requests.Session() 的方式,我们就实现了 cookie 的保存。

一般在测试中,你可以通过直接请求登录接口便能拿到登录态,例如如下的形态:

1
2
3
4
5
6
7
8
9
# 本代码仅供演示用法
import requests

if __name__ == '__main__':
s = requests.Session()
# 登录获取登录态
s.post(login_url, data=data, headers=headers, verify = False)
# 登录态获取后,请求登录后才能访问的接口,也能请求成功。
s.post('your-api')

接下来进行示例演示,采用cookies的方式绕过登录,例如:使用cookies登录github,打开Chrome浏览器,访问已经登录的github的页面,command+option+i打开chrome的开发小工具,重新请求一下页面,去 Applicaton → Cookies下查看 cookies:

image-20201222170958186

1
2
3
4
5
6
7
8
9
10
11
12
import requests

if __name__ == '__main__':
url = 'https://github.com/'
cookie = {
'cookie': 'dotcom_user=jinglv; user_session=vTNzJopy2FIqTCvY8eWfL5YLX9EW-OLkqTwfrqxIO1xP0xa5xs;'}
s = requests.Session()
# 直接带登录态发送请求
r = s.get(url, cookies=cookie)
# 不经过登录,也能访问登录后才能访问的页面
print(r.text.encode('utf-8'))