interface--requests封装

前言

  1. requests 继承了urllib2的所有特性
  2. requests 支持HTTP连接保持和连接池,支持保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的 URL 和 POST 数据自动编码
  3. 使用 requests 发送网络请求非常简单
  4. 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请求结果:\n{resp1.json()}')

    # post请求
    data = {'username': 'xiaobai', 'password': '123456'}
    resp2 = http_request('post', 'https://www.wanandroid.com/user/login', data=data)
    print(f'post请求结果:\n{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 请求区别

  1. get 请求是从服务器获取数据,在request中,使用params='get_param'传参,源码解释如下
    :param params: (optional) Dictionary, list of tuples or bytes to send in the query string for the :class:Request.
  2. 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.
  3. 其它关于安全性方面的区别这里不作赘述...

代理配置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证书认证问题

  1. 证书认证是个很麻烦的问题,requesrs默认启用ssl证书认证,verify=True,但很多网站证书不可能一致,则会报SSLerror错误,使用verify=False跳过认证即可
  2. 但认证跳过会仍会告警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

  1. session 是 requests 中非常重要的对象,代表从客户端浏览器连接服务器开始,到客户端浏览器与服务器断开
  2. 会话能让我们在跨请求时候保持某些参数,比如 cookie,使所有操作都不需要重新获取cookie,比如登录后,使用session会话获取订单,不再需要登录
  3. 简单示例:
import requests

# 创建session对象
s = requests.session()
r = s.request('get', 'https://www.wanandroid.com/project/tree/json')
print(r.json())

重新封装request

需求

  1. 需要在调用request时,即保持同一级会话
  2. 调用request时,可以自动判断get 和 post请求,并作出不同的响应
  3. 遇到异常可以抛出
  4. 接口响应超时后,能够自动重运行
  5. 可以选择代理服务器执行脚本
  6. 忽略掉证书认证
  7. 格式化输出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)

执行结果(截取部分,可以自己运行脚本)

posted @ 2020-09-09 17:21  子非鱼焉知鱼之乐丶  阅读(413)  评论(0编辑  收藏  举报