requests库封装

前言

requests是个第三方库,封装了HTTP请求的所有方法,使用方便简单,只需要根据不同的请求方式调用相对应的方法就可以完成发送网络请求的整个过程,那么今天我们就来说说requests库是如何使用的,那么在开始之前我们大致说一下今天的主要内容:

  1. requests如何发送get请求

  2. requests如何发送post请求

  3. params参数和data参数的区别

  4. requests库中Session类的的妙用

  5. 针对get请求和post请求,对requests进行简单封装

GET请求

params

对于这个参数,可以是字典,也可以是嵌套元组的列表,基于get请求的特点,请求参数是可以直接跟在URL之后的,以?号开始以key=value的形式传递(多个参数使用&符号进行分割),但是为了明确区分URL和参数,就需要使用params参数传递.

import requests  # 导入requests模块
response = requests.get('https://www.cnblogs.com/')  # 发送get请求
print(response.text)  # 获取响应数据

响应数据

复制代码
<!DOCTYPE html>
<html lang="zh-cn">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="referrer" content="always" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>博客园 - 开发者的网上家园</title>
    <meta name="keywords"
        content="开发者,程序员,博客园,程序猿,程序媛,极客,码农,编程,代码,软件开发,开源,IT网站,技术社区,Developer,Programmer,Coder,Geek,Coding,Code" />
    <meta name="description"
        content="博客园是一个面向开发者的知识分享社区。自创建以来,博客园一直致力并专注于为开发者打造一个纯净的技术交流社区,推动并帮助开发者通过互联网分享知识,从而让更多开发者从中受益。博客园的使命是帮助开发者用代码改变世界。" />
    <link rel="shortcut icon" href="//common.cnblogs.com/favicon.svg" type="image/svg+xml" />
    <link rel="Stylesheet" type="text/css"
        href="/css/aggsite-new.min.css?v=ovxseaNMgUy6cXIv_fvifewGsazaiVyYWRRwKIyV5IY" />
    <link rel="Stylesheet" type="text/css"
        href="/css/aggsite-mobile-new.min.css?v=v2suEnlPCwax9Hkl1auCodckVHShaihjNC6TbKXbELA"
        media="only screen and (max-width: 767px)" />
    <link id="RSSLink" title="RSS" type="application/rss+xml" rel="alternate"
        href="http://feed.cnblogs.com/blog/sitehome/rss" />
    <script src="//common.cnblogs.com/script/jquery.js" type="text/javascript"></script>
    <script src="/js/aggsite-new.min.js?v=PMJj2v2TjpS1QxVmWxpU20vrjpoMz78PIrD11iNb9yk"></script>
    <script async='async' src='https://www.googletagservices.com/tag/js/gpt.js'></script>
    <script>
        var googletag = googletag || {};
        googletag.cmd = googletag.cmd || [];
    </script>
    <script>
        googletag.cmd.push(function () {
            googletag.defineSlot('/1090369/A1', [300, 60], 'div-gpt-ad-1547816814884-0').addService(googletag.pubads());
            googletag.defineSlot('/1090369/B1', [300, 250], 'div-gpt-ad-1546331539224-0').addService(googletag.pubads());
            googletag.defineSlot('/1090369/B2', [300, 250], 'div-gpt-ad-1539007469525-0').addService(googletag.pubads());
            googletag.defineSlot('/1090369/B3', [300, 250], 'div-gpt-ad-1546331252242-0').addService(googletag.pubads());
            googletag.defineSlot('/1090369/B4', [300, 250], 'div-gpt-ad-1546331385104-0').addService(googletag.pubads());
            googletag.pubads().enableSingleRequest();
            googletag.enableServices();
        });
    </script>
</head>

