455 votes

Télécharger un fichier depuis le Web en Python 3

Je suis en train de créer un programme qui téléchargera un fichier .jar (java) à partir d'un serveur web, en lisant l'URL spécifiée dans le fichier .jad du même jeu/application. J'utilise Python 3.2.1.

J'ai réussi à extraire l'URL du fichier JAR du fichier JAD (chaque fichier JAD contient l'URL du fichier JAR), mais comme vous pouvez l'imaginer, la valeur extraite est une chaîne de type().

Voici la fonction concernée :

def downloadFile(URL=None):
    import httplib2
    h = httplib2.Http(".cache")
    resp, content = h.request(URL, "GET")
    return content

downloadFile(URL_from_file)

Cependant, je reçois toujours une erreur disant que le type dans la fonction ci-dessus doit être des octets, et non une chaîne. J'ai essayé d'utiliser URL.encode('utf-8'), et aussi bytes(URL,encoding='utf-8'), mais j'obtiens toujours la même erreur ou une erreur similaire.

En gros, ma question est la suivante : comment télécharger un fichier à partir d'un serveur lorsque l'URL est stockée dans un type de chaîne ?

4 votes

Alvas, une prime pour ça ? La personne qui a répondu est toujours (et plutôt) active sur SO. Pourquoi ne pas simplement ajouter un commentaire et demander ?

9 votes

Car une bonne réponse qui résiste à l'épreuve du temps mérite d'être récompensée. De plus, nous devrions commencer à faire cela pour beaucoup d'autres questions afin de vérifier si les réponses sont pertinentes aujourd'hui. Surtout que le tri des réponses des OS est assez fou, parfois la réponse dépassée ou même la plus mauvaise arrive en tête.

826voto

Oleh Prypin Points 9086

Si vous souhaitez obtenir le contenu d'une page web dans une variable, il vous suffit d'en faire la demande. read la réponse de urllib.request.urlopen :

import urllib.request
...
url = 'http://example.com/'
response = urllib.request.urlopen(url)
data = response.read()      # a `bytes` object
text = data.decode('utf-8') # a `str`; this step can't be used if data is binary

Le moyen le plus simple de télécharger et d'enregistrer un fichier est d'utiliser la fonction urllib.request.urlretrieve fonction :

import urllib.request
...
# Download the file from `url` and save it locally under `file_name`:
urllib.request.urlretrieve(url, file_name)

import urllib.request
...
# Download the file from `url`, save it in a temporary directory and get the
# path to it (e.g. '/tmp/tmpb48zma.txt') in the `file_name` variable:
file_name, headers = urllib.request.urlretrieve(url)

Mais gardez à l'esprit que urlretrieve est considéré héritage et pourrait devenir obsolète (on ne sait pas trop pourquoi, cependant).

Donc le plus correct La façon de procéder serait d'utiliser l'option urllib.request.urlopen pour renvoyer un objet de type fichier qui représente une réponse HTTP et le copier dans un fichier réel à l'aide de la fonction shutil.copyfileobj .

import urllib.request
import shutil
...
# Download the file from `url` and save it locally under `file_name`:
with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    shutil.copyfileobj(response, out_file)

Si cela vous semble trop compliqué, vous pouvez opter pour une solution plus simple et stocker l'ensemble du téléchargement dans un fichier de type bytes puis l'écrire dans un fichier. Mais cela ne fonctionne bien que pour les petits fichiers.

import urllib.request
...
# Download the file from `url` and save it locally under `file_name`:
with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    data = response.read() # a `bytes` object
    out_file.write(data)

Il est possible d'extraire .gz (et peut-être d'autres formats) des données compressées à la volée, mais une telle opération nécessite probablement que le serveur HTTP prenne en charge l'accès aléatoire au fichier.

import urllib.request
import gzip
...
# Read the first 64 bytes of the file inside the .gz archive located at `url`
url = 'http://example.com/something.gz'
with urllib.request.urlopen(url) as response:
    with gzip.GzipFile(fileobj=response) as uncompressed:
        file_header = uncompressed.read(64) # a `bytes` object
        # Or do anything shown above using `uncompressed` instead of `response`.

7 votes

Vous pourriez utiliser response.info().get_param('charset', 'utf-8') au lieu de coder en dur utf-8 pour obtenir l'encodage des caractères à partir de Content-Type en-tête

3 votes

@OlehPrypin Pourquoi est-ce que outfile.write(data) ne fonctionne bien que pour les petits fichiers ?

0 votes

"urlretrieve est considéré comme un héritage et pourrait devenir déprécié" où avez-vous eu cette idée ?

201voto

Ali Faki Points 1515

J'utilise requests chaque fois que je veux quelque chose en rapport avec les requêtes HTTP, car son API est très facile à utiliser :

d'abord, installez requests

$ pip install requests

puis le code :

from requests import get  # to make GET request

def download(url, file_name):
    # open in binary mode
    with open(file_name, "wb") as file:
        # get request
        response = get(url)
        # write to file
        file.write(response.content)

26voto

Ranvijay Kumar Points 301

J'espère avoir bien compris la question, qui est la suivante : comment télécharger un fichier depuis un serveur lorsque l'URL est stockée dans un type de chaîne ?

Je télécharge les fichiers et les enregistre localement en utilisant le code ci-dessous :

import requests

url = 'https://www.python.org/static/img/python-logo.png'
fileName = 'D:\Python\dwnldPythonLogo.png'
req = requests.get(url)
file = open(fileName, 'wb')
for chunk in req.iter_content(100000):
    file.write(chunk)
file.close()

20voto

Lasith Niroshan Points 169

Vous pouvez utiliser wget qui est un outil populaire de téléchargement de shell pour cela. https://pypi.python.org/pypi/wget C'est la méthode la plus simple, car elle ne nécessite pas l'ouverture du fichier de destination. Voici un exemple.

import wget
url = 'https://i1.wp.com/python3.codes/wp-content/uploads/2015/06/Python3-powered.png?fit=650%2C350'  
wget.download(url, '/Users/scott/Downloads/cat4.jpg')

19voto

Yang Yu Points 141

Ici, nous pouvons utiliser l'interface Legacy d'urllib dans Python3 :

Les fonctions et classes suivantes sont portées à partir du module urllib de Python 2 (par opposition à urllib2). Elles peuvent devenir obsolètes à un moment donné dans le futur.

Exemple (2 lignes de code) :

import urllib.request

url = 'https://www.python.org/static/img/python-logo.png'
urllib.request.urlretrieve(url, "logo.png")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X