为了账号安全,请及时绑定邮箱和手机立即绑定

Python接口测试实战2 - 使用Python发送请求

标签:
Python

本节内容

  • requests安装

  • requests使用

  • JSON类型解析

  • requests库详解

  • 带安全认证的请求

序言

上节课我们学习了接口测试的理论,抓包工具及使用Postman手工测试各种接口,这节课我们主要讲解使用Python语言来发送接口请求,实现接口测试自动化。

发送请求,我们这里主要使用Python的一个第三方包(需要先安装):requests
Python3自带的http.client和urllib.request都能发送http请求,不过相对来说使用较麻烦,第三方库requests让发送请求更简单,支持自动编码解码,会话保持,长连等

参考: requests官方文档

requests安装

  • Windows: 打开cmd命令行,输入pip install requests,等待安装完成即可

  • Linux: (建议使用Python3),终端中输入pip3 install requests,等待安装完成即可

  • Mac: (建议使用Python3), sudo python3 -m pip install requests,等待安装完成即可

验证是否安装成功:

打开命令行,输入python,在python shell环境下输入import requests没有报错即安装成功

requests的使用

一个最简单的GET请求

发送一个请求分3步:

  1. 组装请求: 请求可能包含url,params(url参数),data(请求数据),headers(请求头),cookies等,最少必须有url

  2. 发送请求,获取响应:支持get,post等各种方法发送,返回的是一个响应对象

  3. 解析响应: 输出响应文本

打开Pycharm,新建一个demo项目,项目下新建一个Python文件,输入以下内容:

# 导入requests包import requests 

# 1. 组装请求url = "http://httpbin.org/get"  # 这里只有url,字符串格式# 2. 发送请求,获取响应res = requests.get(url) # res即返回的响应对象# 3. 解析响应print(res.text)  # 输出响应的文本

带参数的GET请求

import requests 

url = "http://www.tuling123.com/openapi/api?key=ec961279f453459b9248f0aeb6600bbe&info=你好"  # 参数可以写到url里res = requests.get(url=url) # 第一个url指get方法的参数,第二个url指上一行我们定义的接口地址print(res.text)

import requests 

url = "http://www.tuling123.com/openapi/api"params = {"key":"ec961279f453459b9248f0aeb6600bbe","info":"你好"} # 字典格式,单独提出来,方便参数的添加修改等操作res = requests.get(url=url, params=params) 
print(res.text)

传统表单类POST请求(x-www-form-urlencoded)

import requests 

url = "http://httpbin.org/post"data = {"name": "hanzhichao", "age": 18} # Post请求发送的数据,字典格式res = requests.post(url=url, data=data) # 这里使用post方法,参数和get方法一样print(res.text)

JSON类型的POST请求(application/json)

import requests 

url = "http://httpbin.org/post"data = '''{
        "name": "hanzhichao",
        "age": 18
        }''' # 多行文本, 字符串格式,也可以单行(注意外层有引号,为字符串) data = '{"name": "hanzhichao", "age": 18}'res = requests.post(url=url, data=data) #  data支持字典或字符串print(res.text)

data参数支持字典格式也支持字符串格式,如果是字典格式,requests方法会将其按照默认表单urlencoded格式转换为字符串,如果是字符串则不转化
如果data以字符串格式传输需要遵循以下几点:

  • 必须是严格的JSON格式字符串,里面必须用双引号,k-v之间必须有逗号,布尔值必须是小写的true/false等等

  • 不能有中文,直接传字符串不会自动编码

一般来说,建议将data声明为字典格式(方便数据添加修改),然后再用json.dumps()方法把data转换为合法的JSON字符串格式

import requests 
import json # 使用到JSON中的方法,需要提前导入url = "http://httpbin.org/post"data = {        "name": "hanzhichao",        "age": 18
        }  # 字典格式,方便添加headers = {"Content-Type":"application/json"} # 严格来说,我们需要在请求头里声明我们发送的格式res = requests.post(url=url, data=json.dumps(data), headers=headers) #  将字典格式的data变量转换为合法的JSON字符串传给post的data参数print(res.text)

或直接将字典格式的data数据赋给post方法的JSON参数(会自动将字典格式转为合法的JSON文本并添加headers)

import requests 

