【问题标题】:Download and save PDF file with Python requests module使用 Python 请求模块下载并保存 PDF 文件
【发布时间】:2016-04-02 21:16:49
【问题描述】:

我正在尝试从网站下载 PDF 文件并将其保存到磁盘。我的尝试要么因编码错误而失败,要么导致 PDF 为空白。

In [1]: import requests

In [2]: url = 'http://www.hrecos.org//images/Data/forweb/HRTVBSH.Metadata.pdf'

In [3]: response = requests.get(url)

In [4]: with open('/tmp/metadata.pdf', 'wb') as f:
   ...:     f.write(response.text)
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-4-4be915a4f032> in <module>()
      1 with open('/tmp/metadata.pdf', 'wb') as f:
----> 2     f.write(response.text)
      3 

UnicodeEncodeError: 'ascii' codec can't encode characters in position 11-14: ordinal not in range(128)

In [5]: import codecs

In [6]: with codecs.open('/tmp/metadata.pdf', 'wb', encoding='utf8') as f:
   ...:     f.write(response.text)
   ...: 

我知道这是某种编解码器问题,但我似乎无法让它工作。

【问题讨论】:

    标签: python python-2.7 python-requests


    【解决方案1】:

    在这种情况下你应该使用response.content

    with open('/tmp/metadata.pdf', 'wb') as f:
        f.write(response.content)
    

    来自the document

    对于非文本请求,您还可以按字节访问响应正文:

    >>> r.content
    b'[{"repository":{"open_issues":0,"url":"https://github.com/...
    

    这意味着:response.text 将输出作为字符串对象返回,在下载文本文件时使用它。如HTML文件等

    并且response.content 将输出作为字节对象返回,在您下载二进制文件时使用它。如PDF文件、音频文件、图片等


    You can also use response.raw instead。但是,当您要下载的文件很大时使用它。下面是一个基本示例,您也可以在文档中找到它:

    import requests
    
    url = 'http://www.hrecos.org//images/Data/forweb/HRTVBSH.Metadata.pdf'
    r = requests.get(url, stream=True)
    
    with open('/tmp/metadata.pdf', 'wb') as fd:
        for chunk in r.iter_content(chunk_size):
            fd.write(chunk)
    

    chunk_size 是您要使用的块大小。如果您将其设置为 2000,则 requests 将下载该文件的第一个 2000 字节,将它们写入文件中,然后一遍又一遍地执行此操作,除非完成。

    所以这可以节省您的 RAM。但在这种情况下,我更喜欢使用response.content,因为您的文件很小。如您所见,使用response.raw 很复杂。


    相关:

    【讨论】:

    • 酷,感谢您提供有关 response.raw 的更多信息。
    【解决方案2】:

    在 Python 3 中,我发现 pathlib 是最简单的方法。 Request 的 response.content 与 pathlib 的 write_bytes 完美结合。

    from pathlib import Path
    import requests
    filename = Path('metadata.pdf')
    url = 'http://www.hrecos.org//images/Data/forweb/HRTVBSH.Metadata.pdf'
    response = requests.get(url)
    filename.write_bytes(response.content)
    

    【讨论】:

    • 感谢您发布此信息。最初的问题是 Python 2.7,但我已经继续前进,现在使用 Python 3。我不知道 pathlib 库 [3.4 版中的新内容],并将其合并到我当前的项目中。
    • 它给了544,文件坏了,有什么想法吗?
    • @ahbon,你是什么意思?
    • 也许这是我的眼睛,但在我看来,您甚至没有使用您推荐的 pathlib 设置的变量“文件名”
    【解决方案3】:

    你可以使用urllib:

    import urllib.request
    urllib.request.urlretrieve(url, "filename.pdf")
    

    【讨论】:

    • 这是最好的,tbh。
    • 这个最好
    • urlretrieve 依赖全局设置来确定请求标头,因此不适合某些用例。
    • 这个真的不错。要记住的一件事是,如果没有headers,它可能会引发 403 错误。为了避免这种情况,pass user-agent into headers.
    【解决方案4】:

    一般来说,这应该在 Python3 中工作:

    import urllib.request 
    ..
    urllib.request.get(url)
    

    记住 urllib 和 urllib2 在 Python2 之后不能正常工作。

    如果在某些神秘的情况下请求不起作用(发生在我身上),您也可以尝试使用

    wget.download(url)
    

    相关:

    这是在网页上查找和下载所有 pdf 文件的一个不错的解释/解决方案:

    https://medium.com/@dementorwriter/notesdownloader-use-web-scraping-to-download-all-pdfs-with-python-511ea9f55e48

    【讨论】:

      【解决方案5】:

      请注意我是初学者。如果我的解决方案有误,请随时纠正和/或让我知道。我也可以学到一些新东西。

      我的解决方案:

      将下载路径相应地更改到您希望保存文件的位置。也可以随意使用绝对路径供您使用。

      将以下内容另存为downloadFile.py。

      用法:python downloadFile.py url-of-the-file-to-download new-file-name.extension

      记得添加扩展!

      用法示例:python downloadFile.py http://www.google.co.uk google.html

      import requests
      import sys
      import os
      
      def downloadFile(url, fileName):
          with open(fileName, "wb") as file:
              response = requests.get(url)
              file.write(response.content)
      
      
      scriptPath = sys.path[0]
      downloadPath = os.path.join(scriptPath, '../Downloads/')
      url = sys.argv[1]
      fileName = sys.argv[2]      
      print('path of the script: ' + scriptPath)
      print('downloading file to: ' + downloadPath)
      downloadFile(url, downloadPath + fileName)
      print('file downloaded...')
      print('exiting program...')
      

      【讨论】:

      • 帕维尔,谢谢您的回答。当我第一次发布这个问题时,我是一名 Python 新手。现在我非常了解这种语言。 wget 或 curl 等实用程序可以涵盖编写 Python 脚本以从命令行下载文件的用例。此外,您发布的函数 downloadFile 似乎自称。您是否打算缩进第二个代码块?在 stackoverflow 中,您可以通过突出它来纠正它。我还想建议您看看 Python 的 argparse 库。您可以使用它来制作漂亮的命令行实用程序。它将为您处理参数。
      • 我确实喜欢您使用上下文管理器(使用 open... 作为文件:等)来处理文件写入。你的代码写得很整齐。你正走在学习 Python 的好道路上。祝你好运!
      • 感谢@Jim 的回复!我已经编辑了帖子,实际上我并没有“打算缩进”:D 程序的主要部分。感谢您的建议! :)
      【解决方案6】:

      关于Kevin回答写在文件夹tmp,应该是这样的:

      with open('./tmp/metadata.pdf', 'wb') as f:
          f.write(response.content)
      

      他在地址之前忘记了.,当然你的文件夹tmp应该已经创建了

      【讨论】:

      • 1- Kevin 没有想出写在tmp 中的想法,就像在 OP 的问题中一样。 2-/tmp目录是Unix系统中的tmp,位于/tmp,没有.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-30
      • 1970-01-01
      • 2021-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多