requests库构建HTTP请求
构建HTTP请求:
1.构建请求URL参数
什么是url参数?
比如:
https://www.baidu.com/s?wd=iphone&rsv_spt=1
问号后面的部分 wd=iphone&rsv_spt=1 就是 url 参数,
每个参数之间是用 & 隔开的。
上面的例子中 有两个参数 wd 和 rsv_spt, 他们的值分别为 iphone 和 1 。
url参数的格式,有个术语叫 urlencoded 格式。
使用Requests发送HTTP请求,url里面的参数,通常可以直接写在url里面,比如
response = requests.get('https://www.baidu.com/s?wd=iphone&rsv_spt=1')
但是有的时候,我们的url参数里面有些特殊字符,比如 参数的值就包含了 & 这个符号。
那么我们可以把这些参数放到一个字典里面,然后把字典对象传递给 Requests请求方法的 params 参数,这时候params称为请求消息体,如下
urlpara = {
'wd':'iphone&ipad',
'rsv_spt':'1'
}
response = requests.get('https://www.baidu.com/s',params=urlpara)
2.构建请求消息头
有时候,我们需要自定义一些http的消息头
每个消息头也就是一种 键值对的格式存放数据,如下所示
user-agent: my-app/0.0.1
auth-type: jwt-token
Requests发送这样的数据,只需要将这些键值对的数据填入一个字典。
然后使用post方法的时候,指定参数 headers 的值为这个字典就可以了,如下
headers = {
'user-agent': 'my-app/0.0.1',
'auth-type': 'jwt-token'
}
r = requests.post("http://httpbin.org/post", headers=headers)
print(r.text)
3.构建请求消息体
当我们进行API 接口测试的时候, 根据接口规范,构建的http请求,通常需要构建消息体。
http 的 消息体就是一串字节,里面包含了一些信息。这些信息可能是文本,比如html网页作为消息体,也可能是视频、音频等信息。
消息体可能很短 ,只有一个字节, 比如字符 a。 也可能很长,有几百兆个字节,比如一个视频文件。
最常见的消息体格式当然是 表示网页内容的 HTML。
Web API接口中,消息体基本都是文本,文本的格式主要是这3种: urlencoded ,json , XML。
注意:消息体采用什么格式,是由 开发人员设计的决定的
3.1 xml格式消息体
如果设计者决定用 XML 格式传输一段信息,用Requests库,只需要这样
payload = '''
<?xml version="1.0" encoding="UTF-8"?>
<WorkReport>
<Overall>良好</Overall>
<Progress>30%</Progress>
<Problems>暂无</Problems>
</WorkReport>
'''
r = requests.post("http://httpbin.org/post",
data=payload.encode('utf8'))
print(r.text) #打印响应消息体的文本内容
如果作为系统开发的设计者,觉得发送这样一篇报告,只需要核心信息就可以了,不需要这样麻烦的XML格式,也可以直接用纯文本,像这样
payload = '''
report
Overall:良好
Progress: 30%
Problems:暂无
'''
r = requests.post("http://httpbin.org/post", data=payload.encode('utf8'))
print(r.text)
#data用于存放消息体,headers用于存放消息头 如果传入的参数是字符串类型,那么requests库使用缺省编码latin-1编码为字节串放到http消息体中,发送出去,但是中文是无法使用latin-1编码的,需要使用utf8编码为字节串对象Bytes传入给data参数.
3.2 urlencoded 格式消息体
这种格式的消息体就是一种 键值对的格式存放数据,如下所示
key1=value1&key2=value2
Requests发送这样的数据,当然可以直接把这种格式的字符串传入到data参数里面。
但是,这样写的话,如果参数中本身就有特殊字符,比如等号,就会被看成参数的分隔符,就麻烦了。
我们还有更方便的方法:只需要将这些键值对的数据填入一个字典。
urlpara = {
'wd':'iphone&ipad',
'rsv_spt':'1'
}
response = requests.get('https://www.baidu.com/s',params=urlpara)
#传递给params的参数是放在url中的
#传递给data/json的参数是放在消息体中的
然后使用post方法的时候,指定参数 data 的值为这个字典就可以了,如下
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.post("http://httpbin.org/post", data=payload)
print(r.text)
效果等同于:
r = requests.post("http://httpbin.org/post", data='key1=value1&key2=value2'.encoe('utf8'))
只不过当它里面包含&或者=字符时,就会把他当作分隔符,所以不建议使用这种
requests消息体格式不管是哪种类型,最终都会被编码成字节串
如果requests库发现你所传递的data格式既不是字符串,又不是字节串,而是一个字典格式,那么他会自动将它转化为urlencode格式消息体
#post方法中,data用于存放消息体
3.3 json 格式消息体
json 是一种表示数据的语法格式。 它和Python 表示数据的语法非常像。
比如要表示上面的报告信息,可以这样
{
"Overall":"良好",
"Progress":"30%",
"Problems":[
{
"No" : 1,
"desc": "问题1...."
},
{
"No" : 2,
"desc": "问题2...."
}
]
}
它的优点是:比xml更加简洁、清晰, 所以程序处理起来效率也更高。
我们怎样才能构建一个json 格式的字符串呢?
可以使用json库的dumps方法,如下
import requests,json
payload = {
"Overall":"良好",
"Progress":"30%",
"Problems":[
{
"No" : 1,
"desc": "问题1...."
},
{
"No" : 2,
"desc": "问题2...."
},
]
}
r = requests.post("http://httpbin.org/post", data=json.dumps(payload)) #headers用于存放消息头,data用于存放消息体,json.dumps(payload)将字典对象转换为字符串(json字符串)
json.dumps会默认使用将非ascii码字符(如中文) 进行unicode编码,所以在抓包中看到的中文是一串编码, 如果不希望这样,可以使用json.dumps(payload,ensure_asscii=False)),但是又存在一个问题,requests库data串字符串时,会默认进行latin-1编码, 而中文并不能被latin-1编码,所以使用json.dumps(payload,ensure_asscii=False).encode(utf8)),这样比较麻烦,所以不建议使用这种
如果直接传data = payload, requests库会认为你传递的是一个字典,那么就认为你传的时rulencode消息格式
也可以将 数据对象 直接 传递给post方法的 json参数,如下
r = requests.post("http://httpbin.org/post", json=payload)
#如果requests发现消息体传给json,底层会自动调用json.dumps进行 格式转换
4.检查HTTP响应
4.1检查响应状态码
要检查 HTTP 响应 的状态码,直接 通过 reponse对象的 status_code 属性获取
import requests
response = requests.get('http://mirrors.sohu.com/')
print(response.status_code)
运行结果发现返回的状态码就是 200
如果故意写一个不存在的地址
import requests
response = requests.get('http://mirrors.sohu.com/haaaaaaaaa')
print(response.status_code)
运行结果发现返回的状态码就是 404
4.2检查响应消息头
要检查 HTTP 响应 的消息头,直接 通过 reponse对象的 headers 属性获取
import requests,pprint
response = requests.get('http://mirrors.sohu.com/')
print(type(response.headers))
print(dict(response.headers))#转为dict格式
运行结果如下
<class 'requests.structures.CaseInsensitiveDict'>
{'Cache-Control': 'no-store',
'Connection': 'keep-alive',
'Content-Type': 'text/html; charset=utf8',
'Date': 'Sat, 21 Sep 2019 09:02:32 GMT',
'Server': 'nginx',
'Transfer-Encoding': 'chunked'}
response.headers 对象的类型 是 继承自 Dict 字典 类型的一个 类。
我们也可以像操作字典一样操作它,比如取出一个元素的值
print(response.headers['Content-Type'])
4.3 检查响应消息体
前面我们已经说过,要获取响应的消息体的文本内容,直接通过response对象 的 text 属性即可获取
import requests
response = requests.get('http://mirrors.sohu.com/')
print(response.text)
那么,requests是 以什么编码格式 把HTTP响应消息体中的 字节串 解码 为 字符串的呢?
requests 会根据响应消息头(比如 Content-Type)对编码格式做推测。
但是有时候,服务端并不一定会在消息头中指定编码格式,这时, requests的推测可能有误,需要我们指定编码格式。
可以通过这样的方式指定
import requests
response = requests.get('http://mirrors.sohu.com/')
response.encoding='utf8'
print(response.text)
如果我们要直接获取消息体中的字节串内容,可以使用 content 属性,
比如
import requests
response = requests.get('http://mirrors.sohu.com/')
print(response.content)
当然,如果可以直接对 获取的字节串 bytes对象进行解码
print(response.content.decode('utf8'))
为了 方便处理 响应消息中json 格式的数据 ,我们通常应该把 json 格式的字符串 转化为 python 中的数据对象。
怎么转化? 前面我们学习过 json库,可以直接使用 json库里面的 loads 函数, 把 json 格式的字符串 转化为 数据对象
import requests,json
response = requests.post("http://httpbin.org/post", data={1:1,2:2})
obj = json.loads(response.content.decode('utf8'))
print(obj)
requests库为我们提供了更方便的方法,可以使用 Response对象的 json方法,
如下:
response = requests.post("http://httpbin.org/post", data={1:1,2:2})
obj = response.json()
print(obj)