Python | HTTP - 如何在下载文件之前检查文件大小

3

我正在使用urllib3爬取网页。示例代码:

from urllib3 import PoolManager

pool = PoolManager()
response = pool.request("GET", url)

问题在于,我可能会偶然遇到一些下载非常大的文件的网址,而我并不想下载它。
我找到了这个问题 - 链接 - 它建议使用urlliburlopen。我不想两次联系服务器。
我想限制文件大小为25MB。是否有办法使用urllib3实现这一点?

读取直到达到25MB,然后取消下载? - jarmod
那是一个选项。我该怎么做? - Montoya
3
您可以使用HTTP HEAD动词以及读取Content-Length标头来检索大小。如果服务器省略Content-Length,则除非像jarmod提到的那样开始下载文件,否则无法检查文件大小。 - Alexander Schmidt
1
我相信你可以发出一个HEAD请求,而不是GET请求,并且它应该包含content-length头。 - John Gordon
@JohnGordon> 并不总是这样。特别是,如果是脚本发送文件且开发人员没有手动设置内容长度标头,则标头将不包括其中一个。 - spectras
要取消,您需要一个更复杂的下载工具,例如:https://dev59.com/6nI-5IYBdhLWcg3wEEDu。 - jarmod
1个回答

6
如果服务器提供了一个Content-Length头,那么您可以使用它来确定是否继续下载剩余的内容。如果服务器没有提供这个头,则需要流式传输响应,直到您决定不再继续为止。
为此,您需要确保您没有预加载完整的响应
from urllib3 import PoolManager

pool = PoolManager()
response = pool.request("GET", url, preload_content=False)

# Maximum amount we want to read  
max_bytes = 1000000

content_bytes = response.headers.get("Content-Length")
if content_bytes and int(content_bytes) < max_bytes:
    # Expected body is smaller than our maximum, read the whole thing
    data = response.read()
    # Do something with data
    ...
elif content_bytes is None:
    # Alternatively, stream until we hit our limit
    amount_read = 0
    for chunk in r.stream():
        amount_read += len(chunk)
        # Save chunk
        ...
        if amount_read > max_bytes:
            break

# Release the connection back into the pool
response.release_conn()

我还开了一个问题来改进我们针对这种情况的文档,请添加任何有用或有帮助的附注:https://github.com/shazow/urllib3/issues/1037 - shazow
快速提问:由于您没有关闭连接而只是将其释放到池中,那么下一个请求不会恢复下载并因为无法识别HTTP响应而中断吗?难道不应该强制关闭吗? - spectras
@ spectras,老实说,我并不100%确定头脑中会发生什么,但如果它确实无法恢复连接,那么我会认为这是urllib3的一个错误,并请求您进行报告。 :) 我相当确定在我们重用连接之前进行了检查。 - shazow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接