You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中获取网络请求的详细时序属性(如Blocked、DNS解析等)?

获取类似Firefox开发者工具的请求时序细节

嘿,这个问题我之前折腾过好一阵子!requests库的elapsed.total_seconds()确实只能给你一个模糊的总耗时,和Firefox开发者工具里拆分的Blocked、DNS解析、Connecting这些阶段时间差得挺多——毕竟前者只算了从请求发起开始到响应拿到手的总时长,还包含了requests自身的一些初始化开销,而Firefox是把整个HTTP请求的生命周期拆得明明白白的。

想要拿到和Firefox一样的细分时序,你可以试试下面这两个方案:

方案一:用PyCurl(底层精确控制)

PyCurl是libcurl的Python绑定,能直接获取到HTTP请求各个阶段的精确时间戳,完全对应Firefox里的各个时序项。

首先先安装它:

pip install pycurl

然后用这段代码就能拿到所有细节:

import pycurl
from io import BytesIO

def get_detailed_timings(url):
    response_buffer = BytesIO()
    curl = pycurl.Curl()
    curl.setopt(curl.URL, url)
    curl.setopt(curl.WRITEDATA, response_buffer)
    
    # 开启时序统计,定义回调函数收集时间数据
    timings = {}
    def track_progress(_, __, ___, ____, total_time, namelookup_time, connect_time, pretransfer_time, starttransfer_time):
        timings['总耗时'] = total_time
        timings['DNS解析耗时'] = namelookup_time
        timings['到TCP连接完成耗时'] = connect_time
        timings['到开始发送请求前耗时'] = pretransfer_time
        timings['到第一个响应字节到达耗时'] = starttransfer_time
    
    curl.setopt(curl.XFERINFOFUNCTION, track_progress)
    curl.setopt(curl.PROGRESSFUNCTION, lambda *args: None)  # 兼容旧版本libcurl
    
    try:
        curl.perform()
    except Exception as e:
        print(f"请求失败:{str(e)}")
        return None
    finally:
        curl.close()
    
    # 计算各个阶段的单独耗时,对应Firefox的展示项
    timings['Blocked(近似)'] = timings['DNS解析耗时']
    timings['TCP连接耗时'] = timings['到TCP连接完成耗时'] - timings['DNS解析耗时']
    timings['TLS握手耗时'] = timings['到开始发送请求前耗时'] - timings['到TCP连接完成耗时']
    timings['Waiting(服务器响应等待)'] = timings['到第一个响应字节到达耗时'] - timings['到开始发送请求前耗时']
    timings['响应接收耗时'] = timings['总耗时'] - timings['到第一个响应字节到达耗时']
    
    return timings

# 测试用例
if __name__ == "__main__":
    url = "https://example.com"
    results = get_detailed_timings(url)
    if results:
        print("请求时序详情(对应Firefox开发者工具):")
        for stage, duration in results.items():
            print(f"{stage}: {duration:.4f} 秒")

这里的各个字段完全对应Firefox里的项:

  • DNS解析耗时 → Firefox的DNS解析时间
  • TCP连接耗时 → Connecting阶段的TCP连接部分
  • TLS握手耗时 → (HTTPS请求)SSL/TLS握手时间
  • Waiting(服务器响应等待) → 就是你看到的~650ms那个等待时间
  • Blocked(近似) → 近似Firefox的Blocked时间(pycurl没有直接提供请求排队等待的精确值,用DNS开始前的时间近似)

方案二:用HTTPX(更简洁的现代库)

如果你觉得PyCurl的代码有点繁琐,HTTPX这个现代HTTP库也支持直接获取细分时序,而且API更友好,还支持异步。

安装HTTPX:

pip install httpx

示例代码:

import httpx
import asyncio

async def get_httpx_timings(url):
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        # 从响应扩展字段里拿到时序数据
        timing_data = response.extensions['http_version']['timings']
        
        print("请求时序详情:")
        print(f"Blocked: {timing_data['blocked']:.4f} 秒")
        print(f"DNS解析: {timing_data['dns']:.4f} 秒")
        print(f"TCP连接: {timing_data['connect']:.4f} 秒")
        print(f"TLS握手: {timing_data['tls']:.4f} 秒")
        print(f"请求发送: {timing_data['send']:.4f} 秒")
        print(f"Waiting(等待响应): {timing_data['wait']:.4f} 秒")
        print(f"响应接收: {timing_data['receive']:.4f} 秒")
        print(f"总耗时: {sum(timing_data.values()):.4f} 秒")

# 运行异步函数
asyncio.run(get_httpx_timings("https://example.com"))

HTTPX的timings字段直接映射了Firefox里的所有阶段,不用自己计算,用起来特别省心。

为什么requests的elapsed和Firefox有差异?

简单来说:

  • requests的elapsed是从你调用requests.get()方法开始计时,到响应完全拿到手的总时间,包含了requests库自身的初始化、参数处理等开销。
  • Firefox的时间是从浏览器真正发起网络请求的那一刻开始算的,而且拆分了各个阶段,没有包含浏览器自身的准备开销,所以两者会有100ms左右的差异,这完全正常。

内容的提问来源于stack exchange,提问作者onon99buynoodle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:33:25