通过python request库获取文件大小和文件类型(解决报错:KeyError: ‘content-length‘)

本文介绍了在Python中使用requests库时遇到的获取content-length和content-type的问题,特别是针对存在鉴权的私有文件。通过设置requests.head的Accept-Encoding参数和使用Range头在GET请求中获取Content-Range,解决了获取文件真实大小的难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


背景

把同一份文件分别存放到了两个oss(可以理解为两个存储商),通过两个oss 返回的下载 url 获取 两个文件的content-length 和 content-type信息,对比是否一致

遇到的问题:

1、当通过response header 获取content-length 的时候,千牛的url 没有返回 content-length

2、涉及到鉴权的私有文件url 获取不到真正的content-length

通过curl -i url 是可以返回同一个文件 存在两个url 的content-length 的,那怎么通过python解决以上两个问题呢(方法不一定最好,欢迎拍砖!)
在这里插入图片描述

一、解决获取不到content-length问题

方法:通过python 的requests.head(url,headers)指定header 里的Accept-Encoding参数,来获取文件流真实的content-length

原因:请求参数 headers里不指定文件流的Accept-Encoding,当服务器有对文件做了压缩后返回时,content-length就有可能获取不到

参考了博文:https://blog.csdn.net/chouhuan1877/article/details/100808814 有说明获取不到content-length的原因

实验对比:

def head_getcontent(file,srcDownloadUrl,distDownloadUrl):
    session = requests.session()
    headers = {
        "Accept-Encoding": "identity"
    }
    # 通过requests.head()填入不同的参数处理千牛的文件url
    src_only_url = requests.head(url=srcDownloadUrl)
    src_url_headers = requests.head(url=srcDownloadUrl, headers=headers)
    src_url_headers_stream = requests.head(url=srcDownloadUrl, stream=True, headers=headers)

    print("src_only_url headers= {}".format(src_only_url.headers))
    print("src_url_headers headers= {}".format(src_url_headers.headers))
    print("src_url_headers_stream headers= {}".format(src_url_headers_stream.headers))
    print("src_only_url Content-Length= {}".format(src_only_url.headers['Content-Length']))
    print("src_url_headers Content-Length= {}".format(src_url_headers.headers['Content-Length']))
    print("src_url_headers_stream Content-Length= {}".format(src_url_headers_stream.headers['Content-Length']))

报错:

Traceback (most recent call last):
  File "F:/directory/Learn/request_url/head_get.py", line 76, in <module>
    print(head_getcontent(file,s,d))
  File "F:/directory/Learn/request_url/head_get.py", line 48, in head_getcontent
    print("src_only_url Content-Length= {}".format(src_only_url.headers['Content-Length']))
  File "D:\Anaconda3\lib\site-packages\requests\structures.py", line 52, in __getitem__
    return self._store[key.lower()][1]
KeyError: 'content-length'
Process finished with exit code 1

在这里插入图片描述

总结:

1)先了解一下Accept-Encoding:https://baike.baidu.com/item/Accept-Encoding/3239902?fr=aladdin,说明服务器对文件做压缩处理了,浏览器请求获取文件信息时需要header 指定Accept-Encoding,追加 headers 参数:“Accept-Encoding”: “identity” 后,就可以解决:KeyError: ‘content-length’ 的问题
2)python 的 requests.head(url,header) 可以获取到url 服务器返回的header信息(是不是所有的都能获取呢?这个就不一定了)

二、解决获取不到真正的content-length问题

问题:通过header 指定编码格式来获取带有鉴权信息的文件的content-length的时候,由于鉴权的存在,获取到的content-length 不是真实的 content-length

dis_url_headers = requests.head(url=distDownloadUrl, headers=headers)

结果:
在这里插入图片描述
说明:requests.head 获取不到具有鉴权信息的文件content-length(或者是需要什么参数来指定?欢迎指教~)

思路1:服务器去掉鉴权的部分,通过requests.head 来直接获取真实的content-length

这个是可行的,但是,很依赖去掉鉴权的操作,于是有了思路2

