Télécharger des images et d’autres fichiers du web en Python (individuellement ou par lots)

Affaires

Ce qui suit explique comment spécifier l'URL d'une image, d'un ZIP, d'un PDF ou d'un autre fichier sur le Web en Python, le télécharger et l'enregistrer comme fichier local.

  • Téléchargez des images en spécifiant l'URL.
    • Exemple de code
    • urllib.request.urlopen():Ouvrir l'URL
    • open():Écriture dans un fichier en mode binaire
    • Un exemple de code plus simple
  • Téléchargez des fichiers ZIP, des fichiers PDF, etc.
  • Extraire l'URL de l'image sur la page web.
    • Si le numéro est séquentiel
    • Extrait avec Beautiful Soup
  • Téléchargement par lots de plusieurs images à partir d'une liste d'URL

Téléchargez des images en spécifiant l'URL.

Vous pouvez utiliser la bibliothèque standard uniquement pour télécharger des fichiers individuels en spécifiant leur URL ; aucune installation supplémentaire n'est requise.

Exemple de code

Voici un exemple d'une fonction qui télécharge et enregistre un fichier en spécifiant l'URL et le chemin de destination, ainsi que son utilisation. Ce code est un peu verbeux dans un souci d'explication. Un exemple simple est donné ci-dessous.

import os
import pprint
import time
import urllib.error
import urllib.request

def download_file(url, dst_path):
    try:
        with urllib.request.urlopen(url) as web_file:
            data = web_file.read()
            with open(dst_path, mode='wb') as local_file:
                local_file.write(data)
    except urllib.error.URLError as e:
        print(e)
url = 'https://www.python.org/static/img/python-logo.png'
dst_path = 'data/temp/py-logo.png'
download_file(url, dst_path)

Pour spécifier le répertoire de destination et enregistrer le fichier avec le nom de fichier URL, procédez comme suit

def download_file_to_dir(url, dst_dir):
    download_file(url, os.path.join(dst_dir, os.path.basename(url)))

dst_dir = 'data/temp'
download_file_to_dir(url, dst_dir)

Il extrait le nom du fichier de l'URL avec os.path.basename() et le joint au répertoire spécifié avec os.path.join() pour générer le chemin de destination.

Les sections suivantes décrivent la partie de l'acquisition des données et la partie de l'enregistrement des données dans un fichier.

urllib.request.urlopen(): Ouvrir l'URL

Utilisez urllib.request.urlopen() pour ouvrir l'URL et récupérer les données. Notez que urllib.urlopen() a été déprécié dans Python 2.6 et antérieurs. urllib.request.urlretrieve() n'a pas encore été déprécié, mais pourrait l'être dans le futur.

Pour éviter de s'arrêter lorsqu'une exception se produit, attrapez l'erreur avec try et except.

Dans l'exemple, urllib.error est importé et seul urllib.error.URLError est explicitement capturé. Le message d'erreur sera affiché lorsque l'URL du fichier n'existe pas.

url_error = 'https://www.python.org/static/img/python-logo_xxx.png'
download_file_to_dir(url_error, dst_dir)
# HTTP Error 404: Not Found

Si vous voulez également attraper les exceptions (FileNotFoundError, etc.) lors de l'enregistrement local, procédez comme suit.
(urllib.error.URLError, FileNotFoundError)

Il est également possible d'utiliser la bibliothèque tierce Requests au lieu de la bibliothèque standard urllib pour ouvrir l'url et obtenir les données.

Écriture dans un fichier en mode binaire dans open()

Les données qui peuvent être obtenues avec urllib.request.urlopen() sont une chaîne d'octets (type bytes).

Open() avec mode='wb' comme deuxième argument écrit les données en binaire. w signifie écrire et b signifie binaire.

Un exemple de code plus simple

Les instructions imbriquées avec peuvent être écrites en une seule fois, séparées par des virgules.

En utilisant ceci, nous pouvons écrire ce qui suit.

def download_file(url, dst_path):
    try:
        with urllib.request.urlopen(url) as web_file, open(dst_path, 'wb') as local_file:
            local_file.write(web_file.read())
    except urllib.error.URLError as e:
        print(e)

Téléchargez des fichiers ZIP, des fichiers PDF, etc.

Les exemples présentés jusqu'à présent concernent le téléchargement et l'enregistrement de fichiers image, mais comme nous ouvrons simplement un fichier sur le web et l'enregistrons en tant que fichier local, les mêmes fonctions peuvent être utilisées pour d'autres types de fichiers.

Vous pouvez télécharger et enregistrer des fichiers en spécifiant l'URL.

url_zip = 'https://from-locas.com/sample_header.csv.zip'
download_file_to_dir(url_zip, dst_dir)

url_xlsx = 'https://from-locas/sample.xlsx'
download_file_to_dir(url_xlsx, dst_dir)

url_pdf = 'https://from-locas/sample1.pdf'
download_file_to_dir(url_pdf, dst_dir)