<body>
    <div id="wrapper" class="flow">
        <div id="top_nav" class="navbar border-none">
            <nav id="nav_main" class="navbar-main">
                <ul id="nav_left" class="navbar-list navbar-left">
                    <li class="navbar-branding">
                        <a href="https://www.cnblogs.com/" title="开发者的网上家园" role="banner">
                            <img src="/images/logo.svg?v=R9M0WmLAIPVydmdzE2keuvnjl-bPR7_35oHqtiBzGsM" alt="博客园Logo" />
                        </a>
                    </li>
                    <li><a href="/">首页</a></li>
                    <li><a href="https://news.cnblogs.com/">新闻</a></li>
                    <li><a href="https://q.cnblogs.com/">博问</a></li>
                    <li><a id="nav_brandzone" href="https://brands.cnblogs.com/huawei">专区</a></li>
                    <li><a href="https://ing.cnblogs.com/">闪存</a></li>
                    <li><a href="https://edu.cnblogs.com/">班级</a></li>
                    <li><a id="nav_legacy" href="/legacy">怀旧</a></li>
                    <li class="dropdown">
                        <div class="dropdown-button">
                            <a href="javascript:void(0)">发现</a>
                            <img src="/images/aggsite/pulldown-light.svg" />
                        </div>
                            <div class="dropdown-menu">
                                <a href="https://home.cnblogs.com/">园子</a>
                                <a href="https://group.cnblogs.com/">小组</a>
                                <a href="https://wz.cnblogs.com/">收藏</a>
                                <a href="https://job.cnblogs.com/">招聘</a>
                                <a href="https://zzk.cnblogs.com/">找找看</a>
                            </div>
                    </li>
                </ul>
                <ul id="nav_right" class="navbar-list navbar-right">
                    <li>
                        <form id="zzk_search" class="navbar-search" action="https://zzk.cnblogs.com/s" method="get"
                            role="search">
                            <input name="w" id="zzk_search_input" placeholder="代码改变世界" type="text" tabindex="3" />
                            <button type="submit" id="zzk_search_button">
                                <img src="/images/aggsite/search.svg" alt="搜索" />
                            </button>
                        </form>
                    </li>......
复制代码

可以看到只需要一行代码即可完成整个请求过程,通过response.text得到响应数据(其实这个过程和我们在浏览器中输入博客园地址访问是一样的),当然你还可以使用以下的方法获取不同的响应数据

response.headers  # 获取响应头信息
response.cookies  # 获取返回的cookie
response.status_code  # 获取状态码

发送带params参数的get请求

import requests

login_url = r'http://***/api/login'  # 接口地址
login_data = {"mobilephone": "12312345783", "pwd": 123456}  # 接口所需参数
response = requests.get(url=login_url, params=login_data)  # 发送get请求
print(response.text)  # 获取响应数据
print(response.url)

响应数据

{"status":1,"code":"10001","data":null,"msg":"登录成功"}
http://***/api/login?mobilephone=12312345783&pwd=123456

我们通过传递一个字典给params参数,即可完成带参数的get请求,并获取响应数据

**注意**

1.我们日常工作中也最好传递字典作为接口数据,如果数据类型是json则在发送请求的时候需要先转成字典

2.只要你发送的是get请求,且不想通过url拼接的方式直接传递接口参数,那么只能使用params参数来传递(如果你使用data,json等参数时你会发现,请求并不会成功),因为通过params传递的参数会附加到url后,这也是get请求的特点,因此你需记住:发送get请求时参数只能使用params即可

以上只是简单的发送get请求的方法,如何发送带其他参数的get请求(比如headers,cookies等)

POST请求

post()和get()一样,仅有一个url参数是必传的,其他仍然可以不传递,但是其中data和json参数却是post()方法中最重要的参数,下面就说一下何时使用data,何时使用json

data

大多数post请求的接口默认支持参数类型Content-Type为application/x-www-form-urlencoded, 它告诉我们请求的接口参数需要传递一个form表单,那么我们往往是通过构造一个字典来传递form表单的,

所以当我们向服务器提交form表单时就可以使用data参数,它会接收一个字典类型的数据,存放到请求体中,然后发送给服务器(参数需是字典类型)

json

首先你访问的接口需要支持content_type为application/json格式的数据类型,那么你就可以通过json这个参数来传递接口参数(参数可以是字典也可以是json类型)

下面我们来看一个发送post请求,使用data参数的实例

import requests

login_url = r'http://***/api/login'  # 接口地址
login_data = {"mobilephone": "12312345783", "pwd": 123456} # 接口所需参数
response = requests.post(url=login_url, data=login_data)  # 发送post请求
print(response.text)  # 获取响应数据
print(response.url)
print(response.status_code)

响应数据

{"status":1,"code":"10001","data":null,"msg":"登录成功"}
http://***:8080/api/login
200

使用json参数实例

import requests

login_url = r'http://***/api/login'  # 接口地址
login_data = {"mobilephone": "12312345783", "pwd": 123456} # 接口所需参数
response = requests.post(url=login_url, json=login_data)  # 发送post请求
print(response.text)  # 获取响应数据
print(response.url)
print(response.status_code)

