Descarga imaxes e outros ficheiros da web en Python (individualmente ou por lotes)

Negocios

A continuación explícase como especificar o URL dunha imaxe, ZIP, PDF ou outro ficheiro na web en Python, descargalo e gardalo como ficheiro local.

  • Descarga imaxes especificando o URL.
    • Exemplo de código
    • urllib.request.urlopen():Abrir URL
    • open():Escribir nun ficheiro en modo binario
    • Un exemplo de código máis sinxelo
  • Descargar ficheiros ZIP, PDF, etc.
  • Extrae o URL da imaxe da páxina web.
    • Se o número é secuencial
    • Extracto con bonita sopa
  • Descarga por lotes varias imaxes dunha lista de URL

Descarga imaxes especificando o URL.

Podes usar a biblioteca estándar só para descargar ficheiros individuais especificando os seus URL; non se precisa instalación adicional.

Exemplo de código

O seguinte é un exemplo dunha función que descarga e garda un ficheiro especificando o URL e o camiño de destino e o seu uso. Este código é un pouco detallado para explicar. A continuación dáse un exemplo sinxelo.

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)

Para especificar o directorio de destino e gardar o ficheiro co nome do ficheiro URL, faga o seguinte

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)

Extrae o nome do ficheiro do URL con os.path.basename() e únese ao directorio especificado con os.path.join() para xerar o camiño de destino.

Nas seguintes seccións descríbense a parte da adquisición de datos e a parte dos datos gardados como ficheiro.

urllib.request.urlopen():Abrir URL

Use urllib.request.urlopen() para abrir o URL e recuperar os datos. Teña en conta que urllib.urlopen() quedou en desuso en Python 2.6 e anteriores. urllib.request.urlretrieve() aínda non quedou en desuso, pero pode estarlo no futuro.

Para evitar deterse cando se produce unha excepción, detecta o erro con try e except.

No exemplo, impórtase urllib.error e só se captura explícitamente urllib.error.URLError. A mensaxe de erro mostrarase cando o URL do ficheiro non exista.

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

Se tamén queres detectar excepcións (FileNotFoundError, etc.) ao gardar localmente, fai o seguinte.
(urllib.error.URLError, FileNotFoundError)

Tamén é posible usar as solicitudes de bibliotecas de terceiros en lugar do urllib da biblioteca estándar para abrir o URL e obter os datos.

Escribir nun ficheiro en modo binario en open()

Os datos que se poden obter con urllib.request.urlopen() son unha cadea de bytes (tipo bytes).

Open() con mode=’wb’ como segundo argumento escribe os datos como binarios. w significa escribir e b significa binario.

Un exemplo de código máis sinxelo

Anidados con declaracións pódense escribir á vez, separados por comas.

Usando isto, podemos escribir o seguinte.

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)

Descargar ficheiros ZIP, PDF, etc.

Os exemplos ata agora son para descargar e gardar ficheiros de imaxe, pero como simplemente estamos abrindo un ficheiro na web e gardándoo como un ficheiro local, pódense utilizar as mesmas funcións para outro tipo de ficheiros.

Podes descargar e gardar ficheiros especificando o 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)

Teña en conta que o URL especificado nesta función debe ser unha ligazón ao propio ficheiro.

Por exemplo, no caso dun ficheiro de repositorio de GitHub, o seguinte URL ten unha extensión pdf pero en realidade é unha páxina html. Se se especifica este URL na función anterior, descargarase a fonte html.

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

A ligazón á entidade do ficheiro é o seguinte URL, que debes especificar se queres descargar e gardar o ficheiro.

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

Tamén hai casos nos que o acceso está restrinxido polo axente de usuario, o referente, etc., o que fai imposible a descarga. Non garantimos que se descarguen todos os ficheiros.

É doado de usar Solicitudes para cambiar ou engadir cabeceiras de solicitudes como o axente de usuario.

Extrae o URL da imaxe da páxina web.

Para descargar todas as imaxes dunha páxina á vez, primeiro extrae os URL das imaxes e crea unha lista.

Se o número é secuencial

Se o URL da imaxe que queres descargar é un simple número secuencial, é doado. Se os URL non son só números secuenciais senón que tamén teñen certa regularidade, é máis fácil facer unha lista de URL segundo as regras en lugar de raspar con Beautiful Soup (ver máis abaixo).

Usa a notación de comprensión de listas.

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

No exemplo anterior, {:03} úsase para un número secuencial de 3 díxitos con cero; {} úsase cando non é necesario o recheo de cero e {:05} úsase para un número de 5 díxitos en lugar de 3 díxitos. Para obter máis información sobre o método de formato da cadea str, consulte o seguinte artigo.

Ademais, aquí estamos usando pprint para facilitar a lectura da saída.

Extracto con bonita sopa

Para extraer URL de imaxes de páxinas web de forma masiva, utiliza Beautiful Soup.

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

from bs4 import BeautifulSoup

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

No exemplo, extráese o URL da imaxe en miniatura deste sitio web.

A estrutura varía segundo a páxina web, pero basicamente obtense do seguinte xeito.

  • Obter unha lista de <img> etiqueta os obxectos especificando a clase, id, etc. do bloque que contén as varias imaxes que queres descargar.
    • soup.find(class_='list').find_all('img')
  • Obter o URL da imaxe do elemento src ou do elemento data-src do <img> etiqueta.
    • img.get('data-src')

O código de mostra anterior é só un exemplo e non se garante que funcione.

Descarga por lotes varias imaxes dunha lista de URL

Se tes unha lista de URL, podes transformala nun bucle for e chamar á función para descargar e gardar o ficheiro co primeiro URL mostrado. Debido á lista de URL temporal, a chamada de función download_image_dir() é comentada aquí.

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

Para non sobrecargar o servidor, uso time.sleep() para crear un tempo de espera para cada descarga de imaxe. A unidade está en segundos, polo que no exemplo anterior impórtase e úsase o módulo de tempo.

O exemplo é para ficheiros de imaxe, pero tamén se poden descargar outros tipos de ficheiros xuntos, sempre que estean listados.

Copied title and URL