【问题标题】:Python urllib2 Progress HookPython urllib2 进度挂钩
【发布时间】:2010-01-08 15:22:50
【问题描述】:

我正在尝试使用 urllib2 http 客户端在 python 中创建下载进度条。我查看了 API(以及在 google 上),似乎 urllib2 不允许您注册进度挂钩。然而,旧的已弃用的 urllib 确实具有此功能。

有谁知道如何使用 urllib2 创建进度条或报告挂钩?还是有其他一些技巧可以获得类似的功能?

【问题讨论】:

    标签: python http progress-bar urllib2 httpclient


    【解决方案1】:

    这是一个完全有效的示例,它建立在 Anurag 的响应分块方法之上。我的版本允许您设置块大小,并附加任意报告功能:

    import urllib2, sys
    
    def chunk_report(bytes_so_far, chunk_size, total_size):
       percent = float(bytes_so_far) / total_size
       percent = round(percent*100, 2)
       sys.stdout.write("Downloaded %d of %d bytes (%0.2f%%)\r" % 
           (bytes_so_far, total_size, percent))
    
       if bytes_so_far >= total_size:
          sys.stdout.write('\n')
    
    def chunk_read(response, chunk_size=8192, report_hook=None):
       total_size = response.info().getheader('Content-Length').strip()
       total_size = int(total_size)
       bytes_so_far = 0
    
       while 1:
          chunk = response.read(chunk_size)
          bytes_so_far += len(chunk)
    
          if not chunk:
             break
    
          if report_hook:
             report_hook(bytes_so_far, chunk_size, total_size)
    
       return bytes_so_far
    
    if __name__ == '__main__':
       response = urllib2.urlopen('http://www.ebay.com');
       chunk_read(response, report_hook=chunk_report)
    

    【讨论】:

    • 太好了,可以下载了。有类似的上传吗? (即写大量的帖子数据?)
    • 这会将您的文件下载到哪里?我好像没找到。
    • @Zachary 据我所知,这不是“保存”文件;它正在打开一个网址。要保存文件,您将执行 file = open('myfile.html', 'wb') 然后 file.write(response.read())
    • 请注意,响应并不总是包含“Content-Length”标头。对于不支持它的服务器,这将失败。
    • @styfle:实际上,它正在打开一个 URL 并丢弃它的字节。 responde.read() 会破坏定期进度报告的全部意义。
    【解决方案2】:

    为什么不直接读取数据块并在其间做任何你想做的事情,例如在线程中运行,挂钩到 UI 等

    import urllib2
    
    urlfile = urllib2.urlopen("http://www.google.com")
    
    data_list = []
    chunk = 4096
    while 1:
        data = urlfile.read(chunk)
        if not data:
            print "done."
            break
        data_list.append(data)
        print "Read %s bytes"%len(data)
    

    输出

    Read 4096 bytes
    Read 3113 bytes
    done.
    

    【讨论】:

    • 唯一的是,我认为最后一行应该是 print "Read %s bytes"%len(data_list)
    • @Zachary Brown ,不,因为我只是打印每次读取的数据量,虽然最好打印读取的总数据,但它仍然不会是 len(data_list)跨度>
    【解决方案3】:

    urlgrabber 内置了对进度通知的支持。

    【讨论】:

      【解决方案4】:

      简化版:

      temp_filename = "/tmp/" + file_url.split('/')[-1]
      f = open(temp_filename, 'wb')
      remote_file = urllib2.urlopen(file_url)
      
      try:
          total_size = remote_file.info().getheader('Content-Length').strip()
          header = True
      except AttributeError:
          header = False # a response doesn't always include the "Content-Length" header
      
      if header:
          total_size = int(total_size)
      
      bytes_so_far = 0
      
      while True:
          buffer = remote_file.read(8192)
          if not buffer:
              sys.stdout.write('\n')
              break
      
          bytes_so_far += len(buffer)
          f.write(buffer)
          if not header:
              total_size = bytes_so_far # unknown size
      
          percent = float(bytes_so_far) / total_size
          percent = round(percent*100, 2)
          sys.stdout.write("Downloaded %d of %d bytes (%0.2f%%)\r" % (bytes_so_far, total_size, percent))
      

      【讨论】:

        【解决方案5】:

        对 Triptych 的响应稍作修改以允许实际写出文件 (python3):

        from urllib.request import urlopen
        
        def chunk_report(bytes_so_far, chunk_size, total_size):
            percent = float(bytes_so_far) / total_size
            percent = round(percent*100, 2)
            sys.stdout.write("Downloaded %d of %d bytes (%0.2f%%)\r" %
                             (bytes_so_far, total_size, percent))
        
            if bytes_so_far >= total_size:
                sys.stdout.write('\n')
        
        
        def chunk_read(response, chunk_size=8192, report_hook=None):
            total_size = response.info().get("Content-Length").strip()
            total_size = int(total_size)
            bytes_so_far = 0
            data = b""
        
            while 1:
                chunk = response.read(chunk_size)
                bytes_so_far += len(chunk)
        
                if not chunk:
                    break
        
                if report_hook:
                    report_hook(bytes_so_far, chunk_size, total_size)
        
                data += chunk
        
            return data
        

        用法:

        with open(out_path, "wb") as f:
            response = urlopen(filepath)
            data_read = chunk_read(response, report_hook=chunk_report)
        
            f.write(data_read)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-05-26
          • 1970-01-01
          • 2011-08-20
          • 2014-04-20
          • 1970-01-01
          • 2011-06-28
          • 1970-01-01
          • 2014-02-10
          相关资源
          最近更新 更多