url = "http://openapi.tuling123.com/openapi/api/v2"data = {    "reqType":0,    "perception": {        "inputText": {            "text": "附近的酒店"
        },        "inputImage": {            "url": "imageUrl"
        },        "selfInfo": {            "location": {                "city": "北京",                "province": "北京",                "street": "信息路"
            }
        }
    },    "userInfo": {        "apiKey": "ec961279f453459b9248f0aeb6600bbe",        "userId": "206379"
    }
} 
res = requests.post(url=url, json=data) # JSON格式的请求,将数据赋给json参数print(res.text)

练习:

  1. 利用图灵聊天接口(GET) http://www.tuling123.com/openapi/api?key=ec961279f453459b9248f0aeb6600bbe&info=你好,结合Python的input编写一个机器人聊天室

  2. 利用图灵查询接口(POST)http://openapi.tuling123.com/openapi/api/v2,封装一个实用的查询方法,查询你附近的美食等等

JSON类型解析

序列化和反序列化

程序中的对象,如Python中的字典、列表、函数、类等,都是存在内存中的,一旦断电就会消失,不方便传递或存储,所以我们需要将内存中的对象转化为文本或者文件格式,来满足传输和持久化(存储)需求

  • 序列化: 内存对象 ->  文本/文件

  • 反序列化: 文本 -> 内存对象

对象在HTTP中的传输过程
HTTP协议是超文本传输协议,是通过文本或二进制进行传输的,所以我们发送的请求要转化成文本进行传输,收到的响应也是文本格式,如果是JSON,一般还需要将文本格式重新转化为对象

JSON对象(Python字典) -> 转为文本请求 -> 发送请求
-> 服务器收到文本请求 -> 将文本请求转化为对象,获取其中的参数,处理业务
-> 返回文本格式的响应 -> 客户端转为对象格式来从响应中取值

JSON对象与Python字典的区别

JSON对象是javascript object即javascript中的对象,是一种通用的格式,格式严格,不支持备注。

JSON文本和JSON对象的区别:

  • JSON文本是符合JSON格式的文本,实际上是一个字符串

  • JSON对象是内存中一个对象,拥有属性和方法,可以通过对象获取其中的参数信息

Python中我们一般提到JSON对象指的是字典

Python的字典的格式和JSON格式,稍有不同:

  • 字典中的引号支持单引号和双引号,JSON格式只支持双引号

  • 字典中的True/False首字母大写,JSON格式为true/false

  • 字典中的空值为None, JSON格式为null

JSON格式操作方法

  • 序列化(字典 -> 文本/文件句柄): json.dumps()/json.dump()

  • 反序列化(文本/文件句柄 -> 字典) : json.loads()/json.load()

import json # 需要导入JSON包data = {'name': '张三', 'password': '123456', "male": True, "money": None} # 字典格式str_data = json.dumps(data) # 序列化,转化为合法的JSON文本(方便HTTP传输)print(str_data)

输出:{"name": "\u5f20\u4e09", "password": "123456", "male": true, "money": null}

json.dumps()支持将json文本格式化输出

import requests 
import json

res = requests.post("http://www.tuling123.com/openapi/api?key=ec961279f453459b9248f0aeb6600bbe&info=怎么又是你") 
print(res.text) # 输出为一行文本res_dict = res.json() # 将响应转为json对象(字典)等同于`json.loads(res.text)`print(json.dumps(res_dict, indent=2, sort_keys=True, ensure_ascii=False)) # 重新转为文本

看一下输出结果对比:

{"code":100000,"text":"我才要说怎么又是你"}  # res.text,有些接口中文会返回为\u..{  "code": 100000,  "text": "我才要说怎么又是你"  # 树状格式,比较清晰,显示中文}
  • indent: 缩进空格数,indent=0输出为一行

  • sork_keys=True: 将json结果的key按ascii码排序

  • ensure_ascii=Fasle: 不确保ascii码,如果返回格式为utf-8包含中文,不转化为\u...

反序列化

import json

res_text = {"name": "\u5f20\u4e09", "password": "123456", "male": true, "money": null}  # JSON文本格式的响应信息res_dict = json.loads(res_text) # 转化为字典 print(res_dict['name'])  # 方便获取其中的参数值

