Baixeu imatges i altres fitxers del web en Python (individualment o per lots)

Negocis

A continuació s’explica com especificar l’URL d’una imatge, ZIP, PDF o un altre fitxer al web en Python, descarregar-lo i desar-lo com a fitxer local.

  • Baixeu imatges especificant l’URL.
    • Exemple de codi
    • urllib.request.urlopen():Obre l’URL
    • open():Escriure en un fitxer en mode binari
    • Un exemple de codi més senzill
  • Descarrega fitxers ZIP, PDF, etc.
  • Extreu l’URL de la imatge a la pàgina web.
    • Si el nombre és seqüencial
    • Extracte amb bella sopa
  • Baixeu per lots diverses imatges d’una llista d’URL

Baixeu imatges especificant l’URL.

Podeu utilitzar la biblioteca estàndard només per descarregar fitxers individuals especificant els seus URL; no es requereix cap instal·lació addicional.

Exemple de codi

El següent és un exemple d’una funció que baixa i desa un fitxer especificant l’URL i el camí de destinació, i el seu ús. Aquest codi és una mica detallat per a l’explicació. A continuació es presenta un exemple senzill.

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)

Per especificar el directori de destinació i desar el fitxer amb el nom del fitxer URL, feu el següent

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)

Extreu el nom del fitxer de l’URL amb os.path.basename() i l’uneix amb el directori especificat amb os.path.join() per generar el camí de destinació.

Les seccions següents descriuen la part de l’adquisició de dades i la part de l’emmagatzematge de dades com a fitxer.

urllib.request.urlopen():Obre l’URL

Utilitzeu urllib.request.urlopen() per obrir l’URL i recuperar les dades. Tingueu en compte que urllib.urlopen() ha estat obsolet a Python 2.6 i anteriors. urllib.request.urlretrieve() encara no ha estat obsolet, però pot ser que ho sigui en el futur.

Per evitar aturar-se quan es produeix una excepció, detecteu l’error amb try i except.

A l’exemple, urllib.error s’importa i només es captura explícitament urllib.error.URLError. El missatge d’error es mostrarà quan l’URL del fitxer no existeixi.

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 també voleu detectar excepcions (FileNotFoundError, etc.) quan deseu localment, feu el següent.
(urllib.error.URLError, FileNotFoundError)

També és possible utilitzar les sol·licituds de biblioteca de tercers en comptes de l’urllib de la biblioteca estàndard per obrir l’URL i obtenir les dades.

Escriure en un fitxer en mode binari a open()

Les dades que es poden obtenir amb urllib.request.urlopen() són una cadena de bytes (tipus bytes).

Open() amb mode=’wb’ com a segon argument escriu les dades com a binàries. w significa escriure i b significa binari.

Un exemple de codi més senzill

Les declaracions niuades es poden escriure alhora, separades per comes.

Amb això, podem escriure el següent.

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)

Descarrega fitxers ZIP, PDF, etc.

Els exemples fins ara són per descarregar i desar fitxers d’imatge, però com que simplement estem obrint un fitxer a la web i desant-lo com a fitxer local, les mateixes funcions es poden utilitzar per a altres tipus de fitxers.

Podeu baixar i desar fitxers especificant 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)

Tingueu en compte que l’URL especificat en aquesta funció ha de ser un enllaç al fitxer en si.

Per exemple, en el cas d’un fitxer de dipòsit de GitHub, l’URL següent té una extensió pdf, però en realitat és una pàgina html. Si s’especifica aquest URL a la funció anterior, es baixarà la font HTML.

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

L’enllaç a l’entitat del fitxer és l’URL següent, que heu d’especificar si voleu descarregar i desar el fitxer.

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

També hi ha casos en què l’accés està restringit per l’agent d’usuari, el referent, etc., cosa que fa que no es pugui descarregar. No garantim que es baixin tots els fitxers.

És fàcil d’utilitzar Sol·licituds per canviar o afegir capçaleres de sol·licitud, com ara l’agent d’usuari.

Extreu l’URL de la imatge a la pàgina web.

Per descarregar totes les imatges d’una pàgina alhora, primer extreu els URL de les imatges i creeu una llista.

Si el nombre és seqüencial

Si l’URL de la imatge que voleu descarregar és un simple número seqüencial, és fàcil. Si els URL no només són números seqüencials, sinó que també tenen certa regularitat, és més fàcil fer una llista d’URL d’acord amb les regles en lloc de raspar amb Beautiful Soup (vegeu més avall).

Utilitzeu la notació de comprensió de llista.

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']

A l’exemple anterior, {:03} s’utilitza per a un nombre seqüencial de 3 dígits amb zero; {} s’utilitza quan no cal emplenar zero i {:05} s’utilitza per a un nombre de 5 dígits en lloc de 3. Per obtenir més informació sobre el mètode de format de la cadena str, consulteu l’article següent.

A més, aquí estem utilitzant pprint per facilitar la lectura de la sortida.

Extracte amb bella sopa

Per extreure URL d’imatge de pàgines web a granel, utilitzeu Beautiful Soup.

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

from bs4 import BeautifulSoup

url = 'https://ca.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')]

A l’exemple, s’extreu l’URL de la imatge en miniatura d’aquest lloc web.

L’estructura varia segons la pàgina web, però bàsicament s’obté de la següent manera.

  • Obteniu una llista de <img> etiqueta objectes especificant la classe, id, etc. del bloc que conté les múltiples imatges que voleu descarregar.
    • soup.find(class_='list').find_all('img')
  • Obteniu l’URL de la imatge a partir de l’element src o de l’element data-src del <img> etiqueta.
    • img.get('data-src')

El codi d’exemple anterior és només un exemple i no es garanteix que funcioni.

Baixeu per lots diverses imatges d’una llista d’URL

Si teniu una llista d’URL, només podeu convertir-la en un bucle for i trucar a la funció per descarregar i desar el fitxer amb el primer URL mostrat. A causa de la llista temporal d’URL, aquí es comenta la trucada de funció download_image_dir().

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

Per no sobrecarregar el servidor, faig servir time.sleep() per crear un temps d’espera per a cada descàrrega d’imatges. La unitat està en segons, de manera que a l’exemple anterior, el mòdul de temps s’importa i s’utilitza.

L’exemple és per a fitxers d’imatge, però també es poden descarregar altres tipus de fitxers junts, sempre que estiguin llistats.

Copied title and URL