Pythonリクエストモジュールを使用してPDFファイルをダウンロードして保存します


87

Webサイトから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)
   ...: 

ある種のコーデックの問題であることは知っていますが、機能させることができないようです。

回答:


176

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に関する追加情報をありがとう。
ジム

23

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)

1
これを投稿していただきありがとうございます。元の質問はPython2.7でしたが、次に進んでPython 3を使用します。pathlibライブラリ[バージョン3.4の新機能]について知らなかったので、現在のプロジェクトに組み込みます。
ジム

それは与え544、ファイルは壊れています、何かアイデアはありますか?
ahbon

@ahbon、どういう意味ですか?
user64818 7020年

14

urllibを使用できます:

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

1
これは最高です、tbh。
DhavalSavalia19年

この1は最高です
roktim

1
urlretrieveグローバル設定に依存してリクエストヘッダーを決定するため、一部のユースケースには適していません。
MichaelCrenshaw20年

5

通常、これはPython3で機能するはずです。

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

Python2以降はurllibとurllib2が正しく機能しないことに注意してください。

不思議なケースでリクエストが機能しない場合(私と一緒に起こった)、使用してみることもできます

wget.download(url)

関連:

Webページ上のすべてのPDFファイルを見つけてダウンロードするための適切な説明/解決策は次のとおりです。

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


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の初心者でした。今、私はその言語をとてもよく知っています。コマンドラインからファイルをダウンロードするPythonスクリプトを作成するユースケースは、wgetやcurlなどのユーティリティでカバーできます。また、投稿された関数downloadFileはそれ自体を呼び出しているようです。コードの2番目のブロックをインデントするつもりでしたか?stackoverflowでは、それをアウトデントすることで修正できます。また、Pythonのargparseライブラリをご覧になることをお勧めします。これを使用して、優れたコマンドラインユーティリティを作成できます。それはあなたのためにパラメータの世話をします。
ジム

私は、ファイルの書き込みを処理するためにコンテキストマネージャー(open ... as file:など)を使用するのが好きです。あなたのコードはきちんと書かれています。あなたはPythonを学ぶための良い道を進んでいます。幸運を!
ジム

1
返信ありがとう、@ Jim!私は投稿を編集しましたが、実際、プログラムの主要部分を「インデントするつもりはありませんでした」:D。アドバイスありがとうございます!:)
陵ダック

-4

フォルダーに書き込むためのKevinの回答に関してtmpは、次のようになります。

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

.はアドレスの前に忘れていました、そしてもちろんあなたのフォルダtmpはすでに作成されているはずです


5
1-ケビンは書くという考えを思いつきませんでしたtmp、それはOPの質問のようでした。2-/tmpディレクトリはUnixシステムのtmpであり/tmp、no.
realUser404 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.