思路2:通过curl 我们可以获取到文件的几个字节的方式来 间接获取这个文件流的字节大小

HTTP1.1 协议(RFC2616)开始支持获取文件的部分内容。通过在 Header 里两个参数实现的,客户端发请求时对应的是 Range ,服务器端响应时对应的是 Content-Range。

在这里插入图片描述

方法和实验

那么通过python如何实现呢?
要在发出带 Range 的请求后,服务器才会在 Content-Range 头部返回当前接受的范围和文件总大小,那只能是发出一个 指定header里 range 参数的请求头的get 请求了

def head_getcontent(file,srcDownloadUrl,distDownloadUrl):
    headers = {
        "Accept-Encoding": "identity",
        "Range": "bytes=0-1"
    }
    # 处理千牛的url
    src_only_url = requests.head(url=srcDownloadUrl)
    src_url_headers = requests.head(url=srcDownloadUrl, headers=headers)
    src_url_headers_stream = requests.head(url=srcDownloadUrl, stream=True, headers=headers)

    print("src_only_url headers= {}".format(src_only_url.headers))
    print("src_url_headers headers= {}".format(src_url_headers.headers))
    print("src_url_headers_stream headers= {}".format(src_url_headers_stream.headers))
    # print("src_only_url Content-Length= {}".format(src_only_url.headers['Content-Length']))
    print("src_url_headers Content-Length= {}".format(src_url_headers.headers['Content-Length']))
    print("src_url_headers_stream Content-Length= {}".format(src_url_headers_stream.headers['Content-Length']))
    print("src_url_headers_stream Content-Range= {}".format(src_url_headers_stream.headers['Content-Range']))


    # 处理oss2 的url
    print("____________head_____________")
    dis_only_url = requests.head(url=distDownloadUrl)
    dis_url_headers = requests.head(url=distDownloadUrl, headers=headers)
    dis_url_headers_stream = requests.head(url=distDownloadUrl, stream=True, headers=headers)
    print("dis_only_url headers= {}".format(dis_only_url.headers))
    print("dis_url_headers headers= {}".format(dis_url_headers.headers))
    print("dis_url_headers_stream headers= {}".format(dis_url_headers_stream.headers))
    print("dis_only_url Content-Length= {}".format(dis_only_url.headers['Content-Length']))
    print("dis_url_headers Content-Length= {}".format(dis_url_headers.headers['Content-Length']))
    print("dis_url_headers_stream Content-Length= {}".format(dis_url_headers_stream.headers['Content-Length']))

    print("________session____get_____________")
    requests.DEFAULT_RETRIES = 5  # 增加重试连接次数
    session = requests.session()
    requests.keep_alive = False  # 关闭多余连接
    dis_only_geturl = session.get(url=distDownloadUrl)
    dis_geturl_headers = session.get(url=distDownloadUrl, headers=headers)
    dis_geturl_headers_stream = session.get(url=distDownloadUrl, stream=True, headers=headers)
    print("dis_only_geturl headers= {}".format(dis_only_geturl.headers))
    print("dis_geturl_headers headers= {}".format(dis_geturl_headers.headers))
    print("dis_geturl_headers_stream headers= {}".format(dis_geturl_headers_stream.headers))
    print("dis_only_geturl Content-Length= {}".format(dis_only_geturl.headers['Content-Length']))
    print("dis_geturl_headers Content-Length= {}".format(dis_geturl_headers.headers['Content-Length']))
    print("dis_geturl_headers_stream Content-Length= {}".format(dis_geturl_headers_stream.headers['Content-Length']))
    print("dis_geturl_headers_stream Content-Range= {}".format(dis_geturl_headers_stream.headers['Content-Range']))

返回:
在这里插入图片描述

总结

既要获取到 oss1 的content-length 也要获取到 oss2 带有鉴权的url静态资源信息 只能通过get 指定header 的range 让服务器返回 content-range 来对比了

如果需要转载请注明出处
如果有说的不对的地方或 有更好的实现方式,欢迎拍砖🧐 和 赐教😊

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值