如何确定在Python中使用HTTP下载的内容的文件名?

das*_*s-g 14 python content-disposition http-headers python-requests

我使用getPython requests库的功能下载文件.为了存储文件,我想确定Web浏览器用于"保存"或"另存为..."对话框的文件名.

容易,对吗?我可以Content-Disposition HTTP头中获取它,可以在响应对象上访问:

import re
d = r.headers['content-disposition']
fname = re.findall("filename=(.+)", d)
Run Code Online (Sandbox Code Playgroud)

但在这个话题更加密切关注,不在于简单:

根据RFC 6266第4.3节4.1节中的语法,值可以是不带引号的标记(例如the_report.pdf)或带引号的字符串,它也可以包含空格(例如"the report.pdf")和转义序列.进一步,

当"filename"和"filename*"都出现在单个标题字段值中时,[我们]应该选择"filename*"并忽略"filename".

filename*但是,它的价值比那个更复杂filename.

此外,RFC似乎允许额外的空白围绕=.

因此,对于RFC中列出示例,我想要以下结果:

现在,我可以很容易地调整正则表达式来解释周围的变量空格=,但是让它处理所有其他变量也会变得相当笨拙.(通过引用和转义,我甚至不确定RegEx是否可以涵盖所有情况.也许它们可以,因为没有涉及支撑嵌套.)

那么我是否必须实现一个完整的解析器,或者我可以根据RFC 6266通过对HTTP库(可能requests本身)的一些调用来确定文件名?由于RFC 6266是HTTP标准的一部分,我可以想象一些专门用于HTTP的库已经涵盖了这一点.(所以我也问过软件建议SE.)

Aly*_*sen 10

rfc6266库似乎完全符合您的需求.它可以解析原始标头,requests响应和urllib2响应.它在PyPI上.

一些例子:

>>> import rfc6266, requests
>>> rfc6266.parse_headers('''Attachment; filename=example.html''').filename_unsafe
'example.html'
>>> rfc6266.parse_headers('''INLINE; FILENAME= "an example.html"''').filename_unsafe
'an example.html'
>>> rfc6266.parse_headers(
    '''attachment; '''
    '''filename*= UTF-8''%e2%82%ac%20rates''').filename_unsafe
'€ rates'
>>> rfc6266.parse_headers(
    '''attachment; '''
    '''filename="EURO rates"; '''
    '''filename*=utf-8''%e2%82%ac%20rates''').filename_unsafe
'€ rates'
>>> r = requests.get('http://example.com/€ rates')
>>> rfc6266.parse_requests_response(r).filename_unsafe
'€ rates'
Run Code Online (Sandbox Code Playgroud)

作为一个说明,虽然:这个库并没有像在头非标准空白.


Tim*_*yev 8

到 2022 年,原始答案中推荐的Python 模块rfc6266似乎已被放弃,并且无法真正与较新版本的 Python 一起使用。

好消息是有一个名为Pyrfc6266的替换模块(其中之一,但这个确实有效!)

它可以通过以下方式安装:

pip install pyrfc6266
Run Code Online (Sandbox Code Playgroud)

并使用相同的方式:

import pyrfc6266
pyrfc6266.parse_filename('attachment; filename="foo.html"')
Run Code Online (Sandbox Code Playgroud)

或者

import requests
import pyrfc6266
response = requests.get('http://httpbin.org/response-headers?Content-Disposition=attachment;%20filename%3d%22foo.html%22')
pyrfc6266.requests_response_to_filename(response)
Run Code Online (Sandbox Code Playgroud)