zoukankan      html  css  js  c++  java
  • 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请求结果:
    {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 请求区别

    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)
    
    

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

  • 相关阅读:
    scrapy中selenium的应用
    Django的锁和事务
    redis
    【leetcode】187. Repeated DNA Sequences
    【leetcode】688. Knight Probability in Chessboard
    【leetcode】576. Out of Boundary Paths
    【leetcode】947. Most Stones Removed with Same Row or Column
    【leetcode】948. Bag of Tokens
    【leetcode】946. Validate Stack Sequences
    【leetcode】945. Minimum Increment to Make Array Unique
  • 原文地址:https://www.cnblogs.com/xiaohuboke/p/13640092.html
Copyright © 2011-2022 走看看