使用Python请求模块下载并保存PDF文件


85

我正在尝试从网站下载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)
   ...: 

我知道这是某种编解码器问题,但我似乎无法使其正常工作。

Answers:


171

response.content在这种情况下,您应该使用:

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

文件

对于非文本请求,您还可以字节形式访问响应主体:

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

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

response.content以字节对象返回输出,在下载二进制文件时使用它。如PDF文件,音频文件,图像等。


您还可以使用response.raw代替。但是,当您要下载的文件很大时,请使用它。以下是一个基本示例,您也可以在文档中找到该示例:

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,则请求将下载该文件的第一个2000字节,将其写入文件,然后一次又一次地执行,除非完成。

这样可以节省您的RAM。但是response.content在这种情况下,我宁愿使用它,因为您的文件很小。如您所见,使用response.raw非常复杂。


关联:


太好了,谢谢您提供有关response.raw的其他信息。
吉姆(Jim)

22

在Python 3中,我发现pathlib是执行此操作的最简单方法。请求的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)

1
感谢您发布此信息。最初的问题是Python 2.7,但我继续前进,现在使用Python3。我不了解pathlib库(3.4版中的新功能),并将其合并到当前项目中。
吉姆(Jim)

它给544和文件坏了,有什么想法吗?
艾本

@ahbon,你是什么意思?
user6481870

13

您可以使用urllib:

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

这是最好的,TBH。
Dhaval Savalia

这是最好的
roktim

urlretrieve依赖于全局设置来确定请求标头,使其不适用于某些用例。
迈克尔·克伦肖


2

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

我的解决方案:

相应将downloadPath更改为要保存文件的位置。您也可以随意使用绝对路径。

将以下内容另存为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 ...作为file:等)来处理文件写入。您的代码编写整齐。您正在学习Python的良好道路上。祝好运!
吉姆

1
感谢您的回复,@ Jim!我已经编辑了帖子,实际上我并没有“打算缩进”:D程序的主要部分。感谢您的建议!:)
Duck Ling

-5

关于Kevin将答案写在一个文件夹中tmp,应该是这样的:

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

他忘了.在地址和路线之前tmp应该已经创建了您的文件夹


5
1-凯文(Kevin)没有想出要写的想法tmp,就像在OP的问题中一样。2-/tmp目录是Unix系统中的tmp,位于/tmp,否.
realUser404 '17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.