Python接口测试之Requests


Requests简介

Requests介绍

Requests是Python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库。相较于urlib更加方便易用。Request支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动响应内容的编码,支持国际化的URL和POST数据自动编码。在python内置模块的基础上进行了高度的封装,从而使得python进行网络请求时,变得人性化。

Requests的官方地址为:https://cn.python-requests.org/zh_CN/latest/

Requests安装

$ pip install requests

基础使用

简单例子

测试通过requests库访问百度首页

import requests

r = requests.get('http://httpbin.org/ip')

print(r)

执行结果:

<Response [200]>

Response对象的常用属性

属性或方法 描述
r.status_code 响应状态码
r.encoding response对象的编码
r.text 把response对象转换为字符串数据
r.content 把response对象转换成二进制数据
r.json() 通过JSON解码器转换response对象数据
r.url 获取请求网址
r.cookie 获取请求后的cookie
r.headers 以字典对象存储服务器响应头

演示代码:

import requests

r = requests.get('http://httpbin.org/ip')

print(r)
print(r.status_code)
print(r.encoding)
print(r.content)
print(r.text)
print(r.json())
print(r.headers)
print(r.url)
print(r.cookies)

执行结果:

<Response [200]>
200
utf-8
b'{\n  "origin": "24.65.47.34"\n}\n'
{
  "origin": "24.65.47.34"
}

{'origin': '24.65.47.34'}
{'Date': 'Tue, 03 Jan 2023 08:17:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '33', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'}
http://httpbin.org/ip
<RequestsCookieJar[]>

Requests库常用请求方法

方法 描述
requests.session() 创建一个会话,会话能让在跨请求的时候保持某些参数,比如在同一个session实例发出的所有请求之间保持cookie信息
requests.request() 构造一个请求,支持以下的各种方法
requests.get() 发送一个get请求,获取HTML网页的主要方法,对应HTTP的GET
requests.post() 发送一个post请求,向HTML网页提交POST请求的方法,对应HTTP的POST
requests.head() 发送一个head请求,获取HTML头信息的方法,对应HTTP的HEAD
requests.put() 发送一个put请求,向HTML网页提交PUT请求的方法,对应HTTP的PUT
requests.patch() 发送一个patch请求,向HTML网页提交局部修改请求,对应HTTP的PATCH
requests.delete() 发送一个delete请求,向HTML网页提交删除请求,对应HTTP的DELETE
requests.options() 发送一个options请求,向HTML网页获取服务器支持的HTTP请求方法,对应HTTP的OPTIONS

其中,requests.get()requests.post()requests.request()requests.session()最常用

requests.get()

requests的api.py源代码

def get(url, params=None, **kwargs):
    r"""Sends a GET request.

    :param url: URL for the new :class:`Request` object.
    :param params: (optional) Dictionary, list of tuples or bytes to send
        in the query string for the :class:`Request`.
    :param \*\*kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

    return request("get", url, params=params, **kwargs)

requests.get()的基本语法是:

get(url, params=None, **kwargs)

其中:

  • url:(必填参数)请求的URL地址;
  • params:(可选参数)字典或元组列表或字节,作为参数增加到url中;
  • **kwargs:其他的可选参数,可参考【requests.request()】中的**kwargs

示例网站:https://httpbin.org

示例1:

import requests

r = requests.get('https://httpbin.org/ip')

print(r)
print(r.status_code)
print(r.encoding)
print(r.content)
print(r.text)
print(r.json())
print(r.headers)
print(r.url)
print(r.cookies)

执行结果:

<Response [200]>
200
utf-8
b'{\n  "origin": "64.65.47.34"\n}\n'
{
  "origin": "64.65.47.34"
}

{'origin': '124.65.147.234'}
{'Date': 'Wed, 04 Jan 2023 07:28:15 GMT', 'Content-Type': 'application/json', 'Content-Length': '33', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'}
https://httpbin.org/ip
<RequestsCookieJar[]>

示例2:(含有params参数时)

import requests

r = requests.get('https://httpbin.org/get', params={'name': 'laobai', 'age': 18})

print(r.json())

执行结果:

{'args': {'age': '18', 'name': 'laobai'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.28.1', 'X-Amzn-Trace-Id': 'Root=1-63b52b16-0b6f50d7668fa5ab52669f76'}, 'origin': '124.65.147.234', 'url': 'https://httpbin.org/get?name=laobai&age=18'}

requests.post()

requests的api.py源代码

def post(url, data=None, json=None, **kwargs):
    r"""Sends a POST request.

    :param url: URL for the new :class:`Request` object.
    :param data: (optional) Dictionary, list of tuples, bytes, or file-like
        object to send in the body of the :class:`Request`.
    :param json: (optional) json data to send in the body of the :class:`Request`.
    :param \*\*kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

    return request("post", url, data=data, json=json, **kwargs)

requests.post()的基本语法是:

post(url, data=None, json=None, **kwargs)

