使用 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 文件的主要内容,如果未能解决你的问题,请参考以下文章

用python实现csdn博主全部博文下载,html转pdf,有了学习的电子书了。。。(附源码)

python下载日语语法并保存为pdf

Python监控进程性能数据并画图保存为PDF文档

用PDFMiner从PDF中提取文本文字

无法使用 python 请求下载 pdf

在 chrome 中自动打印/保存网页为 pdf - python 2.7