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

使用Python Requests测量网页下载速度:问题与改进方案

问题分析

你的代码主要问题出在时间范围的计算错误,以及单次测量的偶然性:

  • response.elapsed统计的是从发起请求到收到完整响应的总耗时,包含DNS解析、TCP三次握手、服务器处理请求、网络传输数据的全部时间,并非仅数据下载的时间。服务器处理和握手等环节会占用大量时间,导致计算出的速度远低于实际下载速率。
  • 单次测量结果受网络波动、服务器负载影响极大,无法反映真实的平均速度。
  • 若存在重定向,elapsed还会包含所有重定向请求的耗时,进一步拉低计算值。
改进方案

针对网页HTML的测量需求,我们可以通过精准记录数据下载阶段的时间,并多次测量取平均来优化:

方法1:利用requests流式响应捕获下载时间(适配网页场景)

这里的流式只是用来捕获开始下载的时间点,不需要分块处理大文件,完全适配网页测量需求:

import requests
import time

def measure_download_speed(url, num_trials=5):
    total_speed = 0.0
    session = requests.Session()
    
    for _ in range(num_trials):
        start_time = None
        content_length = 0
        
        def track_download(response, *args, **kwargs):
            nonlocal start_time, content_length
            # 首次收到响应数据时记录开始时间
            if start_time is None:
                start_time = time.perf_counter()
            # 累加收到的字节数
            content_length += len(response.raw.read(1024*1024))
        
        try:
            response = session.get(url, stream=True, hooks={'response': track_download})
            response.raise_for_status()
            # 确保所有数据都被读取
            while response.raw.read(1024*1024):
                pass
            
            if start_time is not None:
                elapsed_time = time.perf_counter() - start_time
                if elapsed_time > 0:
                    # 字节转KB/s(1KB=1024字节)
                    speed = (content_length / 1024) / elapsed_time
                    total_speed += speed
        except Exception as e:
            print(f"请求失败: {e}")
            continue
    
    if num_trials > 0:
        avg_speed = total_speed / num_trials
        print(f"平均下载速度: {avg_speed:.2f} KB/s")
        return avg_speed
    else:
        return 0

# 测试
measure_download_speed("https://stackoverflow.com", num_trials=5)

方法2:通过响应头分离下载时间(更简洁)

如果不想用流式,也可以通过对比总耗时和服务器处理时间,近似分离出下载阶段的耗时:

import requests
from datetime import datetime

def get_download_speed(url, num_trials=5):
    total_speed = 0.0
    session = requests.Session()
    
    for _ in range(num_trials):
        try:
            response = session.get(url, allow_redirects=True)
            response.raise_for_status()
            
            # 总耗时(秒)
            total_elapsed = response.elapsed.total_seconds()
            # 计算服务器处理时间:从本地请求发送到服务器返回响应头的时间
            server_date = datetime.strptime(response.headers['Date'], '%a, %d %b %Y %H:%M:%S %Z')
            local_request_time = datetime.utcnow() - response.elapsed
            server_processing_time = (server_date - local_request_time).total_seconds()
            
            # 近似下载时间 = 总耗时 - 服务器处理时间(避免负数,设最小阈值)
            download_time = max(total_elapsed - server_processing_time, 0.001)
            content_size_kb = len(response.content) / 1024
            speed = content_size_kb / download_time
            
            total_speed += speed
        except Exception as e:
            print(f"请求失败: {e}")
            continue
    
    avg_speed = total_speed / num_trials
    print(f"平均下载速度: {avg_speed:.2f} KB/s")
    return avg_speed

get_download_speed("https://stackoverflow.com", num_trials=5)
关键优化点
  • 精准计时:只统计数据传输阶段的时间,排除握手、服务器处理等非下载耗时。
  • 多次取平均:减少网络波动、服务器负载带来的误差。
  • 异常处理:避免单次请求失败导致整个测量失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:10:38