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.

5voto

Kaushal Points 409

Oui, sans aucun doute, requests est un excellent paquetage à utiliser dans quelque chose lié aux requêtes HTTP. Mais nous devons également faire attention au type d'encodage des données entrantes. Voici un exemple qui explique la différence

from requests import get

# case when the response is byte array
url = 'some_image_url'

response = get(url)
with open('output', 'wb') as file:
    file.write(response.content)

# case when the response is text
# Here unlikely if the reponse content is of type **iso-8859-1** we will have to override the response encoding
url = 'some_page_url'

response = get(url)
# override encoding by real educated guess as provided by chardet
r.encoding = r.apparent_encoding

with open('output', 'w', encoding='utf-8') as file:
    file.write(response.content)

0voto

Carson Arucard Points 334

Motivation

Parfois, nous voulons obtenir l'image sans avoir besoin de la télécharger dans des fichiers réels,

c'est-à-dire, télécharger les données et les garder en mémoire.

Par exemple, si j'utilise la méthode d'apprentissage automatique, former un modèle qui peut reconnaître une image avec le numéro (code à barres).

Lorsque je parcours des sites web qui contiennent ces images, je peux utiliser le modèle pour les reconnaître,

et je ne veux pas sauvegarder ces photos sur mon disque dur,

alors vous pouvez essayer la méthode ci-dessous pour vous aider à garder les données de téléchargement en mémoire.

Points

import requests
from io import BytesIO
response = requests.get(url)
with BytesIO as io_obj:
    for chunk in response.iter_content(chunk_size=4096):
        io_obj.write(chunk)

fondamentalement, est comme à @Ranvijay Kumar

Un exemple

import requests
from typing import NewType, TypeVar
from io import StringIO, BytesIO
import matplotlib.pyplot as plt
import imageio

URL = NewType('URL', str)
T_IO = TypeVar('T_IO', StringIO, BytesIO)

def download_and_keep_on_memory(url: URL, headers=None, timeout=None, **option) -> T_IO:
    chunk_size = option.get('chunk_size', 4096)  # default 4KB
    max_size = 1024 ** 2 * option.get('max_size', -1)  # MB, default will ignore.
    response = requests.get(url, headers=headers, timeout=timeout)
    if response.status_code != 200:
        raise requests.ConnectionError(f'{response.status_code}')

    instance_io = StringIO if isinstance(next(response.iter_content(chunk_size=1)), str) else BytesIO
    io_obj = instance_io()
    cur_size = 0
    for chunk in response.iter_content(chunk_size=chunk_size):
        cur_size += chunk_size
        if 0 < max_size < cur_size:
            break
        io_obj.write(chunk)
    io_obj.seek(0)
    """ save it to real file.
    with open('temp.png', mode='wb') as out_f:
        out_f.write(io_obj.read())
    """
    return io_obj

def main():
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7',
        'Cache-Control': 'max-age=0',
        'Connection': 'keep-alive',
        'Host': 'statics.591.com.tw',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'
    }
    io_img = download_and_keep_on_memory(URL('http://statics.591.com.tw/tools/showPhone.php?info_data=rLsGZe4U%2FbphHOimi2PT%2FhxTPqI&type=rLEFMu4XrrpgEw'),
                                         headers,  # You may need this. Otherwise, some websites will send the 404 error to you.
                                         max_size=4)  # max loading < 4MB
    with io_img:
        plt.rc('axes.spines', top=False, bottom=False, left=False, right=False)
        plt.rc(('xtick', 'ytick'), color=(1, 1, 1, 0))  # same of plt.axis('off')
        plt.imshow(imageio.imread(io_img, as_gray=False, pilmode="RGB"))
        plt.show()

if __name__ == '__main__':
    main()

-2voto

user7726287 Points 11
from urllib import request

def get(url):
    with request.urlopen(url) as r:
        return r.read()

def download(url, file=None):
    if not file:
        file = url.split('/')[-1]
    with open(file, 'wb') as f:
        f.write(get(url))

-7voto

Si vous utilisez Linux, vous pouvez utiliser l'option wget de Linux par le biais du shell python. Voici un exemple d'extrait de code

import os
url = 'http://www.example.com/foo.zip'
os.system('wget %s'%url)

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