输出:张三

文件的序列化与反序列化

  1. 序列化:字典 -> 文件句柄

import json

res_dict = {'name': '张三', 'password': '123456', "male": True, "money": None} # 字典格式f = open("demo1.json","w")
json.dump(res_dict, f)

查看同级目录,增加了一个demo1.json文件,内容为:

{"name": "\u5f20\u4e09", "password": "123456", "male": true, "money": null}
  1. 序列化: 文件句柄 -> 字典

在项目中(和下面脚本文件同一路径下)新建demo2.json文件,内容如下,保存

{  "name": "张三",  "password": "123456",  "male": true,  "money": null}

新建Python文件

import json

f = open("demo.JSON","r", encoding="utf-8")  # 文件中有中文需要指定编码f_dict = json.load(f) # 反序列化将文件句柄转化为字典print(f['name']) # 读取其中参数f.close()

什么时候使用JSON对象(字典)什么时候使用JSON文本?
一般在组装data参数时,建议使用字典格式,发送请求时用json.dumps(data)转化为文本发送,收到请求后使用json.loads(res.text)转化为字典,方便我们获取其中的参数信息
练习:

  1. 解析以下json格式文件,发送请求并打印响应

注: method支持get和post,如果没有method,有data默认发post请求,没有data默认发get请求,type支持:form或json,没有默认发form格式
demo1.json

{  "url": "http://www.tuling123.com/openapi/api",  "method": "get",  "params": {    "key": "ec961279f453459b9248f0aeb6600bbe",    "info": "你好"
  }
}

demo2.json

{  "url": "http://openapi.tuling123.com/openapi/api/v2",  "method": "post",  "type": "json",  "data": {    "reqType": 0,    "perception": {      "inputText": {        "text": "附近的酒店"
      },      "inputImage": {        "url": "imageUrl"
      },      "selfInfo": {        "location": {          "city": "北京",          "province": "北京",          "street": "信息路"
        }
      }
    },    "userInfo": {      "apiKey": "ec961279f453459b9248f0aeb6600bbe",      "userId": "206379"
    }
  }
}

requests库详解

请求方法

  • requests.get()

  • requests.post()

  • requests.put()
    ...

  • requests.session(): 用于保持会话(session)
    除了requests.session()外,其他请求方法的参数都差不多,都包含url,params, data, headers, cookies, files, auth, timeout等等

请求参数

  • url: 字符串格式,参数也可以直接写到url中

  • params:url参数,字典格式

  • data: 请求数据,字典或字符串格式

  • headers: 请求头,字典格式

  • cookies: 字典格式,可以通过携带cookies绕过登录

  • files: 字典格式,用于混合表单(form-data)中上传文件

  • auth: Basic Auth授权,数组格式 auth=(user,password)

  • timeout: 超时时间(防止请求一直没有响应,最长等待时间),数字格式,单位为秒

响应解析

  • res.status_code: 响应的HTTP状态码

  • res.reason: 响应的状态码含义

  • req.text:响应的文本格式,按req.encoding解码

  • req.content: 响应的二进制格式

  • req.encoding: 解码格式,可以通过修改req.encoding='utf-8'来解决一部分中文乱码问题

  • req.apparent_encoding:真实编码,由chardet库提供的明显编码

  • req.json(): (注意,有括号),响应的json对象(字典)格式,慎用!如果响应文本不是合法的json文本,或报错

  • req.headers: 响应头

  • req.cookies: 响应的cookieJar对象,可以通过req.cookies.get(key)来获取响应cookies中某个key对应的值
    ...
    示例:

import requests 

res = requests.get("https://www.baidu.com") 
print(res.status_code, res.reason) # 200 OKprint(res.text) # 文本格式,有乱码print(res.content) # 二进制格式print(res.encoding) # 查看解码格式 ISO-8859-1print(res.apparent_encoding) # utf-8res.encoding='utf-8' # 手动设置解码格式为utf-8print(res.text) # 乱码问题被解决print(res.cookies.items()) # cookies中的所有的项 [('BDORZ', '27315')]print(res.cookies.get("BDORZ")) # 获取cookies中BDORZ所对应的值 27315



作者:韩志超
链接:https://www.jianshu.com/p/e94a18950a53


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消