A continuación se explica cómo especificar en Python la URL de una imagen, un ZIP, un PDF u otro archivo de la web, descargarlo y guardarlo como archivo local.
- Descargue las imágenes especificando la URL.
- Ejemplo de código
urllib.request.urlopen()
:Abrir URLopen()
:Escribir en un archivo en modo binario- Un ejemplo de código más sencillo
- Descargue archivos ZIP, PDF, etc.
- Extraer la URL de la imagen en la página web.
- Si el número es secuencial
- Extracto con Beautiful Soup
- Descarga por lotes de múltiples imágenes desde una lista de URLs
Descargue las imágenes especificando la URL.
Puede utilizar la biblioteca estándar sólo para descargar archivos individuales especificando sus URL; no se requiere ninguna instalación adicional.
Ejemplo de código
El siguiente es un ejemplo de una función que descarga y guarda un archivo especificando la URL y la ruta de destino, y su uso. Este código es un poco verboso en aras de la explicación. A continuación se ofrece un ejemplo sencillo.
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 el directorio de destino y guardar el archivo con el nombre de archivo URL, haga lo siguiente
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 el nombre del archivo de la URL con os.path.basename() y lo une con el directorio especificado con os.path.join() para generar la ruta de destino.
Las siguientes secciones describen la parte de la adquisición de datos y la parte del almacenamiento de datos como un archivo.
urllib.request.urlopen(): Abrir URL
Utilice urllib.request.urlopen() para abrir la URL y recuperar los datos. Tenga en cuenta que urllib.urlopen() ha sido obsoleta en Python 2.6 y anteriores. urllib.request.urlretrieve() no ha sido obsoleta todavía, pero puede serlo en el futuro.
Para evitar que se detenga cuando se produzca una excepción, atrape el error con try y except.
En el ejemplo, se importa urllib.error y sólo se captura explícitamente urllib.error.URLError. El mensaje de error se mostrará cuando la URL del archivo no 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
Si quiere capturar también excepciones (FileNotFoundError, etc.) al guardar localmente, haga lo siguiente.(urllib.error.URLError, FileNotFoundError)
También es posible utilizar la biblioteca de terceros Requests en lugar de la biblioteca estándar urllib para abrir la url y obtener los datos.
Escribir en un archivo en modo binario en open()
Los datos que se pueden obtener con urllib.request.urlopen() son una cadena de bytes (tipo bytes).
Open() con mode='wb' como segundo argumento escribe los datos como binarios. w significa escritura y b significa binario.
Un ejemplo de código más sencillo
Las declaraciones anidadas con pueden escribirse a la vez, separadas por comas.
Utilizando esto, podemos escribir lo siguiente.
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)
Descargue archivos ZIP, PDF, etc.
Los ejemplos hasta ahora son para descargar y guardar archivos de imagen, pero como simplemente estamos abriendo un archivo en la web y guardándolo como un archivo local, las mismas funciones se pueden utilizar para otros tipos de archivos.
Puedes descargar y guardar archivos especificando la 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)
Tenga en cuenta que la URL especificada en esta función debe ser un enlace al propio archivo.
Por ejemplo, en el caso de un archivo del repositorio de GitHub, la siguiente URL tiene una extensión pdf pero en realidad es una página html. Si se especifica esta URL en la función anterior, se descargará la fuente html.
- https://github.com/from-locals/python-snippets/blob/master/notebook/data/src/pdf/sample1.pdf
El enlace a la entidad del archivo es la siguiente URL, que debe especificar si desea descargar y guardar el archivo.
- https://github.com/from-locals/python-snippets/raw/master/notebook/data/src/pdf/sample1.pdf
También hay casos en los que el acceso está restringido por el agente de usuario, el referente, etc., lo que hace imposible la descarga. No garantizamos que se descarguen todos los archivos.
Es fácil utilizar Requests para cambiar o añadir cabeceras de solicitud como el agente de usuario.
Extraer la URL de la imagen en la página web.
Para descargar todas las imágenes de una página a la vez, primero extraiga las URL de las imágenes y cree una lista.
Si el número es secuencial
Si la URL de la imagen que se quiere descargar es un simple número secuencial, es fácil. Si las URLs no son sólo números secuenciales sino que tienen cierta regularidad, es más fácil hacer una lista de URLs según las reglas en lugar de hacer un scraping con Beautiful Soup (ver más abajo).
Utiliza la notación de comprensión de listas.
- Artículos relacionados:Uso de la notación de comprensión de listas de Python
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']
En el ejemplo anterior, {:03} se utiliza para un número secuencial de 3 dígitos rellenado con cero; {} se utiliza cuando no es necesario rellenar con cero, y {:05} se utiliza para un número de 5 dígitos en lugar de 3 dígitos. Para obtener más información sobre el método de formato de la cadena de caracteres, consulte el siguiente artículo.
- Artículos relacionados:Conversión de formatos en Python, formato (llenado de ceros, notación exponencial, hexadecimal, etc.)
Además, aquí utilizamos pprint para que la salida sea más fácil de leer.
Extracto con Beautiful Soup
Para extraer las URL de las imágenes de las páginas web de forma masiva, utilice Beautiful Soup.
import os import time import urllib.error import urllib.request from bs4 import BeautifulSoup url = 'https://es.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')]
En el ejemplo, se extrae la URL de la imagen en miniatura de este sitio web.
La estructura varía según la página web, pero básicamente se obtiene como sigue.
- Obtenga una lista de objetos de la etiqueta <img> especificando la clase, el id, etc. del bloque que contiene las múltiples imágenes que desea descargar.
soup.find(class_='list').find_all('img')
- Obtenga la URL de la imagen del elemento src o del elemento data-src de la etiqueta <img>.
img.get('data-src')
El código de muestra anterior es sólo un ejemplo y no se garantiza que funcione.
Descarga por lotes de múltiples imágenes desde una lista de URLs
Si tienes una lista de URLs, puedes simplemente convertirla en un bucle for y llamar a la función para descargar y guardar el archivo con la primera URL mostrada. Debido a la lista temporal de URLs, la llamada a la función download_image_dir() se comenta 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 no sobrecargar el servidor, utilizo time.sleep() para crear un tiempo de espera para cada descarga de imágenes. La unidad está en segundos, por lo que en el ejemplo anterior se importa y se utiliza el módulo de tiempo.
El ejemplo es para archivos de imagen, pero también se pueden descargar juntos otros tipos de archivos, siempre que estén en la lista.