响应数据

{"status":0,"code":"20103","data":null,"msg":"手机号不能为空"}
http://***/api/login
200

可以看到使用data参数和json参数,获取到的返回结果是不一样的,因为我这里使用的接口不支持application/json数据格式,所以当你使用json参数传递参数时,服务器是无法解析数据的,也就不会返回正确的结果了

所以对于何时使用data参数,何时使用json参数,还需要根据实际的接口所支持的数据类型进行选择

params和data区别

上面已经说过get请求中的params参数和post请求中的data参数,那么这两个参数到底有什么区别呢?

  1. 发送get请求时,由于get请求没有请求体,请求参数只能跟在url地址后的,而且服务器也只能通过解析url获得请求的参数,因此get()方法发送get请求时只能使用params参数,它会把请求的参数默认追加到url地址后面

  2. 通常情况下用户需要提交某些数据时,发送的请求一般都为post请求,post请求会提交一个form表单,那么我们就可以构造一个字典格式的数据,使用data参数传递,由于post请求是有请求体的,而且请求参数就存放在请求体中,服务器也只能通过解析请求体中内容而获得请求的参数,所以post请求不能使用params传递接口参数,只能使用data,json,file等, data参数会把请求参数放到请求体中

Session类的妙用

实际工作中,我们会经常遇到需要保持某一个状态,才能测试后续的接口,比如说:充值接口,那么需要用户先登录,且一直保持登录状态才能进行充值,那么对于这种情况该怎么解决呢?这就要用到requests库中的Session类了,Session可以保持请求的状态,像我们访问某个网站一样,我们只要登录后就可以浏览该网站上的任意页面,先看下面实例

复制代码
import requests

login_url = r'http://***/api/login'  #  登录接口地址
login_data = {"mobilephone": "13691579841", "pwd": 123456} # 接口所需参数
response_login = requests.post(url=login_url, data=login_data)  # 发送post请求 登录
print(response_login.text)
recharge_url = r'http://***/api/recharge'  # 充值接口地址
recharge_data = {"mobilephone": "13691579841", "amount": 10000.00}  # 接口所需参数
response_recharge = requests.post(url=recharge_url, data=recharge_data)  # 发送请求,开始充值
print(response_recharge.text)
复制代码
# 执行结果
{"status":1,"code":"10001","data":null,"msg":"登录成功"}
{"status":0,"code":null,"data":null,"msg":"抱歉,请先登录。"}

可以发现,我们之前都已经登录过了,但是充值时却失败了,原因就是直接使用reauests来发送请求时,并不会保持当前的状态(这也是HTTP请求的缺陷),现在我们使用Session对像再次发送充值请求,修改代码

复制代码
import requests
request = requests.Session()  # 初始化Session
login_url = r'http://***/api/login'  #  登录接口地址
login_data = {"mobilephone": "13691579841", "pwd": 123456} # 接口所需参数
response_login = request.request(method='post', url=login_url, data=login_data)  # 发送post请求 登录
print(response_login.text)
recharge_url = r'http://***/api/recharge'  # 充值接口地址
recharge_data = {"mobilephone": "13691579841", "amount": 10000.00}  # 接口所需参数
response_recharge = request.request(method='post', url=recharge_url, data=recharge_data)  # 发送请求,开始充值
print(response_recharge.text)
复制代码

执行结果

{"status":1,"code":"10001","data":null,"msg":"登录成功"}
{"status":1,"code":"10001","data":{"id":5451,"regname":"test","pwd":"E10ADC3949BA59ABBE56E057F20F883E","mobilephone":"13691579841","leaveamount":"15000.00","type":"1","regtime":"2019-05-26 19:08:44.0"},"msg":"充值成功"}

可以发现,我们改用Session对象来发送充值请求就成功了。那这是什么原因呢?

简单来说,当我们第一次请求服务器时,获取的响应信息会包含一个set-cookie的字段,保存了我们登录的cookies信息,如果我们想保持这个状态,那么再次访问服务器时就需要带上这个cookies传递给服务器,才能保持这个状态。

那么我们使用Session对象发送请求时,Session会自动帮我们完成上述的过程,Session会自动把cookies的信息传递给服务器,而无需我们在请求参数中手动添加cookies,这样就保持了登录的状态,后续的依赖操作都可以正常执行了

