前言
- requests 继承了urllib2的所有特性
- requests 支持HTTP连接保持和连接池,支持保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的 URL 和 POST 数据自动编码
- 使用 requests 发送网络请求非常简单
- requests 中文手册
安装
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple
request特性
get & post 请求
import requests
def http_request(method, url, data=None, header=None):
r = requests.request(method=method, url=url, data=data, headers=header)
return r
if __name__ == '__main__':
# get请求
resp1 = http_request('get', 'https://www.wanandroid.com/project/tree/json')
print(f'get请求结果:
{resp1.json()}')
# post请求
data = {'username': 'xiaobai', 'password': '123456'}
resp2 = http_request('post', 'https://www.wanandroid.com/user/login', data=data)
print(f'post请求结果:
{resp2.json()}')
查看响应结果
import requests
def http_request(method, url, data=None, header=None, proxies=None):
r = requests.request(method=method, url=url, data=data, headers=header, proxies=proxies)
return r
if __name__ == '__main__':
# get请求
resp1 = http_request('get', 'https://www.wanandroid.com/project/tree/json')
# 获取json数据(如果响应结果为json格式,否则报错)
print(resp1.json())
# 获取字节流数据,即被编码的进制数据,解码用.decode('utf-8'),如果响应结果中存在图片音视频等文件,且需要获取这些数据,则使用此种获取响应结果的方式
# print(resp1.content)
# 获取Unicode格式的数据,即str数据
# print(resp1.text)
# 查看字符串编码
print(resp1.encoding)
# 查看完整URL
print(resp1.url)
# 查看响应状态码
print(resp1.status_code)
执行结果(json数据太长,只截取部分结果)
get & post 请求区别
- get 请求是从服务器获取数据,在request中,使用params='get_param'传参,源码解释如下
:param params: (optional) Dictionary, list of tuples or bytes to send in the query string for the :class:
Request.
- post 请求是从服务器发送数据,在request中,使用data='post_param'传参,源码解释如下
:param data: (optional) Dictionary, list of tuples, bytes, or file-like object to send in the body of the :class:
Request.
- 其它关于安全性方面的区别这里不作赘述...
代理配置proxies
- 在测试调试过程中,可能需要发送的请求能够被抓取,可以将抓包工具设置为中间代理的方式去实现,request中使用proxies实现:
proxies = {"http": "http://127.0.0.1:8888", "https": "https://127.0.0.1:8888"}
resp1 = http_request('get', 'https://www.wanandroid.com/project/tree/json', proxies=proxies)
print(resp1.status_code)
- 在此测试中,只有启用代理服务器(域名为
http://127.0.0.1:8888
),get请求才能成功(还是调用上一部分http_request()方法)
https请求客户端ssl证书认证问题
- 证书认证是个很麻烦的问题,requesrs默认启用ssl证书认证,verify=True,但很多网站证书不可能一致,则会报
SSLerror
错误,使用verify=False跳过认证即可 - 但认证跳过会仍会告警
InsecureRequestWarning
,未经认证的HTTPS请求,但这个警告并不影响你执行request请求,如需禁用,使用 urllib3 来忽略掉这个警告,如下:
import urllib3
import requests
def http_request(method, url, data=None, header=None, proxies=None, verify=False):
urllib3.disable_warnings() # 忽略浏览器认证警告
r = requests.request(method=method, url=url, data=data, headers=header, proxies=proxies, verify=verify)
return r
if __name__ == '__main__':
resp1 = http_request('get', 'https://www.wanandroid.com/project/tree/json')
print(resp1.status_code)
再次执行
cookies
获取Cookies参数
import requests
r = requests.get("http://www.baidu.com/")
# 返回Cookiejar对象:
cookiejar = r.cookies
# 将CookieJar转为字典:
cookiedict = requests.utils.dict_from_cookiejar(cookiejar)
print(cookiejar)
print(cookiedict)
执行结果
session
- session 是 requests 中非常重要的对象,代表从客户端浏览器连接服务器开始,到客户端浏览器与服务器断开
- 会话能让我们在跨请求时候保持某些参数,比如 cookie,使所有操作都不需要重新获取cookie,比如登录后,使用session会话获取订单,不再需要登录
- 简单示例:
import requests
# 创建session对象
s = requests.session()
r = s.request('get', 'https://www.wanandroid.com/project/tree/json')
print(r.json())
重新封装request
需求
- 需要在调用request时,即保持同一级会话
- 调用request时,可以自动判断get 和 post请求,并作出不同的响应
- 遇到异常可以抛出
- 接口响应超时后,能够自动重运行
- 可以选择代理服务器执行脚本
- 忽略掉证书认证
- 格式化输出json字符串
代码实现
很明显,request库不能实现上述功能,需再次封装,如下:
# File : run_main.py
# IDE : PyCharm
import json
import urllib3
import requests
import warnings
from common.logger import Logger
from requests.adapters import HTTPAdapter
class RunMain:
def __init__(self):
self.logging = Logger().logger
def run_main(self, method, url, data=None, proxies=None, headers=None, timeout=15, max_retries=3):
'''
:param url: tested url
:param data: dict type
:param method: 'get' or 'post'
:param proxies: The result is displayed in fiddler:
{"http": "http://127.0.0.1:8888", "https": "https://127.0.0.1:8888"}
:param timeout: 请求默认超时时间15s
:param max_retries: 请求超时后默认重试3次
'''
s = requests.session()
s.mount('http://', HTTPAdapter(max_retries=max_retries))
s.mount('https://', HTTPAdapter(max_retries=max_retries))
urllib3.disable_warnings() # 忽略浏览器认证警告
warnings.simplefilter('ignore', ResourceWarning) # 忽略 ResourceWarning(https认证)警告
if method.upper() == 'POST':
try:
res = s.request(method='post', url=url, data=data, verify=False, proxies=proxies, headers=headers, timeout=timeout)
except Exception as e:
self.logging.error('POST请求出错,错误信息为:{0}'.format(e))
elif method.upper() == 'GET':
try:
res = s.request(method='get', url=url, params=data, verify=False, proxies=proxies, headers=headers, timeout=timeout)
except Exception as e:
self.logging.error('GET请求出错,错误信息为:{0}'.format(e))
else:
raise ValueError('method方法为get和post')
self.logging.info(f'请求方法:{method},请求路径:{url}, 请求参数:{data}, 请求头:{headers}')
# json.dumps() 将 dict 格式化字符串
# ensure_ascii=False 禁止中文编码为 ascii,indent 缩进,sort_keys 排序
# json.loads() 将 str 转换为 dict
if isinstance(res.text, str):
try:
json_data = json.loads(res.text)
finally_data = json.dumps(json_data, ensure_ascii=False, indent=2, sort_keys=True)
except ValueError as e:
self.logging.error('数据类型错误,错误信息为:{0}'.format(e))
raise e
else:
finally_data = res.text
return finally_data
if __name__ == '__main__':
method = 'get'
url = 'https://www.wanandroid.com//hotkey/json'
response = RunMain().run_main(method, url)
print(response)
执行结果(截取部分,可以自己运行脚本)