【问题标题】:Why python print is delayed?为什么python打印延迟?
【发布时间】:2015-05-05 15:16:48
【问题描述】:

我正在尝试使用请求下载文件,并在每次检索 100k 大小的文件时打印一个点,但最后打印出所有点。见代码。

with open(file_name,'wb') as file:
    print("begin downloading, please wait...")
    respond_file = requests.get(file_url,stream=True)
    size = len(respond_file.content)//1000000

    #the next line will not be printed until file is downloaded
    print("the file size is "+ str(size) +"MB")
    for chunk in respond_file.iter_content(102400):
        file.write(chunk)
        #print('',end='.')
        sys.stdout.write('.')
        sys.stdout.flush()
    print("")

【问题讨论】:

  • 哪些部分延迟了?一些print() 电话或sys.stdout.write() 电话?
  • 猜想:访问respond_file.content 会强制请求全部完成,然后才能继续下一行。尝试删除size = ...print("the file size is... 行,看看你的点是否能更及时地打印出来。
  • @Kevin:我错过了,但猜测是正确的。
  • 是的,是.content导致打印点延迟,根据答案可以解决。

标签: python python-3.x web-crawler python-requests


【解决方案1】:

您正在这里访问request.content

size = len(respond_file.content)//1000000

访问该属性会强制下载整个响应,对于大型响应,这需要一些时间。请改用int(respond_file.headers['content-length'])

size = int(respond_file.headers['content-length']) // 1000000

Content-Length 标头由服务器提供,由于它是标头的一部分,因此您无需先下载所有内容即可访问该信息。

如果服务器选择使用Transfer-Encoding: chunked 流式传输响应,则无需设置Content-Length 标头;您可能需要考虑到这一点:

content_length = respond_file.headers.get('content-length', None)
size_in_kb = '{}KB'.format(int(content_length) // 1024) if content_length else 'Unknown'
print("the file size is", size_in_kb)

其中以千字节为单位的大小是通过将长度除以 1024 而不是 100 万来计算的。

或者,在单独的 HEAD 请求中询问大小(仅获取标头):

head_response = requests.get(file_url)
size = int(head_response.headers.get('content-length', 0))

【讨论】:

  • 谢谢大家,但是当我尝试从标头获取内容长度时,出现以下错误:keyerror,我打印了响应标头:{'server': 'nginx/1.4.2' ,“日期”:“格林威治标准时间 2015 年 5 月 5 日星期二 16:18:44”,“传输编码”:“分块”,“内容类型”:“文本/html”,“连接”:“关闭”},有办法解决吗?
  • @1a1a11a:那么服务器没有预先给你一个长度,你将无法给出关于大小的消息。会更新。
  • 有没有其他方法可以在下载前知道文件的大小?
  • @1a1a11a:你可以在 URL 上使用HEAD 请求。
【解决方案2】:

这应该会如您所愿。获取respond_file 的长度不是您想要的。而是检查内容长度标头。

注意:我将代码改为显示 KB(出于测试目的)。

import requests
import sys

file_url = "https://github.com/kennethreitz/requests/archive/master.zip"
file_name = "out.zip"

with open(file_name,'wb') as file:
    print("begin downloading, please wait...")
    respond_file = requests.get(file_url,stream=True)
    size = int(respond_file.headers['content-length'])//1024

    #the next line will not be printed until file is downloaded
    print("the file size is "+ str(size) +"KB")
    for chunk in respond_file.iter_content(1024):
        file.write(chunk)
        #print('',end='.')
        sys.stdout.write('.')
        sys.stdout.flush()
    print("")

【讨论】:

  • 谢谢大家,但是当我尝试从标头获取内容长度时,出现以下错误:keyerror,我打印了响应标头:{'server': 'nginx/1.4.2' ,“日期”:“格林威治标准时间 2015 年 5 月 5 日星期二 16:18:44”,“传输编码”:“分块”,“内容类型”:“文本/html”,“连接”:“关闭”},有办法解决吗?
【解决方案3】:

@kevin 在评论中写道,respond.file.content 会阻止执行,直到下载整个内容。我的回答和他的评论之间的唯一区别是我不是在猜测 ;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多