本节内容

requests安装

requests使用

JSON类型解析

requests库详解

带安全认证的请求

序言

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

发送请求,我们这里主要使用Python的一个第三方包(需要先安装):requests。

Python3自带的http.client和urllib.request都能发送http请求,不过相对来说使用较麻烦,第三方库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步:

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

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

解析响应: 输出响应文本

打开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)

练习:

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

利用图灵查询接口(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']) # 方便获取其中的参数值

输出:张三

文件的序列化与反序列化

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

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}

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

在项目中(和下面脚本文件同一路径下)新建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)转化为字典,方便我们获取其中的参数信息

练习:

解析以下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 OK

print(res.text) # 文本格式,有乱码

print(res.content) # 二进制格式

print(res.encoding) # 查看解码格式 ISO-8859-1

print(res.apparent_encoding) # utf-8

res.encoding='utf-8' # 手动设置解码格式为utf-8

print(res.text) # 乱码问题被解决

print(res.cookies.items()) # cookies中的所有的项 [('BDORZ', '27315')]

print(res.cookies.get("BDORZ")) # 获取cookies中BDORZ所对应的值 27315

带安全认证的请求

需要登录的请求(Cookie/Session认证)

未登录访问接口

使用会话保持

import requests

s = requests.session() # 新建一个会话

s.post(url="https://demo.fastadmin.net/admin/index/login.html",data={"username":"admin","password":"123456"}) # 发送登录请求

res = s.get("https://demo.fastadmin.net/admin/dashboard?ref=addtabs") # 使用同一个会话发送get请求,可以保持登录状态

print(res.text)

如果不使用session()而单独发一个post登录请求一个get请求是否可以呢?你可以自己试一下(requests.get()或post()每次都会建立一个新会话)

抓取cookies

import requests

url = "https://demo.fastadmin.net/admin/dashboard?ref=addtabs"

cookies = {"PHPSESSID":"9bf6b19ddb09938cf73d55a094b36726"}

res = requests.get(url=url, cookies=cookies) # 携带cookies发送请求

print(res.text)

两种方式的对比

使用session方式:每次都要发送两次请求,效率较低

使用携带cookies方式:需要手动抓包,提取组装,cookies中是session有一定有效期,过期之后要重新抓取和更换cookies

如果很多或所有请求都需要登录,可以发一次请求,保持该session为全局变量,其他接口都使用该session发送请求(同样要注意登录过期时间)

练习

抓包并用脚本发一条微博或一篇博客

appid或token方式

appid: 系统为合法用户赋予的访问id,固定的字符串,一般经过加密以确保HTTP传输中的安全

token: 即令牌,固定或需要动态申请(有一定有效期),一般由用户信息及申请时间计算加密而成,用于验证接口访问的权限

token与session的区别

session是存在服务器的,服务端通过验证客户端的请求所携带的session值在服务会话中是否存在,来验证用户是否合法

token: 是按一定算法加密计算出来的,服务端通过解密客户端所携带的token值来验证用户是否合法

**示例: **

访问百度AI开发者平台:http://ai.baidu.com/,注册并登录,成为开发者,选择文字识别

根据文档新建应用,查看自己的App Key和Secret Key

创建应用

获取token

通用文字接口

从网络上找一张带文字的图片,右键,复制图片地址(注意不支持https地址的图片)

带文字的图片

请求结果

import requests

import json

app_key = 'kPoFYw85FXsnojsy5bB9hu6x'

secret_key = 'l7SuGBkDQHkjiTPU3m6NaNddD6SCvDMC'

img_url = '//upload-images.jianshu.io/upload_images/7575721-40c847532432e852.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240'

# 获取token

get_token_url = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={}&client_secret={}'.format(app_key,secret_key)

token = requests.get(url=get_token_url).json().get("access_token") # 从获取token接口的响应中取得token值

# 识别图片文字

orc_url = 'https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token={}'.format(token)

data = {"url": img_url}

res = requests.post(url=orc_url, data=data)

print(json.dumps(res.json(), indent=2, ensure_ascii=False)) # 格式化输出

显示结果:

{

"log_id": 4745549456768330559,

"words_result_num": 6,

"words_result": [

{

"words": "我又问:那么何时,你带我回去?"

},

{

"words": "莲师言:你是你,我是我。你若不愿流连凡尘,自会回去。"

},

{

"words": "我问莲师:我从哪里来,要到哪里去?"

},

{

"words": "莲师言:世间种种变相,皆有起源。来与去皆是命中定数,不可参度。"

},

{

"words": "我再问:我是否还会再见到你?"

},

{

"words": "莲师言:你若心中有我,自然会再见。"

}

]

}

练习:

自己注册任意一个开发者平台(微信开发者平台,百度开发者平台,饿了么开发者平台),创建应用,根据相应的授权方式获取token,并使用token正常访问一个接口

开放协议授权

reqeusts支持Basic Auth(基本授权)和Digist Auth(摘要授权)

Oauth1.0 Oauth2.0 参考: requests官方文档

Basic Auth

import requests

import json

# 基本授权可以直接在请求方法中使用`auth = (user,password)`

res = requests.get("https://api.github.com/user", auth=("hanzhichao", "hanzhichao123"))

