【问题标题】:How to get pdf filename with Python requests?如何使用 Python 请求获取 pdf 文件名?
【发布时间】:2015-10-26 14:14:43
【问题描述】:

我正在使用 Python requests lib 从网上获取 PDF 文件。这很好用,但我现在也想要原始文件名。如果我在 Firefox 中转到 PDF 文件并单击 download,它已经定义了一个文件名来保存 pdf。我如何获得这个文件名?

例如:

import requests
r = requests.get('http://www.researchgate.net/profile/M_Gotic/publication/260197848_Mater_Sci_Eng_B47_%281997%29_33/links/0c9605301e48beda0f000000.pdf')
print r.headers['content-type']  # prints 'application/pdf'

我检查了r.headers 是否有任何有趣的内容,但其中没有文件名。我实际上希望像r.filename..

有人知道我如何使用请求库获取下载的 PDF 文件的文件名吗?

【问题讨论】:

  • 有趣——我本来想说,“好吧显然 0c9605301e48beda0f000000.pdf”(正如请求中的那样)但幸运的是我决定先测试它。并且 FireFox 想将其保存为“Mater Sci Eng B47 (1997) 33.pdf”。
  • 你如何检查标题?文件名那里,content-disposition : inline; filename="Mater Sci Eng B47 (1997) 33.pdf"。 FWIW,许多 PDF 都嵌入了 Title,但不是全部,如果 PDF 是二进制形式,可能不容易访问。

标签: python pdf python-requests filenames


【解决方案1】:

从 Content-Disposition 获取文件名的简单 python3 实现:

import requests
response = requests.get(<your-url>)
print(response.headers.get("Content-Disposition").split("filename=")[1])

【讨论】:

  • 小心,以防没有“Content-Disposition”标头!
【解决方案2】:

在其他一些答案的基础上,这就是我的做法。如果没有Content-Disposition 标头,我从下载地址解析:

import re
import requests
from requests.exceptions import RequestException


url = 'http://www.example.com/downloads/sample.pdf'

try:
    with requests.get(url) as r:

        fname = ''
        if "Content-Disposition" in r.headers.keys():
            fname = re.findall("filename=(.+)", r.headers["Content-Disposition"])[0]
        else:
            fname = url.split("/")[-1]

        print(fname)
except RequestException as e:
    print(e)

可以说有更好的解析 URL 字符串的方法,但为了简单起见,我不想再涉及任何库。

【讨论】:

  • 我建议在 else 子句中调用urllib.parse.unquote,这样你就不会在文件名中得到%20s。
【解决方案3】:

在 http 标头 content-disposition 中指定。所以要提取你会做的名字:

import re
d = r.headers['content-disposition']
fname = re.findall("filename=(.+)", d)[0]

通过正则表达式从字符串中提取的名称(re 模块)。

【讨论】:

  • 如果文件名编码为 utf8,这将不起作用。有什么建议吗?
  • findall 返回匹配列表。你需要这样的索引fname = re.findall("filename=(.+)", d)[0]
  • 这个不完整,文件名可以用引号括起来。
  • @Michael-O 尝试使用"filename=\"(.+)\"" 删除引号
  • 只是一个侧面案例,有时标题中未提供预期的文件名,尤其是社交媒体 CDN 链接。在这种情况下,您可以制定自己的基本名称(也许解析您想要使用的根文件名的 url),然后确定正确的扩展名以用作类似 resp.headers['Content-Type'].split('/')[-1] 的后缀。
【解决方案4】:

您可以将werkzeug 用于选项标题https://werkzeug.palletsprojects.com/en/0.15.x/http/#werkzeug.http.parse_options_header

>>> import werkzeug


>>> werkzeug.parse_options_header('text/html; charset=utf8')
('text/html', {'charset': 'utf8'})

【讨论】:

  • 这是最强大的选项,因为它删除了可选引号。
【解决方案5】:

显然,对于这个特定的资源,它位于:

r.headers['content-disposition']

不知道是否总是这样。

【讨论】:

  • 并非所有响应都包含“content-disposition”标头,但根据其中一个 cmets,它们似乎在这种情况下可用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多