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