Laden Sie die PDF-Datei mit dem Python-Anforderungsmodul herunter und speichern Sie sie

85

Ich versuche, eine PDF-Datei von einer Website herunterzuladen und auf der Festplatte zu speichern. Meine Versuche schlagen entweder mit Codierungsfehlern fehl oder führen zu leeren PDFs.

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)
   ...: 

Ich weiß, dass es sich um ein Codec-Problem handelt, aber ich kann es scheinbar nicht zum Laufen bringen.

Jim
quelle

Antworten:

171

Sie sollten response.contentin diesem Fall verwenden:

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

Aus dem Dokument :

Sie können für Nicht-Text-Anforderungen auch als Bytes auf den Antworttext zugreifen:

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

Das bedeutet also: response.textGeben Sie die Ausgabe als Zeichenfolgenobjekt zurück und verwenden Sie sie, wenn Sie eine Textdatei herunterladen . Wie HTML-Datei usw.

Und response.contentgeben Sie die Ausgabe als Byte-Objekt zurück. Verwenden Sie sie, wenn Sie eine Binärdatei herunterladen . Wie PDF-Datei, Audiodatei, Bild usw.


Sie können response.rawstattdessen auch verwenden . Verwenden Sie es jedoch, wenn die Datei, die Sie herunterladen möchten, groß ist. Unten finden Sie ein grundlegendes Beispiel, das Sie auch im Dokument finden können:

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_sizeist die Blockgröße, die Sie verwenden möchten. Wenn Sie es als festlegen 2000, laden Anforderungen diese Datei mit den ersten 2000Bytes herunter , schreiben sie in die Datei und tun dies immer wieder, es sei denn, sie ist abgeschlossen.

So können Sie Ihren RAM sparen. response.contentIn diesem Fall würde ich jedoch lieber verwenden, da Ihre Datei klein ist. Wie Sie sehen können, response.rawist die Verwendung komplex.


Verwandte:

Casimir Kristall
quelle
Cool, danke für die zusätzlichen Informationen zu response.raw.
Jim
22

In Python 3 finde ich, dass Pathlib der einfachste Weg ist, dies zu tun. Die Antwort von Request.content passt gut zu pathlibs 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)
user6481870
quelle
1
Vielen Dank für die Veröffentlichung. Die ursprüngliche Frage war Python 2.7, aber ich bin weitergegangen und verwende jetzt Python 3. Ich wusste nichts über die Pathlib-Bibliothek [neu in Version 3.4] und werde sie in meine aktuellen Projekte integrieren.
Jim
Es gibt 544und die Datei ist kaputt, irgendwelche Ideen?
Ahbon
@ahbon, was meinst du?
user6481870
13

Sie können urllib verwenden:

import urllib.request
urllib.request.urlretrieve(url, "filename.pdf")
jugi
quelle
Das ist das Beste, tbh.
Dhaval Savalia
Dieser ist am besten
roktim
urlretrievestützt sich auf globale Einstellungen, um Anforderungsheader zu bestimmen, was es für einige Anwendungsfälle ungeeignet macht.
Michael Crenshaw
5

Im Allgemeinen sollte dies in Python3 funktionieren:

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

Denken Sie daran, dass urllib und urllib2 nach Python2 nicht richtig funktionieren.

Wenn in einigen mysteriösen Fällen Anfragen nicht funktionieren (ist bei mir passiert), können Sie auch versuchen, sie zu verwenden

wget.download(url)

Verbunden:

Hier ist eine anständige Erklärung / Lösung, um alle PDF-Dateien auf einer Webseite zu finden und herunterzuladen:

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

x89
quelle
2

Bitte beachten Sie, dass ich ein Anfänger bin. Wenn meine Lösung falsch ist, können Sie sie gerne korrigieren und / oder mich informieren. Ich kann auch etwas Neues lernen.

Meine Lösung:

Ändern Sie den DownloadPath entsprechend an den Ort, an dem Ihre Datei gespeichert werden soll. Fühlen Sie sich frei, den absoluten Pfad auch für Ihre Verwendung zu verwenden.

Speichern Sie das Folgende als downloadFile.py.

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

Denken Sie daran, eine Erweiterung hinzuzufügen!

Anwendungsbeispiel: 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...')
Ente Ling
quelle
Pawel, danke für deine Antwort. Ich war ein Python-Neuling, als ich diese Frage zum ersten Mal stellte. Jetzt kenne ich die Sprache sehr gut. Ihr Anwendungsfall, ein Python-Skript zum Herunterladen einer Datei von einer Befehlszeile zu schreiben, kann von Dienstprogrammen wie wget oder curl abgedeckt werden. Außerdem scheint sich Ihre Funktion downloadFile wie veröffentlicht selbst aufzurufen. Wollten Sie den zweiten Codeblock einrücken? Im Stackoverflow können Sie dies korrigieren, indem Sie dies überbieten. Ich möchte auch vorschlagen, dass Sie sich Pythons Argparse-Bibliothek ansehen. Sie können es verwenden, um nette Befehlszeilenprogramme zu erstellen. Es kümmert sich um die Parameter für Sie.
Jim
Ich mag Ihre Verwendung eines Kontextmanagers (mit open ... als Datei:, usw.), um das Schreiben von Dateien zu handhaben. Ihr Code ist ordentlich geschrieben. Sie sind auf einem guten Weg, um Python zu lernen. Viel Glück!
Jim
1
Danke für die Antwort, @Jim! Ich habe den Beitrag bearbeitet und tatsächlich nicht "beabsichtigt einzurücken": D den Hauptteil des Programms. Vielen Dank für Ihre Ratschläge! :)
Ente Ling
-5

In Bezug auf die Antwort von Kevin, in einen Ordner zu schreiben tmp, sollte es so sein:

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

er hat .vor der adresse vergessen und natürlich sollte dein ordner tmpschon angelegt sein

Nima Sajedi
quelle
5
1- Kevin hatte nicht die Idee zu schreiben tmp, es war wie in der Frage von OP. 2- Das /tmpVerzeichnis ist der tmp in Unix-Systemen, befindet sich unter /tmp, no.
realUser404