利用requests中hook实现打印请求包和响应包

2022年4月12日10:35:40

我们知道,在requests中可以使用hook来对响应实现一些自定义的操作,例如我可以使用下面的例子来打印请求包和响应包。

from urllib.parse import urlparse
import requests


def ResponseHook(rep, **kwargs):
    rep.encoding = 'utf-8'
    request_str = '%s %s HTTP/%.1f\n' % (rep.request.method, rep.request.path_url, rep.raw.version * 0.1)
    request_str += f"Host: {urlparse(rep.url).netloc}\n"
    for k, v in dict(rep.request.headers).items():
        request_str += f"{k}: {v}\n"

    if rep.request.body:
        request_str += '\n' + str(rep.request.body)
    resp_str = 'HTTP/%.1f %d %s\n' % (rep.raw.version * 0.1, rep.raw.status,
                                                  rep.raw.reason)
    for k, v in dict(rep.headers).items():
        resp_str += f"{k}: {v}\n"

    resp_str += '\n' + rep.text
    print(request_str)
    print(resp_str)


r = requests.get('https://baidu.com', hooks={'response': ResponseHook})

但是 ,在有些情况下我们不方便修改或不能修改源代码的情况下如何查看代码中使用requests中的请求包和响应包,第一时间想到的是使用装饰器,但是这里我们可以子类方法重写了父类方法()也可以实现, 这样就可以不用每次在使用requests的时候都写上hook和其他关键字参数了。

在 Python 中,如果子类 继承 了父类,那么子类会继承父类所有的 方法 和 属性,此时,如果子类重新定义了父类中的方法,那么就构成了方法重写,即子类方法重写了父类方法。

例子如下

首先新建一个reqtests_hook.py

from urllib.parse import urlparse
import requests
from urllib3 import disable_warnings

disable_warnings()

# 在这里可以自定义默认的header
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134'
}


def ResponseHook(rep, **kwargs):
    """打印请求包和响应包"""
    rep.encoding = 'utf-8'
    # 状态码及http版本
    request_str = '%s %s HTTP/%.1f\n' % (rep.request.method, rep.request.path_url, rep.raw.version * 0.1)
    # 遍历headers将字典转换成字符串
    request_str += f"Host: {urlparse(rep.url).netloc}\n"
    for k, v in dict(rep.request.headers).items():
        request_str += f"{k}: {v}\n"
    # 请求体
    if rep.request.body:
        request_str += '\n' + str(rep.request.body)
    # 响应包状态码及响应码
    resp_str = 'HTTP/%.1f %d %s\n' % (rep.raw.version * 0.1, rep.raw.status, rep.raw.reason)
    # 响应包头部信息
    for k, v in dict(rep.headers).items():
        resp_str += f"{k}: {v}\n"
    # 响应体
    resp_str += '\n' + rep.text
    print(request_str)
    print(resp_str)


class HookSession(requests.Session):

    def request(self, method, url, **kwargs):
        headers = {}
        headers.update(HEADERS)
        if 'headers' in kwargs:
            headers.update(kwargs['headers'])
            kwargs['headers'] = headers
        kwargs.setdefault('verify', False)
        kwargs.setdefault('hooks', {'response': ResponseHook})
        return super().request(method, url, **kwargs)


requests.sessions.Session = HookSession

test.py

import requests
import reqtests_hook

r = requests.get('https://baidu.com')

这样我们不使用任何关键字参数就可以实现hook的功能

利用requests中hook实现打印请求包和响应包