print(json.dumps(res.json(), indent=2, ensure_ascii=False)) # 格式化输出

数字签名

无论是cookie/session还是appid/token方式,只用来验证请求者身份而不验证参数,因此无法防止请求参数被抓包拦截后篡改(仍携带合法的cookie或token)

数字签名(sign或sig)是用来对原始参数整体进行加密后生成的一个字符串,请求时参数和签名一期发送,服务器收到请求后对参数再次计算签名核对和所携带的签名是否一致。

例如: 原始签名{}

python调用接口测试_Python接口测试实战2 - 使用Python发送请求相关推荐

  1. 云计算Python自动化运维开发实战 三、python文件类型

    为什么80%的码农都做不了架构师?>>>    云计算Python自动化运维开发实战 三.python文件类型 导语: python常用的有3种文件类型 1. 源代码     py ...

  2. Python调用OpenStack API 《通过RESTful编写Python运维》

    目录 Python调用OpenStack API   <通过RESTful编写Python运维> 赛题实施 1. 认证服务:用户管理 (1&#x

  3. python调用c++_python高性能编程之Cython篇 第一章

    第一节 cython的潜能 •Cython是一种编程语言,它将Python与C和C ++的静态类型系统相结合. •Cython是一个将Cython源代码转换为高效的C或C ++源代码的编译器.然后可以 ...

  4. python调用系统命令_Python如何调用外部系统命令

    前言 利用Python调用外部系统命令的方法可以提高编码效率.调用外部系统命令完成后可以通过获取命令执行返回结果码.执行的输出结果进行进一步的处理.本文主要描述Python常见的调用外部系统命令的方法 ...

  5. python网络爬虫_Python爬虫实战之网络小说

    今天和大家分享的是python爬虫实战,由于本人最近迷上了看网络小说,学生党又穷,只能看看网络dao版小说,现在这类dao版小说网站可以说非常的多,但是所有的网站进去都可以看见一大把的广告信息,非常影 ...

  6. python调用系统命令_Python调用外部系统命令

    利用Python调用外部系统命令的方法可以提高编码效率.调用外部系统命令完成后可以通过获取命令执行返回结果码.命令执行的输出结果进行进一步的处理.本文主要描述Python常见的调用外部系统命令的方法, ...

  7. python文件审计_Python代码审计实战案例总结之CRLF和任意文件读取

    文章目录 介绍 CRLF和任意文件读取的审计实战 CRLF 审计实战 urllib CRLF漏洞(CVE-2019-9740和CVE-2019-9947) httplib CRLF 漏洞 任意文件读取 ...

  8. python百度云盘采集_Python爬虫实战:抓取并保存百度云资源(附代码)!

    寻找并分析百度云的转存api 首先你得有一个百度云盘的账号,然后登录,用浏览器(这里用火狐浏览器做示范)打开一个分享链接.F12打开控制台进行抓包.手动进行转存操作:全选文件->保存到网盘-&g ...

  9. python 拼音库_python有没有拼音库python进阶之socket详解

    Socket的英文原义是"孔"或"插座".作为BSD UNIX的进程通信机制,通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句 ...

最新文章

  1. [LeetCode] [C++] 第一轮刷题总结(持续更新~~~)
  2. 如何安装系统认证签名过的APK
  3. ASP.NET MVC 4高级编程(第4版)
  4. 虚拟机centos 上安装svn
  5. liunx java font_Linux下JDK中文字体乱码 | 学步园
  6. ios 静态库合成_iOS : 静态库(.framework)合并
  7. 函数指针及其的运用(上)——何为函数指针
  8. EL表达式JSON应用
  9. webview设置请求时长_41个路口智能识别“公交信号” 66面电子屏告诉您乘公交车优先时长...
  10. 笔记本安装linux无线网卡,笔记本安装centos7 无线网卡启动不起来,那位大神看看?...
  11. 单片机软件开发的简单入门
  12. 如何在PC端看超星学习通直播
  13. 肖哥所有课程/HCNA HCNP/安全/云计算/虚拟化/linux/视频教程/资料软件下载链接
  14. 图像分割(语义分割)的局限以及解决方法
  15. 苹果税务信息填写教程
  16. DNS基础知识以及golang实现的简单DNS服务器
  17. 如何将kindle上的书导出成epub格式
  18. 大数据分析案例-对电信客户流失分析预警预测
  19. 安卓初中级开发基础知识整理(面试自用)
  20. 华为鸿蒙系统摄像头什么时候预售开卖,华为智选海雀智能摄像头PRO开卖 采用鸿蒙OS 内置AI智慧侦测...

热门文章

  1. vue 组件之间数据传递(七)
  2. windows phone7 学习笔记14——地理位置服务与反应性扩展框架
  3. 海量数据库解决方案2011030101
  4. Perl文档操作选项
  5. 简单的脚本控制面试题
  6. 我们应该搞清楚分支预测
  7. Linux C Socket编程,这篇文章让我耳目一新
  8. 初识Buildroot
  9. 单精度浮点数与十六进制转换
  10. c语言密文解密程序,请问有学长做过这个程序设计的吗?C语言写加密解密问题,跪求代码!...