J'essaie de télécharger un fichier PDF à partir d'un site Web et de l'enregistrer sur le disque. Mes tentatives échouent avec des erreurs de codage ou donnent des fichiers PDF vierges.
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)
...:
Je sais que c'est un problème de codec mais je n'arrive pas à le faire fonctionner.
Vous devez utiliser response.content
dans ce cas:
with open('/tmp/metadata.pdf', 'wb') as f:
f.write(response.content)
De le document :
Vous pouvez également accéder au corps de la réponse sous forme d'octets, pour les requêtes non textuelles:
>>> r.content b'[{"repository":{"open_issues":0,"url":"https://github.com/...
Cela signifie donc que: response.text
renvoie le résultat sous forme d'objet chaîne, utilisez-le lorsque vous téléchargez un fichier texte . Tels qu'un fichier HTML, etc.
Et response.content
renvoie la sortie sous forme d'objet octets, utilisez-la lorsque vous téléchargez un fichier binaire . Tels que fichier PDF, fichier audio, image, etc.
Vous pouvez aussi utiliser response.raw
à la place . Cependant, utilisez-le lorsque le fichier que vous êtes sur le point de télécharger est volumineux. Voici un exemple de base que vous pouvez également trouver dans le document:
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
est la taille de bloc que vous souhaitez utiliser. Si vous le définissez comme 2000
, les requêtes téléchargeront alors les premiers 2000
octets de ce fichier, les écriront dans le fichier et le feront encore et encore, à moins que l'opération ne soit terminée.
Donc, cela peut économiser votre RAM. Mais je préférerais utiliser response.content
à la place dans ce cas car votre fichier est petit. Comme vous pouvez le voir, l'utilisation de response.raw
est complexe.
Relates:
Dans Python 3, je trouve que pathlib est le moyen le plus simple de le faire. La demande response.content se marie bien avec _write_bytes_ de pathlib.
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)
S'il vous plaît noter que je suis un débutant. Si ma solution est fausse, n'hésitez pas à la corriger et/ou à me le faire savoir. Je peux aussi apprendre quelque chose de nouveau.
Ma solution:
Modifiez le chemin de téléchargement en conséquence à l'emplacement où vous souhaitez que votre fichier soit enregistré. N'hésitez pas à utiliser également le chemin absolu pour votre utilisation.
Enregistrez le fichier ci-dessous sous le nom downloadFile.py.
Utilisation: python downloadFile.py url-of-the-file-to-download new-file-name.extension
N'oubliez pas d'ajouter une extension!
Exemple d'utilisation: 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...')