我正在制作一个下载一个大文件的程序,我已经添加了一个功能,该功能可以确定程序的下载百分比,并在每次下载另一个10%的时候通知用户,当我在较小的文件上测试该程序时(即,print (str(percent) + " downloaded at " + str(time))),然而,我注意到它的准确性要低得多。下面是我做的一个示例程序:
import urllib.request
def printout(a, b, c):
print(str(a) + ", " + str(b) + ", " + str(c))
urllib.request.urlretrieve("http://downloadcenter.mcafee.com/products/tools/foundstone/fport.zip", r"C:\Users\Username\Downloads\fport.zip", reporthook = printout)这会下载Fport,这是我本来要下载的一个工具。不管怎样,我得到了这个输出:
0, 8192, 57843
1, 8192, 57843
2, 8192, 57843
3, 8192, 57843
4, 8192, 57843
5, 8192, 57843
6, 8192, 57843
7, 8192, 57843
8, 8192, 57843我想这正是我想要的。我正要把它放进去,这时我发现了一个小错误。8192与57843不符。不是8次。我把它插入到一个计算器中,发现,实际上,它大约有7次。这是一个相当大的差异,考虑到。这种断开对较大文件的影响较小,但它仍然存在。这是一种元数据还是报头?如果是这样的话,它是相当大的,不是吗?有没有办法解决这个问题(比如,它总是在16000字节左右)?
发布于 2014-01-17 03:01:25
urllib.request的高级接口真的不适合你正在尝试做的事情。你可以使用底层接口,但实际上,这是第三方库requests简化了一个数量级的事情之一。(例如,你不必使用requests-the各种curl包装器,这也比urllib更容易。但requests是最urllib的-like,也是最简单的第三方替代品)。
requests可以像urllib一样工作,自动下载所有内容,但只需添加stream=True,您就可以控制数据的提取。它有几个不同的接口(解码的Unicode行、字节行、套接字中的原始数据等),但iter_content可能是您想要的接口-它按需提供内容块、适当缓冲、透明地将分块传输模式映射为平面传输、处理100Continue、…基本上HTTP可以抛给你的所有东西。所以:
with open(path, 'wb') as f:
r = requests.get(url, stream=True)
for chunk in r.iter_content(8192):
f.write(chunk)添加进度仍然需要手动完成。但是,由于您提取的是块,而不是将它们保存到背后的文件中,因此您确切地知道您看到了多少字节。而且,只要服务器提供了Content-Length标头(有些服务器在某些情况下不会这样做,但除了处理它之外,您对此也无能为力),这很容易:
with open(path, 'wb') as f:
r = requests.get(url, stream=True)
total = r.headers.get('content-length')
sofar = 0
for chunk in r.iter_content(8192):
f.write(chunk)
sofar += len(chunk)
if total:
print('{} / {}: {}%'.format(sofar, total, sofar*100.0/total))
else:
print('{} / ???: ???%'.format(sofar))https://stackoverflow.com/questions/21149555
复制相似问题