其中:

  • url:(必填参数)请求的URL地址;
  • data=None:(可选参数)字典,元组列表,字节或文件对象,作为post请求的参数。(content_typeapplication/x-www-form-urlencode键值对的编码格式);
  • json=None:(可选参数)JSON格式的数据,作为post请求的json参数。(content_typeapplication/json)(使用json接收会自动将字典转换为json;也可以用data接收json格式的数据,data=json.dump(字典格式的数据));
  • **kwargs:其他的可选参数,可参考【requests.request()】中的**kwargs

传递参数是用data还是json,需要根据Content-Type的类型来判断

Content-Type是服务器要求传入的报文的内容类型:

  • Content-Type:application/json 用json接收
  • Content-Type:application-www-form-urlencoded 用data接收
  • Content-Type:text/plain 用data接收

示例网站:http://101.43.8.10:6969/(likeshop商城)

示例1:登录接口( http://www.likeshop.cn/doc/2/173

import requests

url1 = 'http://101.43.8.10:6969/api/account/login'

data1 = {
    'account': '17900000001',
    'password': 'a123456',
    'client': 2
}

r1 = requests.post(url=url1, data=data1)

print(r1.json())

执行结果:

{'code': 1, 'msg': '登录成功', 'data': {'id': 1, 'nickname': '测试账号一', 'avatar': 'http://101.43.8.10:6969/static/common/image/default/user.png', 'level': 1, 'disable': 0, 'distribution_code': 'TVHYKM', 'token': '7a81e50075f4afb54eef89c6d0c29e8e'}, 'show': 0, 'time': '0.100006'}

从登录接口的执行接口可以看到生成了token

示例2:个人中心接口( http://www.likeshop.cn/doc/2/287

import requests

url2 = 'http://101.43.8.10:6969/api/user/center'

r2 = requests.post(url=url2)

print(r2.json())

执行结果:

{'code': -1, 'msg': 'token不能为空', 'data': [], 'show': 1, 'time': '0.042536'}

这里提示缺少token,需要在发送请求时,在headers中增加token参数

import requests

url1 = 'http://101.43.8.10:6969/api/account/login'

data1 = {
    'account': '17900000001',
    'password': 'a123456',
    'client': 2
}

r1 = requests.post(url=url1, data=data1)


url2 = 'http://101.43.8.10:6969/api/user/center'
headers = {
    'token': r1.json()['data']['token']
}

r2 = requests.post(url=url2, headers=headers)

print(r2.json())

再次执行:

{'code': 1, 'msg': '获取成功', 'data': {'id': 1, 'sn': '61853905', 'nickname': '测试账号一', 'avatar': 'http://101.43.8.10:6969/static/common/image/default/user.png', 'mobile': '17900000001', 'level': '普通会员', 'user_money': '9960.20', 'user_integral': 1020, 'total_order_amount': '39.80', 'total_recharge_amount': '0.00', 'distribution_code': 'TVHYKM', 'wait_pay': 0, 'wait_delivery': 1, 'wait_take': 0, 'wait_comment': 0, 'after_sale': 0, 'coupon': 0, 'distribution_setting': 1, 'notice_num': 1, 'next_level_tips': '距离升级还差999', 'hasPayPassword': 0}, 'show': 0, 'time': '0.078589'}

requests.request()

requests的api.py源代码

def request(method, url, **kwargs):
    """Constructs and sends a :class:`Request <Request>`.

    :param method: method for the new :class:`Request` object: ``GET``, ``OPTIONS``, ``HEAD``, ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
    :param url: URL for the new :class:`Request` object.
    :param params: (optional) Dictionary, list of tuples or bytes to send
        in the query string for the :class:`Request`.
    :param data: (optional) Dictionary, list of tuples, bytes, or file-like
        object to send in the body of the :class:`Request`.
    :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
    :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
    :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
    :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload.
        ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')``
        or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string
        defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers
        to add for the file.
    :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
    :param timeout: (optional) How many seconds to wait for the server to send data
        before giving up, as a float, or a :ref:`(connect timeout, read
        timeout) <timeouts>` tuple.
    :type timeout: float or tuple
    :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``.
    :type allow_redirects: bool
    :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
    :param verify: (optional) Either a boolean, in which case it controls whether we verify
            the server's TLS certificate, or a string, in which case it must be a path
            to a CA bundle to use. Defaults to ``True``.
    :param stream: (optional) if ``False``, the response content will be immediately downloaded.
    :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response

    Usage::

      >>> import requests
      >>> req = requests.request('GET', 'https://httpbin.org/get')
      >>> req
      <Response [200]>
    """

    # By using the 'with' statement we are sure the session is closed, thus we
    # avoid leaving sockets open which can trigger a ResourceWarning in some
    # cases, and look like a memory leak in others.
    with sessions.Session() as session:
        return session.request(method=method, url=url, **kwargs)

requests.request()的基本语法是:

requests.request(method,url,**kwargs)

其中:

  • method:(必填参数) GETPOSTHEADPUTDELETEPATCHOPTIONS;
  • url:(必填参数)请求的URL地址;
  • **kwargs:(可选参数)是一个可变的参数类型,在传实参时,以关键字参数的形式传入,python会自动解析成字典的形式;
    • params:字典或元组列表或字节,作为参数增加到url中;一般用于get请求,post请求也可用(不常用);
    • data:字典,元组列表,字节或文件对象,作为post请求的参数。(content_typeapplication/x-www-form-urlencode键值对的编码格式);
    • json:JSON格式的数据,作为post请求的json参数。(content_typeapplication/json)(使用json接收会自动将字典转换为json;也可以用data接收json格式的数据,data=json.dump(字典格式的数据));
    • headers:字典类型, HTTP请求头信息;
    • cookies:字典或CookieJar,Request中的auth : 元组支持HTTP认证功能;
    • files:字典类型,传输文件,作为post请求文件流数据;
    • timeout:设定超时时间,秒为单位;
    • proxies:字典类型,设定访问代理服务器,可以增加登录认证;
    • allow_redirects:True/False,默认为True,重定向开关;
    • stream:True/False,默认为True,获取内容立即下载开关;
    • verify:True/False,默认为True,认证SSL证书开关。当verify为True时, 如果想解析https内容,需在Cert参数中添加证书路径;
    • cert:本地SSL证书的路径;
    • auth:元组,支持HTTP认证功能(“证书、密钥”对);
requests.request(method,url,params=None,data=None,headers=None,cookies=None,
                 files=None,auth=None,timeout=None,allow_redirects=True,
                 proxies=None,hooks=None,stream=None,verify=None,cert=None,json=None)

示例:

import requests

url = 'http://101.43.8.10:6969/api/account/login'

data = {
    'account': '17900000001',
    'password': 'a123456',
    'client': 2
}

res = requests.request('post', url=url, data=data)

print(res.json())

执行结果:

{'code': 1, 'msg': '登录成功', 'data': {'id': 1, 'nickname': '测试账号一', 'avatar': 'http://101.43.8.10:6969/static/common/image/default/user.png', 'level': 1, 'disable': 0, 'distribution_code': 'TVHYKM', 'token': '9dc861b841c7abab6068dd2f6393bd45'}, 'show': 0, 'time': '0.100812'}

requests.session()

requests的sessions.py源代码

def request(self, method, url,
            params=None, data=None, headers=None, cookies=None, files=None,
            auth=None, timeout=None, allow_redirects=True, proxies=None,
            hooks=None, stream=None, verify=None, cert=None, json=None):
        """Constructs a :class:`Request <Request>`, prepares it and sends it.
        Returns :class:`Response <Response>` object.

        :param method: method for the new :class:`Request` object.
        :param url: URL for the new :class:`Request` object.
        :param params: (optional) Dictionary or bytes to be sent in the query
            string for the :class:`Request`.
        :param data: (optional) Dictionary, list of tuples, bytes, or file-like
            object to send in the body of the :class:`Request`.
        :param json: (optional) json to send in the body of the
            :class:`Request`.
        :param headers: (optional) Dictionary of HTTP Headers to send with the
            :class:`Request`.
        :param cookies: (optional) Dict or CookieJar object to send with the
            :class:`Request`.
        :param files: (optional) Dictionary of ``'filename': file-like-objects``
            for multipart encoding upload.
        :param auth: (optional) Auth tuple or callable to enable
            Basic/Digest/Custom HTTP Auth.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple
        :param allow_redirects: (optional) Set to True by default.
        :type allow_redirects: bool
        :param proxies: (optional) Dictionary mapping protocol or protocol and
            hostname to the URL of the proxy.
        :param stream: (optional) whether to immediately download the response
            content. Defaults to ``False``.
        :param verify: (optional) Either a boolean, in which case it controls whether we verify
            the server's TLS certificate, or a string, in which case it must be a path
            to a CA bundle to use. Defaults to ``True``. When set to
            ``False``, requests will accept any TLS certificate presented by
            the server, and will ignore hostname mismatches and/or expired
            certificates, which will make your application vulnerable to
            man-in-the-middle (MitM) attacks. Setting verify to ``False`` 
            may be useful during local development or testing.
        :param cert: (optional) if String, path to ssl client cert file (.pem).
            If Tuple, ('cert', 'key') pair.
        :rtype: requests.Response
        """
        # Create the Request.
        req = Request(
            method=method.upper(),
            url=url,
            headers=headers,
            files=files,
            data=data or {},
            json=json,
            params=params or {},
            auth=auth,
            cookies=cookies,
            hooks=hooks,
        )
        prep = self.prepare_request(req)

        proxies = proxies or {}

        settings = self.merge_environment_settings(
            prep.url, proxies, stream, verify, cert
        )

        # Send the request.
        send_kwargs = {
            'timeout': timeout,
            'allow_redirects': allow_redirects,
        }
        send_kwargs.update(settings)
        resp = self.send(prep, **send_kwargs)

        return resp

requests.session()的基本语法是:

session = requests.session()
session.request(method, url, **kwargs)

首先,实例化session会话对象

其次:

  • method:(必填参数) GETPOSTHEADPUTDELETEPATCHOPTIONS;

  • url:(必填参数)请求的URL地址;

  • **kwargs:(可选参数)是一个可变的参数类型,在传实参时,以关键字参数的形式传入,python会自动解析成字典的形式;

    (可选参数,可参考【requests.request()】中的**kwargs

示例:

这里使用 http://101.43.8.10:6996/ ( ShopXO商城 )

登录接口地址:https://doc.shopxo.net/article/2/336656718643593216.html

我的积分列表接口地址:https://doc.shopxo.net/article/2/288212974584201216.html

若不使用session,实现代码如下:

import requests

url1 = 'http://101.43.8.10:6996/api.php/user/login'

data1 = {
    'accounts': 'laobai',
    'pwd': 'laobai123',
    'type': 'username'
}

url2 = 'http://101.43.8.10:6996/api.php/userintegral/index'
data2 = {
    'page': 1
}

r1 = requests.post(url=url1, data=data1)
r2 = requests.post(url=url2, data=data2, cookies=r1.cookies)

print(r1.json())
print(r2.json())

执行结果:

{'msg': '登录成功', 'code': 0, 'data': {'body_html': ''}}
{'msg': 'success', 'code': 0, 'data': {'total': 0, 'page_total': 0, 'data': []}}

请求我的积分列表接口时,需要增加cookies参数

若使用session进行请求:

import requests

url1 = 'http://101.43.8.10:6996/api.php/user/login'

data1 = {
    'accounts': 'laobai',
    'pwd': 'laobai123',
    'type': 'username'
}

url2 = 'http://101.43.8.10:6996/api.php/userintegral/index'
data2 = {
    'page': 1
}

session = requests.session()
r1 = session.post(url1, data1)
r2 = session.post(url2, data2)

print(r1.json())
print(r2.json())

执行结果:

{'msg': '登录成功', 'code': 0, 'data': {'body_html': ''}}
{'msg': 'success', 'code': 0, 'data': {'total': 0, 'page_total': 0, 'data': []}}

可以看到我的积分列表接口可以正确的获取接口返回值,即不必传cookies参数,通过session即可携带登录cookies

requests.session()只对cookies中记录登录状态的有效,若使用token则无效,还是需要传token

import requests

url1 = 'http://101.43.8.10:6969/api/account/login'

data1 = {
    'account': '17900000001',
    'password': 'a123456',
    'client': 2
}

session = requests.session()
res1 = session.post(url=url1, data=data1)

url2 = 'http://101.43.8.10:6969/api/user/center'

res2 = session.post(url=url2)

print(res2.json())

执行结果:

{'code': -1, 'msg': 'token不能为空', 'data': [], 'show': 1, 'time': '0.042134'}

Requests封装

上面的例子中,requestsget请求、post请求等,都是分别请求的,若测试用例较多时,会有大量的代码冗余,并且在后续的代码异常处理、日志、断言等功能的扩充,代码冗余会更加严重。

在上面的章节中,requests请求可以通过requests.get/requests.post/requests.request等请求形式进行请求,也可以使用requests.session进行请求。接下来将会采用requests.session来学习之后的内容。session对象可以自动的关联cookies,这在WEB类型的项目会很方便。

PLRequests.py

import requests


class PLRequests:
    # 只要调用这个类,就会进入到init这个函数里面去
    def __init__(self):
        # 定义session对象
        self.session = requests.session()

    # 封装请求,这里只对GET、POST、PUT、DELETE四种请求方法做处理
    def pl_request(self, method, url, **kwargs):
        # 将接受到的method的值统一转为大写字母
        method = method.upper()

        if 'GET' == method:
            resp = self.session.request(method=method, url=url, **kwargs)
        elif 'POST' == method:
            resp = self.session.request(method=method, url=url, **kwargs)
        elif 'PUT' == method:
            resp = self.session.request(method=method, url=url, **kwargs)
        elif 'DELETE' == method:
            resp = self.session.request(method=method, url=url, **kwargs)
        else:
            raise "请求方法错误"
        return resp

    # 关闭session对象
    def close_session(self):
        self.session.close()

改写调用程序如下:

# 导入封装好的LBRequests类,此时就不需要导入requests了
from common.PLRequests import PLRequests

# 实例化LBRequests对象
PLRequests = PLRequests()

url = 'http://101.43.8.10:6996/api.php/user/login'
data = {
    'accounts': 'laobai',
    'pwd': 'laobai123',
    'type': 'username'
}

r = PLRequests.pl_request(method='post', url=url, data=data)
print(r.json())
print(r.url)
print(r.cookies)

执行结果:

{'msg': '登录成功', 'code': 0, 'data': {'body_html': ''}}
http://101.43.8.10/api.php/user/login
<RequestsCookieJar[<Cookie PHPSESSID=08d0442ada4631c6a245d87d56b8b9b2 for 101.43.8.10/>, <Cookie user_login_info=e991MrdJ7Kb%252FrOPAuOH8H8g5hH1rwgdh1ip5Vn3d%252F3DuxiCaglqrMTFYLkFYIUw%252FInQQX2H4v7KFoaZ0pJ8d52vxccKIyhPgWm16uEsLQ3NruB6MOZQ8SEoT9QKb92ePv8HNi%252FYS%252B%252BfIEFn3c5WzLGXUFAcAvd0gApumVgT1nFqBqxiwzJ%252B11aD7KrQWjIhYdgEBL9iYbCedojBssgjN1l4%252FhluyeZe0PXgP0M5GayLN53%252BTMCVCMO0bSe5EP04CmJFM9bx4xM2SdnYk9PFk7AG%252BtveorBfEwovzOYroc0fbXRQ0wYJ6tA48lF5w4uF4uTYIBd6wUi7QjJMxZTjtzA8T9NlcofXKUrQYpyqWkBwKJFRGKWD8%252F8Ufm6fDpYoWFPUQmi6WzDrnPk0wI8kY2JyUcvj0D29inV3YrWju0Ulo9obFYDpAJXv43UAzTpscngS%252FyVAClfFKvdjXOqODVbckZjJYw8x9fxSuivce3SSC5UWa2u%252BbBo8yfbt%252BtzJk%252BilGF0bxBlBsnaMM9XOXN3qr6MGpbH7LHcEQK3S9EVecVGlhTf5AMVoyyMuqAvXkO3wAZM2hMRp9%252FdeVgQCBihIxMLVuJyfs6ICcxWThh0cabtnxfRk5ivwaULT2nwXcdVR4DMcsR41zxWMflwq1lTWZi4cPvvUxK29zcajseU%252FkX%252BpDdY%252BdpPwwXqmKzutT7ZJ%252FGflWs2xdSWhqID6lGktc5XzApNJZ4%252BZmJ7UyGxm1JKhwHt13gct8DndQeGF318vRBmhPYI3786pefSx4CUcQaO0ItcpTvR%252FREwoaiK6T5gHk4yyuWQbTzvYaYfzdE992REtKuVyDhK8Y%252B2W8pzuNjTUmIIxsvV03iJ2gXdnX8N0OajPbU4POgZPTfiBWizjYcKtb6fpfiLO7r19FgL0mi5KO0BKFwoPx8gtEtkKziFe24blksRjg9d0DLDyan9%252FGssl6KcvL6xXoqvKmBZYGMGuSqq%252B2A3V7ULTyT6ZQc5%252FykI5EfauoEgs2BBAZGsG2lETiY1rmBr9yxPXgIC54I9ugiycHaAjouC16Zf3dOP4ZMmccielPFvWnQ%252FjlYVYz7fALgnUrojGb4719rwRVNmvlqlgU2cWUQSp0LstFAK2e5umQeUoS%252Bx4mF3Dau508WPJEWLTIKuEQxYpeynv9tcng0sar8nPRrmqwjQse%252FIlGqGM2B%252FyV5P1v47r0GD7yGRLVXuvGBpc0I5R%252BulIbg85SnK1PHVqeAigYrwd4UthigLWjFzAM9FHxAdwkS6Z4WRiy2%252FgdL%252BPsRcBSENghPFcb%252B9ouDB3ZWp9wd9U%252F2uQF1ifU3WCdGO0VBpA4CLOK0ylS31xFfisqv3ZS05p%252BDZfnWKekP0bWUmC546BqLv7j41noKn5u%252B0KvoTagJpQ%252BFnDkPI%252B31fljSbq8ld6lZtNcwKZRoQ for 101.43.8.10/>, <Cookie uuid=749bc766-39c0-9ba5-cc2e-294b0c235044 for 101.43.8.10/>]>

requests的api.py源代码中如下:

def request(method, url, **kwargs):

    with sessions.Session() as session:
        return session.request(method=method, url=url, **kwargs)

可以看到,每次执行request都会新建一个session,多次调用会生成多个session,所以多个request请求是没有cookies关联的。

实例

项目:likeshop商城

网址:http://101.43.8.10:6969/ (H5版)

1、登录接口:

2、商品详情接口:

3、添加到购物车接口:

4、生成订单接口:

5、订单详情接口:

代码实现:

from common.PLRequests import PLRequests

PLRequests = PLRequests()

"""
1、登录接口:
- 接口文档:http://www.likeshop.cn/doc/2/173
- 登录接口:http://101.43.8.10:6969/api/account/login
"""
url1 = 'http://101.43.8.10:6969/api/account/login'
data1 = {
    'account': '17900000001',
    'password': 'a123456',
    'client': 2
}

res1 = PLRequests.pl_request(method='post', url=url1, data=data1)
print(res1.json())


"""
2、商品详情接口:
- 接口文档:http://www.likeshop.cn/doc/2/209
- 登录接口:http://101.43.8.10:6969/api/goods/getGoodsDetail
"""
url2 = 'http://101.43.8.10:6969/api/goods/getGoodsDetail'
params = {
    'id': 4
}

res2 = PLRequests.pl_request(method='get', url=url2, params=params)
print(res2.json())


"""
3、添加到购物车接口:

- 接口文档:http://www.likeshop.cn/doc/2/183
- 登录接口:http://101.43.8.10:6969/api/cart/add
"""
url3 = 'http://101.43.8.10:6969/api/cart/add'
data3 = {
    'item_id': 1,
    'goods_num': 1
}
headers = {
    'token': res1.json()['data']['token']
}
res3 = PLRequests.pl_request(method='post', url=url3, data=data3, headers=headers)
print(res3.json())


"""
4、生成订单接口:
- 接口文档:http://www.likeshop.cn/doc/2/272
- 登录接口:http://101.43.8.10:6969/api/order/buy
"""
url4 = 'http://101.43.8.10:6969/api/order/buy'
json = {
    "action": "submit",
    "goods": [{
        "item_id": 1,
        "num": 1
    }],
    "pay_way": 3,
    "use_integral": 0,
    "type": "cart"
}

res4 = PLRequests.pl_request(method='post', url=url4, json=json, headers=headers)
print(res4.json())


"""
5、订单详情接口:

- 接口文档:http://www.likeshop.cn/doc/2/273
- 登录接口:http://101.43.8.10:6969/api/order/detail
"""
url5 = 'http://101.43.8.10:6969/api/order/detail'
params5 = {
    "id": res4.json()['data']['order_id']
}

res5 = PLRequests.pl_request(method='get', url=url5, params=params5, headers=headers)
print(res5.json())

执行结果:

{'code': 1, 'msg': '登录成功', 'data': {'id': 1, 'nickname': '测试账号一', 'avatar': 'http://101.43.8.10:6969/static/common/image/default/user.png', 'level': 1, 'disable': 0, 'distribution_code': 'TVHYKM', 'token': '5754a539eea7c2cd5ca12dc8639bdc23'}, 'show': 0, 'time': '0.093337'}
{'code': 1, 'msg': '获取成功', 'data': {'id': 4, 'name': '晨光文具可削铅笔 六角2B 红黑抽条 木杆铅笔 儿童铅笔 AWP30804', 'image': 'http://101.43.8.10:6969/uploads/images/background/20201210/4b06036c7e6c8f653a51fd94d4cb5bc5.png', 'video': None, 'remark': '好用', 'content': '<div id="attributes" class="attributes"><div class="attributes-list" id="J_AttrList"><div class="tm-clear tb-hidden tm_brandAttr" id="J_BrandAttr"><div class="name" data-spm-anchor-id="a220o.1000855.0.i3.26c46d7d371Jfl">品牌名称:<span class="J_EbrandLogo" target="_blank" href="//brand.tmall.com/brandInfo.htm?brandId=105529784&amp;type=0&amp;scm=1048.1.1.4">M&G/晨光</span></div></div><p class="attr-list-hd tm-clear"><span>产品参数:</span></p><ul id="J_AttrUL"><li title="M&G/晨光 AWP30804">产品名称:M&G/晨光 AWP30804</li><li id="J_attrBrandName" title="&nbsp;M&G/晨光">品牌:&nbsp;M&G/晨光</li><li title="&nbsp;AWP30804">晨光型号:&nbsp;AWP30804</li><li title="&nbsp;2B 六角 10支装">颜色分类:&nbsp;2B 六角 10支装</li><li title="&nbsp;石墨/普通铅笔">笔类型:&nbsp;石墨/普通铅笔</li><li title="&nbsp;上海晨光文具股份有限公司">生产企业:&nbsp;上海晨光文具股份有限公司</li><li title="&nbsp;2B">笔芯硬度:&nbsp;2B</li><li title="&nbsp;书写">适用场景:&nbsp;书写</li><li title="&nbsp;10支">支数:&nbsp;10支</li><li title="&nbsp;单色">颜色数:&nbsp;单色</li><li title="&nbsp;棕榈树">笔杆材质:&nbsp;棕榈树</li><li title="&nbsp;gb国标标准">安全标准:&nbsp;gb国标标准</li><li title="&nbsp;是">是否带橡皮头:&nbsp;是</li></ul></div></div><div id="mall-banner"><div data-spm="1998132255"></div><div id="J_DescTMS1"></div></div><div id="J_TmpActBanner"></div><div id="J_DcTopRightWrap"><div id="J_DcTopRight" class="J_DcAsyn tb-shop"><div class="J_TModule" data-widgetid="23276204330" id="shop23276204330" data-componentid="5003" data-spm="110.0.5003-23276204330" microscope-data="5003-23276204330" data-title="自定义内容区"><div class="skin-box tb-module tshop-pbsm tshop-pbsm-shop-self-defined"><s class="skin-box-tp"><b></b></s><div class="skin-box-bd clear-fix"><div class="rel" data-title="power by junezx 3.0" data-rn="alnjH"><a class="jsib abs a0Auo-VfMx" data-linkmode="ptlink" data-appid="a0Auo-VfMx"></a><a class="jdb abs a0Auo-weZe" href="https://detail.tmall.com/item.htm?id=627740950878&amp;scene=taobao_shop" target="_blank" data-linkmode="ptlink" data-appid="a0Auo-weZe"></a><a class="jdb abs a0Auo-d9p7" href="https://detail.tmall.com/item.htm?id=631257030944&amp;scene=taobao_shop" target="_blank" data-linkmode="ptlink" data-appid="a0Auo-d9p7"></a><a class="jdb abs a0Auo-95xd" href="https://detail.tmall.com/item.htm?id=600754691350&amp;scene=taobao_shop" target="_blank" data-linkmode="ptlink" data-appid="a0Auo-95xd"></a><a class="jdb abs a0Auo-rTvT" href="https://detail.tmall.com/item.htm?id=591204959642&amp;scene=taobao_shop" target="_blank" data-linkmode="ptlink" data-appid="a0Auo-rTvT"></a><a class="jdb abs a0Auo-Suog" href="https://detail.tmall.com/item.htm?id=611893635921&amp;scene=taobao_shop" target="_blank" data-linkmode="ptlink" data-appid="a0Auo-Suog"></a><a class="jdb abs a0Auo-nrwW" href="https://detail.tmall.com/item.htm?id=571300231971&amp;scene=taobao_shop" target="_blank" data-linkmode="ptlink" data-appid="a0Auo-nrwW"></a></div></div><s class="skin-box-bt"><b></b></s></div></div></div></div><div id="description" class="J_DetailSection tshop-psm tshop-psm-bdetaildes"><div class="content ke-post"><p><img align="absmiddle" src="https://img.alicdn.com/imgextra/i3/682114580/TB2ceIhcW8lpuFjy0FpXXaGrpXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i3/682114580/TB2m0QbcYtlpuFjSspoXXbcDpXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i1/682114580/TB2M.v5c4XlpuFjSsphXXbJOXXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i4/682114580/TB22C7fc80kpuFjSsppXXcGTXXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i2/682114580/TB2oq.fcYVkpuFjSspcXXbSMVXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i3/682114580/TB2K6z6c4XkpuFjy0FiXXbUfFXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i4/682114580/TB2OGIcc90jpuFjy0FlXXc0bpXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i1/682114580/TB29Sn3cYBkpuFjy1zkXXbSpFXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i2/682114580/TB2dOQpc9FjpuFjSszhXXaBuVXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i4/682114580/TB2FkYVc3JkpuFjSszcXXXfsFXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i4/682114580/TB221ZkcYFkpuFjy1XcXXclapXa_!!682114580.jpg" class="img-ks-lazyload"><img align="absmiddle" src="https://img.alicdn.com/imgextra/i3/682114580/TB2pO_7cY0kpuFjy0FjXXcBbVXa_!!682114580.jpg" class="img-ks-lazyload"></p><div><a name="maijsoft_s1_191268_start"></a></div><p>温馨提示:商品外盒或塑封仅作为包装材料使用,在快递运输过程中可能出现不同程度的变形或损坏,均为正常现象,不作为售后理由处理,望亲见谅!</p><div><a name="maijsoft_s1_191268_end"></a></div><div><a name="maijsoft_s1_201186_start"></a></div><p>温馨提示:商品外盒或塑封仅作为包装材料使用,在快递运输过程中可能出现不同程度的变形或损坏,均为正常现象,不作为售后理由处理,望亲见谅!</p></div></div>', 'sales_sum': 43676, 'click_count': 21, 'market_price': '8.00', 'stock': 66532, 'is_collect': 0, 'member_price': 0, 'activity': {'type': 1, 'info': {'id': 3, 'start_time': '14:00', 'end_time': 1672995600}}, 'like': [{'id': 1, 'name': '晨光中性笔笔芯黑0.5mm黑色碳素签字笔GP-1008按动式水笔学生考试用蓝黑医生处方笔教师专用红笔圆珠笔文具', 'image': 'http://101.43.8.10:6969/uploads/images/background/20201210/45b6bb2224e4051ecf407cabb54cd781.png', 'price': '44.82', 'market_price': '55.00'}, {'id': 3, 'name': '晨光文具经典六角木杆铅笔中小学生考试绘图铅笔 2B铅笔练字笔20支 AWP35715', 'image': 'http://101.43.8.10:6969/uploads/images/background/20201210/2d62627fef767a38034162c066f9c253.png', 'price': '13.50', 'market_price': '21.00'}, {'id': 8, 'name': 'HERO/英雄钢笔HS208女神钢笔成人女士商务高档礼盒装办公时尚练字女生专用精致送礼官方正品代写贺卡', 'image': 'http://101.43.8.10:6969/uploads/images/background/20201210/5e11c751c7e662764764e132ab6a8f72.png', 'price': '1359.00', 'market_price': '2598.00'}, {'id': 5, 'name': '小米文具可削铅笔 六角2B 红黑抽条 木杆铅笔 儿童铅笔 AWP30804', 'image': 'http://101.43.8.10:6969/uploads/images/background/20201210/956e95bc35d0a8005255889036e9aae5.png', 'price': '6.00', 'market_price': '7.00'}, {'id': 2, 'name': '晨光文具速干中性笔直液式签字笔学生考试大容量全针管子弹头水笔直液式笔黑色0.5/0.38', 'image': 'http://101.43.8.10:6969/uploads/images/background/20201210/5a23d75c44ef8c293aa2a1bed1f10e41.png', 'price': '43.90', 'market_price': '78.00'}], 'price': '6.00', 'goods_spec': [{'id': 4, 'goods_id': 4, 'name': '默认', 'spec_value': [{'id': 4, 'goods_id': 4, 'spec_id': 4, 'value': '默认'}]}], 'goods_item': [{'id': 4, 'goods_id': 4, 'image': 'http://101.43.8.10:6969/uploads/images/background/20201210/4b06036c7e6c8f653a51fd94d4cb5bc5.png', 'spec_value_ids': '4', 'spec_value_str': '默认', 'market_price': '8.00', 'price': '6.00', 'stock': 66532}], 'goods_image': [{'goods_id': 4, 'uri': 'http://101.43.8.10:6969/uploads/images/background/20201210/4b06036c7e6c8f653a51fd94d4cb5bc5.png'}, {'goods_id': 4, 'uri': 'http://101.43.8.10:6969/uploads/images/background/20201210/d97a7d56854eb8cd5afa228b1d9608c3.png'}, {'goods_id': 4, 'uri': 'http://101.43.8.10:6969/uploads/images/background/20201210/956e95bc35d0a8005255889036e9aae5.png'}], 'order_give_integral': 0, 'commission_price': 0, 'comment': []}, 'show': 0, 'time': '0.111794'}
{'code': 1, 'msg': '加入成功', 'data': [], 'show': 0, 'time': '0.094376'}
{'code': 1, 'msg': '', 'data': {'order_id': '8', 'type': 'order'}, 'show': 0}
{'code': 1, 'msg': '获取成功', 'data': {'id': 8, 'order_sn': '202301061626104229', 'order_type': 1, 'order_status': 1, 'pay_status': 1, 'pay_way': 3, 'pay_time': '2023-01-06 16:26:10', 'consignee': '老百', 'mobile': '17900000001', 'delivery_type': 1, 'goods_price': '40.00', 'order_amount': '40.00', 'discount_amount': '0.00', 'integral_amount': '0.00', 'total_amount': '40.00', 'total_num': 1, 'shipping_price': '0.00', 'shipping_time': '', 'user_remark': '', 'confirm_take_time': '', 'cancel_time': '', 'refund_status': 0, 'settle_id': 0, 'settle_amount': None, 'use_integral': 0, 'refund_amount': None, 'order_remarks': '', 'create_time': '2023-01-06 16:26:10', 'update_time': None, 'coupon_list_id': None, 'team_found_id': 0, 'team_id': 0, 'delivery_id': 0, 'attach_values': '{"give_integral_scene":1,"give_growth_scene":1,"give_growth_num":0,"give_integral_num":0}', 'team': [], 'order_goods': [{'id': 9, 'order_id': 8, 'goods_id': 1, 'item_id': 1, 'goods_name': '晨光中性笔笔芯黑0.5mm黑色碳素签字笔GP-1008按动式水笔学生考试用蓝黑医生处方笔教师专用红笔圆珠笔文具', 'goods_num': 1, 'goods_price': '40.00', 'member_price': '44.82', 'original_price': '44.82', 'total_price': '40.00', 'total_pay_price': '40.00', 'discount_price': '0.00', 'integral_price': '0.00', 'spec_value_ids': '1', 'refund_status': 0, 'is_comment': 0, 'is_seckill': 1, 'is_member': 0, 'member_discount': '0.00', 'goods_info': '{"item_id":1,"goods_id":1,"goods_name":"晨光中性笔笔芯黑0.5mm黑色碳素签字笔GP-1008按动式水笔学生考试用蓝黑医生处方笔教师专用红笔圆珠笔文具","status":1,"del":0,"image":"\\/uploads\\/images\\/background\\/20201210\\/45b6bb2224e4051ecf407cabb54cd781.png","is_integral":0,"is_member":0,"give_integral_type":0,"give_integral":null,"free_shipping_type":1,"free_shipping":"0.00","free_shipping_template_id":0,"spec_image":"","spec_value_str":"默认","spec_value_ids":"1","goods_price":"40.00","volume":"2.000","stock":9857,"weight":"2.000","first_category_id":1,"second_category_id":4,"third_category_id":9,"goods_num":1,"image_str":"http:\\/\\/101.43.8.10:6969\\/uploads\\/images\\/background\\/20201210\\/45b6bb2224e4051ecf407cabb54cd781.png","is_seckill":1,"discount_price":0,"integral_price":0,"original_price":"44.82","member_price":"44.82","is_show_member":0,"give_integral_num":0,"sub_price":40}', 'create_time': 1672993570, 'comment_btn': 0, 'refund_btn': 0, 'spec_value': '默认', 'image': 'http://101.43.8.10:6969/uploads/images/background/20201210/45b6bb2224e4051ecf407cabb54cd781.png'}], 'delivery_address': '北京北京市东城区东直门内大街1号', 'pay_btn': 0, 'cancel_btn': 0, 'delivery_btn': 0, 'take_btn': 0, 'del_btn': 0, 'order_cancel_time': '', 'pay_way_text': '余额支付'}, 'show': 0, 'time': '0.075669'}

文章作者: 老百
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 老百 !
  目录