reqests简单封装

有人会问,requests库已经封装的很好了,直接用就行了,为啥还要自己封装一次?

第一. 通过封装,我可以直接把所有的请求参数统一使用字典来传递

比如,我们接口请求需要的数据也就是测试数据往往会保存在excel表里面,那么我们取到后是字符串类型,字符串是无法作为请求参数传递的,所以我每次都要做数据转换,再传递给接口,为了节省这个过程,我只需要把这个过程封装到我的requests里即可,每次取数据后自动给我处理

第二. 当我想保持某个状态时,不想每次都初始化一个Session对象,那么我可以把它封装到我的requests里面,以后直接调用即可

下面来看封装的代码

复制代码
import json
import requests
class HttpRequests(object):
    """
    eg: request = HttpRequests()
        response = request(method, url, data)
        or
        response = request.send_request(method, url, data)
        print(response.text)
    """
    def __init__(self):
        self.session = requests.Session()

    def send_request(self, method, url, params_type='form', data=None, **kwargs):
        method = method.upper()
        params_type = params_type.upper()
        if isinstance(data, str):
            try:
                data = json.loads(data)
            except Exception:
                    data = eval(data)
        if 'GET' == method:
            response = self.session.request(method=method, url=url, params=data, **kwargs)
        elif 'POST' == method:
            if params_type == 'FORM':  # 发送表单数据,使用data参数传递
                response = self.session.request(method=method, url=url, data=data, **kwargs)
            elif params_type == 'JSON':  # 如果接口支持application/json类型,则使用json参数传递
                response = self.session.request(method=method, url=url, json=data, **kwargs)
            else:  # 如果接口需要传递其他类型的数据比如 上传文件,调用下面的请求方法
                response = self.session.request(method=method, url=url, **kwargs)
        # 如果请求方式非 get 和post 会报错,当然你也可以继续添加其他的请求方法
        else:
            raise ValueError('request method "{}" error ! please check'.format(method))
        return response

    def __call__(self, method, url, params_type='form', data=None, **kwargs):
        return self.send_request(method, url,
                                 params_type=params_type,
                                 data=data,
                                 **kwargs)
    def close_session(self):
        self.session.close()
        try:
            del self.session.cookies['JSESSIONID']
        except:
            pass
request = HttpRequests()
复制代码

封装测试

现在我们使用封装好的方法来测试一下发送登录和充值接口的请求

复制代码
from sendrequests import request
import unittest
class TestRequests(unittest.TestCase):

    # 登录接口地址
    login_url = r'http://***/futureloan/mvc/api/member/login'
    # 登录接口测试数据
    login_test_value = '{"mobilephone": "13691579841", "pwd": 123456}'

    # 充值接口地址
    recharge_url = r'http://***/futureloan/mvc/api/member/recharge'
    # 充值接口测试数据
    recharge_test_value = {"mobilephone": "13691579841", "amount": 10000.00}

    def test_login_api(self):
        """登录接口测试用例"""
        response = request('get', url=self.login_url, data=self.login_test_value)
        self.assertTrue(response.json()["code"] == "10001")
        print("登录接口测试通过")

    def test_recharge_api(self):
        """充值接口测试用例"""
        response = request('get', url=self.login_url, data=self.login_test_value)
        try:
            # 充值接口需要先登录,才能充值
            self.assertTrue(response.json()["code"] == '10001')
        except AssertionError as e:
            print('登录失败!')
            raise e
        else:
            response = request('post', url=self.recharge_url, data=self.recharge_test_value)
            self.assertTrue(response.json()["code"] == "10001")
            print("充值接口测试通过")

if __name__ == '__main__':
    unittest.main()
复制代码

测试结果

登录接口测试通过
..
充值接口测试通过

总结

最后我们再来总结一下本文涉及到的所有的知识点和你需要掌握的

  1. requests发送get请求和post请求的方法

    get(url, params=None, **kwargs)
    post(url, data=None, json=None, **kwargs)
  2. params参数与data参数的区别
    由于get请求无请求体,post请求有请求体
    使用params参数时,默认会把参数附加到url后面,所以发送get请求时应使用params参数
    使用data参数时,参数会存放到请求体中,所以发送post请求时不能使用params,应使用data,除非接口及支持get又支持post,同样get请求也不能使用data参数
posted @   xaom  阅读(261)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示