使用 Python 请求模块下载并保存 PDF 文件
Posted
技术标签:
【中文标题】使用 Python 请求模块下载并保存 PDF 文件【英文标题】:Download and save PDF file with Python requests module 【发布时间】: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)
...:
我知道这是某种编解码器问题,但我似乎无法让它工作。
【问题讨论】:
【参考方案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
很复杂。
相关:
How to download large file in python with requests.py?
How to download image using requests
【讨论】:
酷,感谢您提供有关 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 似乎自称。您是否打算缩进第二个代码块?在 *** 中,您可以通过突出它来纠正它。我还想建议您看看 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
,没有.
以上是关于使用 Python 请求模块下载并保存 PDF 文件的主要内容,如果未能解决你的问题,请参考以下文章