api/Response

发布时间 2023-05-25 17:38:42作者: 挖洞404

1、介绍

 对应http响应对象。两种解析:

  • str字符串对象解析
  • requests.Response类型对象解析

解析响应有两个问题:

  • 一是关于响应体部的类型。一般来说,如果是非文本类型,则不记录响应体部。
  • 二是如果响应体部是文本类型,关于其编码方案的获取。一般来说,会尝试转为utf-8编码

目前,解决方案是先判断是否为文本类型。然后直接对响应体部的字节序列进行utf-8解码。如果出现异常,再尝试gbk。最后尝试iso-8859-1,该编码方案能够适用任意字节。

2、代码

import re

import requests

from api.PropertiesClasses import Headers, Cookies

"""
http响应对象
"""


class Response:
    def __init__(self, res=None):
        # 协议/版本
        self.protocol_version = 'HTTP/1.1'
        # 响应状态码
        self.status_code = ''
        # 响应状态描述符
        self.reason = ''
        # 响应头部字段
        self.headers = Headers()
        # 响应体部
        self.body = ''

        self.parse(res=res)

    """
    解析
    """
    def parse(self, res=None):
        # 响应报文字符串
        if type(res) == str and len(res) > 0:
            res: str
            res = res.replace("\r", "")
            pattern = "^([\\S]*) ([0-9]*) ([^\n]*)((\n[^\n]+)*)\n\n(.*)"
            result = re.findall(pattern=pattern, string=res, flags=re.I | re.DOTALL)
            if result:
                self.protocol_version = result[0][0]
                self.status_code = result[0][1]
                self.reason = result[0][2]
                self.body = result[0][5]
                if result[0][3] != "":
                    self.headers = Headers(result[0][3])
        # requests模块的响应对象
        elif type(res) == requests.Response:
            res: requests.Response
            self.protocol_version = "HTTP/1.1"
            self.status_code = str(res.status_code)
            self.reason = res.reason
            self.headers = Headers(res.headers)

            # 根据响应头部content-type字段判断是否为文本
            if self.headers.hasName('Content-Type') and 'text' not in self.headers.getFirstValue('Content-Type'):
                self.body = '[提示]依据响应头部判断响应体部非文本'
            else:
                # 默认编码为utf-8
                try:
                    if res.content:
                        self.body = res.content.decode('utf-8')
                except Exception as e:
                    # 其次尝试gbk编码
                    try:
                        if res.content:
                            self.body = res.content.decode('gbk')
                    except Exception as e:
                        # 提取编码类型
                        try:
                            flag = False
                            # 从响应头部中提取,text/html;charset=utf-8
                            if self.headers.hasName('Content-Type'):
                                # 采用Cookies类解析,但cookie是严格区分大小写的,所以处理前转小写
                                content_type = self.headers.getFirstValue('Content-Type').lower()
                                if 'charset' in content_type:
                                    content_type: str
                                    arr = Cookies(obj=content_type)
                                    encoding = arr.getFirstValue('charset')
                                    if encoding != '':
                                        self.body = res.content.decode(encoding)
                                        flag = True
                            if not flag:
                                raise Exception('')
                            # 从响应体部<meta charset=>进行正则提取,但是需要先进行iso-8859-1这类扩展ascii编码进行解码
                            # 目的是使用正则提取,而不会报解码异常错误。
                        except Exception as e:
                            # 解析为iso-8859-1,可能乱码,但不会报错
                            self.body = res.content.decode('iso-8859-1')

    """
    获取报文
    """

    def get_message(self):
        """get_message() -> str"""
        message = '%s %s %s\n%s\n\n%s' % (self.protocol_version, self.status_code, self.reason,
                                          self.headers.toString(), self.body)
        return message

    """
    排除响应头部字段中的date字段
    """

    def get_message_exclude_date(self):
        """get_message_exclude_date() -> str"""
        headers = self.headers.clone()
        headers.remove('date')
        message = '%s %s %s\n%s\n\n%s' % (self.protocol_version, self.status_code, self.reason,
                                          headers.toString(), self.body)
        return message