Notez que l'URL spécifié dans cette fonction doit être un lien vers le fichier lui-même.

Par exemple, dans le cas d'un fichier de dépôt GitHub, l'URL suivante a une extension pdf mais est en fait une page html. Si cette URL est spécifiée dans la fonction ci-dessus, la source html sera téléchargée.

  • https://github.com/from-locals/python-snippets/blob/master/notebook/data/src/pdf/sample1.pdf

Le lien vers l'entité fichier est l'URL suivante, que vous devez spécifier si vous voulez télécharger et enregistrer le fichier.

  • https://github.com/from-locals/python-snippets/raw/master/notebook/data/src/pdf/sample1.pdf

Il existe également des cas où l'accès est restreint par l'agent utilisateur, le référent, etc., ce qui rend le téléchargement impossible. Nous ne garantissons pas que tous les fichiers seront téléchargés.

Il est facile d'utiliser Requests pour modifier ou ajouter des en-têtes de demande tels que l'agent utilisateur.

Extraire l'URL de l'image sur la page web.

Pour télécharger toutes les images d'une page en une seule fois, commencez par extraire les URL des images et créez une liste.

Si le numéro est séquentiel

Si l'URL de l'image que vous voulez télécharger est un simple numéro séquentiel, c'est facile. Si les URL ne sont pas seulement des nombres séquentiels mais présentent aussi une certaine régularité, il est plus facile de faire une liste d'URLs selon les règles plutôt que de faire du scraping avec Beautiful Soup (voir ci-dessous).

Utilisez la notation de compréhension de liste.

url_list = ['https://example.com/basedir/base_{:03}.jpg'.format(i) for i in range(5)]
pprint.pprint(url_list)
# ['https://example.com/basedir/base_000.jpg',
#  'https://example.com/basedir/base_001.jpg',
#  'https://example.com/basedir/base_002.jpg',
#  'https://example.com/basedir/base_003.jpg',
#  'https://example.com/basedir/base_004.jpg']

Dans l'exemple ci-dessus, {:03} est utilisé pour un numéro séquentiel à 3 chiffres rempli de zéros ; {} est utilisé lorsque le remplissage de zéros n'est pas nécessaire, et {:05} est utilisé pour un numéro à 5 chiffres au lieu de 3 chiffres. Pour plus d'informations sur la méthode de formatage de string str, voir l'article suivant.

De plus, nous utilisons ici pprint pour rendre la sortie plus facile à lire.

Extrait avec Beautiful Soup

Pour extraire en masse les URL des images des pages Web, utilisez Beautiful Soup.

import os
import time
import urllib.error
import urllib.request

from bs4 import BeautifulSoup

url = 'https://fr.from-locals.com/'
ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) '\
     'AppleWebKit/537.36 (KHTML, like Gecko) '\
     'Chrome/55.0.2883.95 Safari/537.36 '

req = urllib.request.Request(url, headers={'User-Agent': ua})
html = urllib.request.urlopen(req)

soup = BeautifulSoup(html, "html.parser")

url_list = [img.get('data-src') for img in soup.find(class_='list').find_all('img')]

Dans l'exemple, l'URL de l'image miniature de ce site web est extraite.

La structure varie en fonction de la page web, mais fondamentalement, elle s'obtient comme suit.

  • Obtenez une liste d'objets de la balise <img> en spécifiant la classe, l'id, etc. du bloc contenant les multiples images que vous voulez télécharger.
    • soup.find(class_='list').find_all('img')
  • Obtenez l'URL de l'image à partir de l'élément src ou de l'élément data-src de la balise <img>.
    • img.get('data-src')

L'exemple de code ci-dessus n'est qu'un exemple et son fonctionnement n'est pas garanti.

Téléchargement par lots de plusieurs images à partir d'une liste d'URL

Si vous avez une liste d'URL, vous pouvez simplement la transformer en une boucle for et appeler la fonction pour télécharger et enregistrer le fichier avec la première URL affichée. En raison de la liste temporaire d'URL, l'appel de la fonction download_image_dir() est commenté ici.

download_dir = 'data/temp'
sleep_time_sec = 1

for url in url_list:
    print(url)
#     download_file_dir(url, download_dir)
    time.sleep(sleep_time_sec)
# https://example.com/basedir/base_000.jpg
# https://example.com/basedir/base_001.jpg
# https://example.com/basedir/base_002.jpg
# https://example.com/basedir/base_003.jpg
# https://example.com/basedir/base_004.jpg

Afin de ne pas surcharger le serveur, j'utilise time.sleep() pour créer un temps d'attente pour chaque téléchargement d'image. L'unité est en secondes, donc dans l'exemple ci-dessus, le module time est importé et utilisé.

L'exemple concerne les fichiers d'images, mais d'autres types de fichiers peuvent également être téléchargés ensemble, pour autant qu'ils soient répertoriés.

Copied title and URL