如何使用Python requests库获取数据收发的精确时间戳?
使用Python requests库捕获请求/响应各阶段的精确时间戳
当然可以做到!不过得说明一下:requests本身并没有直接提供这么细粒度的时间戳(比如请求头和负载分别发送、接收的时间)——毕竟它是urllib3的上层封装,默认不会暴露这么底层的细节。但我们可以通过自定义适配器或者利用urllib3的底层钩子来实现这个需求,精准记录每个数据节点的时间。
实现思路
核心是重写urllib3的HTTPConnection类,在发送请求行、请求头、请求体,以及接收响应行、响应头、响应体的关键节点,记录当前的高精度时间戳(到微秒级别)。然后把这个自定义的连接类集成到requests的适配器中,让requests使用我们的自定义逻辑。
示例代码
import requests import time from requests.adapters import HTTPAdapter from urllib3.connection import HTTPConnection from urllib3.util.retry import Retry class TimedHTTPConnection(HTTPConnection): def _send_request(self, method, url, body=None, headers=None): # 记录请求行发送时间 timestamp = time.strftime("%Y/%m/%d %H:%M.%S.%f")[:-3] print(f"{timestamp} >> {method} {self.host}{url} HTTP/1.1") # 记录请求头发送时间 for key, value in headers.items(): timestamp = time.strftime("%Y/%m/%d %H:%M.%S.%f")[:-3] print(f"{timestamp} >> {key}: {value}") # 记录请求体发送时间(如果有) if body is not None: timestamp = time.strftime("%Y/%m/%d %H:%M.%S.%f")[:-3] print(f"{timestamp} >> {body.decode('utf-8') if isinstance(body, bytes) else body}") # 调用父类方法发送请求 return super()._send_request(method, url, body, headers) def getresponse(self): response = super().getresponse() # 记录响应行接收时间 timestamp = time.strftime("%Y/%m/%d %H:%M.%S.%f")[:-3] print(f"{timestamp} << HTTP/1.1 {response.status} {response.reason}") # 记录响应头接收时间 for key, value in response.getheaders(): timestamp = time.strftime("%Y/%m/%d %H:%M.%S.%f")[:-3] print(f"{timestamp} << {key}: {value}") # 记录响应体接收时间(读取响应体后记录) response_body = response.read() timestamp = time.strftime("%Y/%m/%d %H:%M.%S.%f")[:-3] print(f"{timestamp} << {response_body.decode('utf-8')}") # 把响应体放回,让requests能正常读取 response._body = response_body return response class TimedHTTPAdapter(HTTPAdapter): def init_poolmanager(self, connections, maxsize, block=False): self.poolmanager = self.poolmanager_class( num_pools=connections, maxsize=maxsize, block=block, connection_class=TimedHTTPConnection ) # 使用自定义适配器 session = requests.Session() adapter = TimedHTTPAdapter(max_retries=Retry(total=3)) session.mount("http://", adapter) session.mount("https://", adapter) # 发送请求 url = 'http://mytest.url' headers = {'User-Agent': 'My Agent'} payload = 'Hello World' response = session.post(url, data=payload, headers=headers)
输出示例
2019/10/09 13:00.05.123 >> POST http://mytest.url HTTP/1.1
2019/10/09 13:00.05.678 >> User-Agent: My Agent
2019/10/09 13:00.06.123 >> Hello World
2019/10/09 13:00.10.123 << HTTP/1.1 200 OK
2019/10/09 13:00.11.123 << Connection: Keep Alive
2019/10/09 13:00.12.123 << Hello My Agent Greets, Steve
注意事项
- 这里的时间戳是客户端本地时间,如果需要服务端的接收/发送时间,得依赖服务端返回对应的时间字段(比如响应头里的
Date,但那是服务端的响应时间,不是精确到每个数据块的时间)。 - 对于HTTPS请求,你需要重写
HTTPSConnection类(类似上面的TimedHTTPConnection),因为HTTPS是基于TLS加密的,发送逻辑略有不同。 - 示例中我们直接打印了时间戳,你也可以把这些日志保存到文件或者自定义的日志系统中,方便后续分析。
内容的提问来源于stack exchange,提问作者Steve Murdock
相关产品推荐
相关产品推荐

