¿Cómo descargo un archivo a través de HTTP usando Python?

875

Tengo una pequeña utilidad que utilizo para descargar un archivo MP3 de un sitio web en un horario y luego construye / actualiza un archivo XML de podcast que he agregado a iTunes.

El procesamiento de texto que crea / actualiza el archivo XML se escribe en Python. Sin embargo, uso wget dentro de un .batarchivo de Windows para descargar el archivo MP3 real. Preferiría tener toda la utilidad escrita en Python.

Luché por encontrar una manera de descargar realmente el archivo en Python, por eso recurrí a usarlo wget.

Entonces, ¿cómo descargo el archivo usando Python?

Owen
fuente
Muchas de las respuestas a continuación no son un reemplazo satisfactorio para wget. Entre otras cosas, wget(1) conserva las marcas de tiempo (2) determina automáticamente el nombre del archivo desde la url, agregando .1(etc.) si el archivo ya existe (3) tiene muchas otras opciones, algunas de las cuales puede haber puesto en su .wgetrc. Si desea alguno de esos, debe implementarlos usted mismo en Python, pero es más simple invocarlo wgetdesde Python.
ShreevatsaR
2
Solución breve para Python 3:import urllib.request; s = urllib.request.urlopen('http://example.com/').read().decode()
Basj

Respuestas:

450

En Python 2, use urllib2 que viene con la biblioteca estándar.

import urllib2
response = urllib2.urlopen('http://www.example.com/')
html = response.read()

Esta es la forma más básica de usar la biblioteca, menos cualquier manejo de errores. También puede hacer cosas más complejas, como cambiar los encabezados. La documentación se puede encontrar aquí.

Corey
fuente
11
Esto no funcionará si hay espacios en la url que proporcione. En ese caso, deberá analizar la url y codificar la ruta.
Jason Sundram
9191
Aquí está la solución Python 3: stackoverflow.com/questions/7243750/…
tommy.carstensen
66
Solo para referencia. La forma de codificar el camino esurllib2.quote
André Puel
11
@JasonSundram: si hay espacios en él, no es un URI.
Zaz
1
Esto no funciona en ventanas con archivos más grandes. ¡Necesitas leer todos los bloques!
Avia
1115

Uno más, usando urlretrieve:

import urllib
urllib.urlretrieve ("http://www.example.com/songs/mp3.mp3", "mp3.mp3")

(para uso en Python 3+ import urllib.requesty urllib.request.urlretrieve)

Otro más, con una "barra de progreso"

import urllib2

url = "http://download.thinkbroadband.com/10MB.zip"

file_name = url.split('/')[-1]
u = urllib2.urlopen(url)
f = open(file_name, 'wb')
meta = u.info()
file_size = int(meta.getheaders("Content-Length")[0])
print "Downloading: %s Bytes: %s" % (file_name, file_size)

file_size_dl = 0
block_sz = 8192
while True:
    buffer = u.read(block_sz)
    if not buffer:
        break

    file_size_dl += len(buffer)
    f.write(buffer)
    status = r"%10d  [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
    status = status + chr(8)*(len(status)+1)
    print status,

f.close()
PabloG
fuente
1
Por extraño que parezca, esto funcionó para mí en Windows cuando el método urllib2 no lo haría. Sin embargo, el método urllib2 funcionó en Mac.
InFreefall
66
Error: file_size_dl + = block_sz debería ser + = len (buffer) ya que la última lectura a menudo no es un block_sz completo. También en Windows necesita abrir el archivo de salida como "wb" si no es un archivo de texto.
Berenjena Jeff
1
Yo también urllib y urllib2 no funcionaron pero urlretrieve funcionó bien, estaba frustrado - gracias :)
funk-shun
2
¡Envuelva todo (excepto la definición de file_name) con if not os.path.isfile(file_name):para evitar sobrescribir podcasts! útil cuando se ejecuta como un cronjob con las URL encontradas en un archivo .html
Sriram Murali
2
@PabloG es un poco más de 31 votos ahora;) De todos modos, la barra de estado fue divertida, así que haré +1
Cinder
340

En 2012, use la biblioteca de solicitudes de Python

>>> import requests
>>> 
>>> url = "http://download.thinkbroadband.com/10MB.zip"
>>> r = requests.get(url)
>>> print len(r.content)
10485760

Puedes correr pip install requestspara conseguirlo.

Las solicitudes tienen muchas ventajas sobre las alternativas porque la API es mucho más simple. Esto es especialmente cierto si tiene que hacer autenticación. urllib y urllib2 son bastante poco intuitivos y dolorosos en este caso.


2015-12-30

La gente ha expresado admiración por la barra de progreso. Es genial, claro. Hay varias soluciones disponibles ahora, que incluyen tqdm:

from tqdm import tqdm
import requests

url = "http://download.thinkbroadband.com/10MB.zip"
response = requests.get(url, stream=True)

with open("10MB", "wb") as handle:
    for data in tqdm(response.iter_content()):
        handle.write(data)

Esta es esencialmente la implementación que @kvance describió hace 30 meses.

hughdbrown
fuente
¿Cómo guardo o extraigo si el archivo zip es en realidad una carpeta con muchos archivos?
Abdul Muneer
66
¿Cómo maneja esto los archivos grandes, todo se almacena en la memoria o se puede escribir en un archivo sin necesidad de memoria grande?
bibstha
8
Es posible transmitir archivos grandes configurando stream = True en la solicitud. Luego puede llamar a iter_content () en la respuesta para leer un fragmento a la vez.
kvance
77
¿Por qué una biblioteca de URL necesita tener una instalación de descompresión de archivos? Lea el archivo de la url, guárdelo y luego descomprímalo de cualquier forma que flote su barco. Además, un archivo zip no es una 'carpeta' como se muestra en Windows, es un archivo.
Harel
2
@ Ali:: r.textpara texto o contenido Unicode. Devuelto como unicode. r.content: Para contenido binario. Devuelto como bytes. Lea sobre esto aquí: docs.python-requests.org/en/latest/user/quickstart
hughdbrown
159
import urllib2
mp3file = urllib2.urlopen("http://www.example.com/songs/mp3.mp3")
with open('test.mp3','wb') as output:
  output.write(mp3file.read())

El wben open('test.mp3','wb')abre un archivo (y borra cualquier archivo existente) en modo binario para que pueda guardar los datos con él en lugar de sólo texto.

Conceder
fuente
30
La desventaja de esta solución es que todo el archivo se carga en la memoria RAM antes de guardarlo en el disco, algo a tener en cuenta si se usa esto para archivos grandes en un sistema pequeño como un enrutador con memoria RAM limitada.
Tripplet
2
@tripplet, ¿cómo solucionaríamos eso?
Lucas Henrique
11
Para evitar leer todo el archivo en la memoria, intente pasar un argumento a file.readese es el número de bytes a leer. Ver: gist.github.com/hughdbrown/c145b8385a2afa6570e2
hughdbrown
@hughdbrown Encontré su script útil, pero tengo una pregunta: ¿puedo usar el archivo para el procesamiento posterior? supongamos que descargo un archivo jpg que quiero procesar con OpenCV, ¿puedo usar la variable 'datos' para seguir trabajando? ¿o tengo que volver a leerlo desde el archivo descargado?
Rodrigo E. Principe el
55
Usar en su shutil.copyfileobj(mp3file, output)lugar.
Aurélien Ooms
130

Python 3

  • urllib.request.urlopen

    import urllib.request
    response = urllib.request.urlopen('http://www.example.com/')
    html = response.read()
    
  • urllib.request.urlretrieve

    import urllib.request
    urllib.request.urlretrieve('http://www.example.com/songs/mp3.mp3', 'mp3.mp3')
    

    Nota: De acuerdo con la documentación, urllib.request.urlretrievees una "interfaz heredada" y "podría quedar obsoleta en el futuro" (gracias Gerrit )

Python 2

  • urllib2.urlopen(gracias Corey )

    import urllib2
    response = urllib2.urlopen('http://www.example.com/')
    html = response.read()
    
  • urllib.urlretrieve(gracias PabloG )

    import urllib
    urllib.urlretrieve('http://www.example.com/songs/mp3.mp3', 'mp3.mp3')
    
bmaupin
fuente
2
Ciertamente tomó un tiempo, pero finalmente, es la API fácil y sencilla que espero de un stdlib de python :)
ThorSummoner
Muy buena respuesta para python3, ver también docs.python.org/3/library/…
Edouard Thiel
@EdouardThiel Si hace clic en urllib.request.urlretrievearriba, lo llevará a ese enlace exacto. ¡Salud!
bmaupin
2
urllib.request.urlretrieveestá documentado como una "interfaz heredada" y "podría quedar obsoleto en el futuro".
Gerrit
@gerrit Agregué una nota, ¡gracias por el aviso!
bmaupin
32

use el módulo wget:

import wget
wget.download('url')
Sara Santana
fuente
21

Una versión mejorada del código PabloG para Python 2/3:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import ( division, absolute_import, print_function, unicode_literals )

import sys, os, tempfile, logging

if sys.version_info >= (3,):
    import urllib.request as urllib2
    import urllib.parse as urlparse
else:
    import urllib2
    import urlparse

def download_file(url, dest=None):
    """ 
    Download and save a file specified by url to dest directory,
    """
    u = urllib2.urlopen(url)

    scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
    filename = os.path.basename(path)
    if not filename:
        filename = 'downloaded.file'
    if dest:
        filename = os.path.join(dest, filename)

    with open(filename, 'wb') as f:
        meta = u.info()
        meta_func = meta.getheaders if hasattr(meta, 'getheaders') else meta.get_all
        meta_length = meta_func("Content-Length")
        file_size = None
        if meta_length:
            file_size = int(meta_length[0])
        print("Downloading: {0} Bytes: {1}".format(url, file_size))

        file_size_dl = 0
        block_sz = 8192
        while True:
            buffer = u.read(block_sz)
            if not buffer:
                break

            file_size_dl += len(buffer)
            f.write(buffer)

            status = "{0:16}".format(file_size_dl)
            if file_size:
                status += "   [{0:6.2f}%]".format(file_size_dl * 100 / file_size)
            status += chr(13)
            print(status, end="")
        print()

    return filename

if __name__ == "__main__":  # Only run if this file is called directly
    print("Testing with 10MB download")
    url = "http://download.thinkbroadband.com/10MB.zip"
    filename = download_file(url)
    print(filename)
Stan
fuente
Quitaría los paréntesis de la primera línea, porque no es una característica demasiado antigua.
Arpad Horvath
21

La Python 2 & Python 3forma simple pero compatible viene con la sixbiblioteca:

from six.moves import urllib
urllib.request.urlretrieve("http://www.example.com/songs/mp3.mp3", "mp3.mp3")
Akif
fuente
1
Esta es la mejor manera de hacerlo por compatibilidad 2 + 3.
Fush
21
import os,requests
def download(url):
    get_response = requests.get(url,stream=True)
    file_name  = url.split("/")[-1]
    with open(file_name, 'wb') as f:
        for chunk in get_response.iter_content(chunk_size=1024):
            if chunk: # filter out keep-alive new chunks
                f.write(chunk)


download("https://example.com/example.jpg")
HS Umer farooq
fuente
17

Escribió la biblioteca de wget en Python puro solo para este propósito. Se bombea urlretrievecon estas características partir de la versión 2.0.

anatoly techtonik
fuente
3
¿Ninguna opción para guardar con un nombre de archivo personalizado?
Alex
2
@Alex agregó la opción -o FILENAME a la versión 2.1
anatoly techtonik
La barra de progreso no aparece cuando uso este módulo en Cygwin.
Joe Coder
Debe cambiar de -oa -Opara evitar confusiones, ya que está en GNU wget. O al menos ambas opciones deben ser válidas.
erik
@eric No estoy seguro de querer hacer wget.pyun reemplazo en el lugar de verdad wget. El -oya se comporta de manera diferente, es compatible de curlesta manera. ¿Una nota en la documentación ayudaría a resolver el problema? ¿O es la característica esencial para que una utilidad con dicho nombre sea compatible con la línea de comandos?
anatoly techtonik
16

Las siguientes son las llamadas más utilizadas para descargar archivos en python:

  1. urllib.urlretrieve ('url_to_file', file_name)

  2. urllib2.urlopen('url_to_file')

  3. requests.get(url)

  4. wget.download('url', file_name)

Nota: urlopeny urlretrievese encuentra que funcionan relativamente mal con la descarga de archivos grandes (tamaño> 500 MB). requests.getalmacena el archivo en la memoria hasta que se complete la descarga.

Jaydev
fuente
14

Estoy de acuerdo con Corey, urllib2 es más completo que urllib y probablemente debería ser el módulo utilizado si quieres hacer cosas más complejas, pero para que las respuestas sean más completas, urllib es un módulo más simple si solo quieres lo básico:

import urllib
response = urllib.urlopen('http://www.example.com/sound.mp3')
mp3 = response.read()

Funcionará bien O, si no desea tratar con el objeto "respuesta", puede llamar a read () directamente:

import urllib
mp3 = urllib.urlopen('http://www.example.com/sound.mp3').read()
akdom
fuente
10

En python3 puedes usar urllib3 y shutil libraires. Descárguelos usando pip o pip3 (dependiendo de si python3 es predeterminado o no)

pip3 install urllib3 shutil

Luego ejecuta este código

import urllib.request
import shutil

url = "http://www.somewebsite.com/something.pdf"
output_file = "save_this_name.pdf"
with urllib.request.urlopen(url) as response, open(output_file, 'wb') as out_file:
    shutil.copyfileobj(response, out_file)

Tenga en cuenta que descarga urllib3pero usa urlliben el código

Apoorv Agarwal
fuente
7

También puede obtener comentarios sobre el progreso con urlretrieve:

def report(blocknr, blocksize, size):
    current = blocknr*blocksize
    sys.stdout.write("\r{0:.2f}%".format(100.0*current/size))

def downloadFile(url):
    print "\n",url
    fname = url.split('/')[-1]
    print fname
    urllib.urlretrieve(url, fname, report)
Marcin Cuprjak
fuente
7

Si tiene instalado wget, puede usar parallel_sync.

pip install parallel_sync

from parallel_sync import wget
urls = ['http://something.png', 'http://somthing.tar.gz', 'http://somthing.zip']
wget.download('/tmp', urls)
# or a single file:
wget.download('/tmp', urls[0], filenames='x.zip', extract=True)

Doc: https://pythonhosted.org/parallel_sync/pages/examples.html

Esto es bastante poderoso. Puede descargar archivos en paralelo, volver a intentarlo en caso de falla e incluso puede descargar archivos en una máquina remota.

max
fuente
Tenga en cuenta que esto es solo para Linux
jjj
4

Si la velocidad es importante para usted, hice una pequeña prueba de rendimiento para los módulos urlliby wget, en lo wgetque respecta , probé una vez con la barra de estado y una vez sin ella. Tomé tres archivos diferentes de 500 MB para probar (diferentes archivos, para eliminar la posibilidad de que haya algo de almacenamiento en caché debajo del capó). Probado en máquina debian, con python2.

Primero, estos son los resultados (son similares en diferentes ejecuciones):

$ python wget_test.py 
urlretrive_test : starting
urlretrive_test : 6.56
==============
wget_no_bar_test : starting
wget_no_bar_test : 7.20
==============
wget_with_bar_test : starting
100% [......................................................................] 541335552 / 541335552
wget_with_bar_test : 50.49
==============

La forma en que realicé la prueba es usando el decorador de "perfil". Este es el código completo:

import wget
import urllib
import time
from functools import wraps

def profile(func):
    @wraps(func)
    def inner(*args):
        print func.__name__, ": starting"
        start = time.time()
        ret = func(*args)
        end = time.time()
        print func.__name__, ": {:.2f}".format(end - start)
        return ret
    return inner

url1 = 'http://host.com/500a.iso'
url2 = 'http://host.com/500b.iso'
url3 = 'http://host.com/500c.iso'

def do_nothing(*args):
    pass

@profile
def urlretrive_test(url):
    return urllib.urlretrieve(url)

@profile
def wget_no_bar_test(url):
    return wget.download(url, out='/tmp/', bar=do_nothing)

@profile
def wget_with_bar_test(url):
    return wget.download(url, out='/tmp/')

urlretrive_test(url1)
print '=============='
time.sleep(1)

wget_no_bar_test(url2)
print '=============='
time.sleep(1)

wget_with_bar_test(url3)
print '=============='
time.sleep(1)

urllib parece ser el más rápido

Omer Dagan
fuente
Debe haber algo completamente horrible sucediendo debajo del capó para que la barra aumente tanto el tiempo.
Alistair Carscadden
4

En aras de la integridad, también es posible llamar a cualquier programa para recuperar archivos utilizando el subprocesspaquete. Los programas dedicados a recuperar archivos son más potentes que las funciones de Python urlretrieve. Por ejemplo, wgetpuede descargar directorios de forma recursiva ( -R), puede lidiar con FTP, redireccionamientos, servidores proxy HTTP, puede evitar volver a descargar archivos existentes ( -nc) y aria2puede realizar descargas de conexiones múltiples que potencialmente pueden acelerar sus descargas.

import subprocess
subprocess.check_output(['wget', '-O', 'example_output_file.html', 'https://example.com'])

En Jupyter Notebook, también se pueden llamar programas directamente con la !sintaxis:

!wget -O example_output_file.html https://example.com
Robin Dinse
fuente
3

El código fuente puede ser:

import urllib
sock = urllib.urlopen("http://diveintopython.org/")
htmlSource = sock.read()                            
sock.close()                                        
print htmlSource  
Olu Smith
fuente
3

Puede usar PycURL en Python 2 y 3.

import pycurl

FILE_DEST = 'pycurl.html'
FILE_SRC = 'http://pycurl.io/'

with open(FILE_DEST, 'wb') as f:
    c = pycurl.Curl()
    c.setopt(c.URL, FILE_SRC)
    c.setopt(c.WRITEDATA, f)
    c.perform()
    c.close()
gzerone
fuente
2

Escribí lo siguiente, que funciona en Python 2 o Python 3.


import sys
try:
    import urllib.request
    python3 = True
except ImportError:
    import urllib2
    python3 = False


def progress_callback_simple(downloaded,total):
    sys.stdout.write(
        "\r" +
        (len(str(total))-len(str(downloaded)))*" " + str(downloaded) + "/%d"%total +
        " [%3.2f%%]"%(100.0*float(downloaded)/float(total))
    )
    sys.stdout.flush()

def download(srcurl, dstfilepath, progress_callback=None, block_size=8192):
    def _download_helper(response, out_file, file_size):
        if progress_callback!=None: progress_callback(0,file_size)
        if block_size == None:
            buffer = response.read()
            out_file.write(buffer)

            if progress_callback!=None: progress_callback(file_size,file_size)
        else:
            file_size_dl = 0
            while True:
                buffer = response.read(block_size)
                if not buffer: break

                file_size_dl += len(buffer)
                out_file.write(buffer)

                if progress_callback!=None: progress_callback(file_size_dl,file_size)
    with open(dstfilepath,"wb") as out_file:
        if python3:
            with urllib.request.urlopen(srcurl) as response:
                file_size = int(response.getheader("Content-Length"))
                _download_helper(response,out_file,file_size)
        else:
            response = urllib2.urlopen(srcurl)
            meta = response.info()
            file_size = int(meta.getheaders("Content-Length")[0])
            _download_helper(response,out_file,file_size)

import traceback
try:
    download(
        "https://geometrian.com/data/programming/projects/glLib/glLib%20Reloaded%200.5.9/0.5.9.zip",
        "output.zip",
        progress_callback_simple
    )
except:
    traceback.print_exc()
    input()

Notas:

  • Admite una devolución de llamada de "barra de progreso".
  • La descarga es un .zip de prueba de 4 MB de mi sitio web.
imallett
fuente
funciona muy bien, ejecútalo a través de jupyter tengo lo que quiero :-)
Samir Ouldsaadi
1

Esto puede ser un poco tarde, ¡pero vi el código de pabloG y no pude evitar agregar un sistema os. ('cls') para que se vea IMPRESIONANTE! Echale un vistazo :

    import urllib2,os

    url = "http://download.thinkbroadband.com/10MB.zip"

    file_name = url.split('/')[-1]
    u = urllib2.urlopen(url)
    f = open(file_name, 'wb')
    meta = u.info()
    file_size = int(meta.getheaders("Content-Length")[0])
    print "Downloading: %s Bytes: %s" % (file_name, file_size)
    os.system('cls')
    file_size_dl = 0
    block_sz = 8192
    while True:
        buffer = u.read(block_sz)
        if not buffer:
            break

        file_size_dl += len(buffer)
        f.write(buffer)
        status = r"%10d  [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
        status = status + chr(8)*(len(status)+1)
        print status,

    f.close()

Si se ejecuta en un entorno que no sea Windows, deberá usar algo distinto de 'cls'. En MAC OS X y Linux debería estar 'claro'.

JD3
fuente
3
clsno hace nada en mi OS X ni en un servidor Ubuntu mío. Alguna aclaración podría ser buena.
kqw
Creo que debería usarlo clearpara Linux, o incluso mejor reemplazar la línea de impresión en lugar de borrar toda la salida de la línea de comando.
Arijoon
44
esta respuesta simplemente copia otra respuesta y agrega una llamada a una función en desuso ( os.system()) que inicia un subproceso para borrar la pantalla usando un comando específico de la plataforma ( cls). ¿Cómo tiene esto que cualquier upvotes ?? Totalmente inútil "respuesta" en mi humilde opinión.
Corey Goldberg
1

urlretrieve y request.get son simples, sin embargo, la realidad no lo es. He obtenido datos para un par de sitios, incluidos texto e imágenes, los dos anteriores probablemente resuelven la mayoría de las tareas. pero para una solución más universal sugiero el uso de urlopen. Como está incluido en la biblioteca estándar de Python 3, su código podría ejecutarse en cualquier máquina que ejecute Python 3 sin preinstalar el paquete del sitio

import urllib.request
url_request = urllib.request.Request(url, headers=headers)
url_connect = urllib.request.urlopen(url_request)

#remember to open file in bytes mode
with open(filename, 'wb') as f:
    while True:
        buffer = url_connect.read(buffer_size)
        if not buffer: break

        #an integer value of size of written data
        data_wrote = f.write(buffer)

#you could probably use with-open-as manner
url_connect.close()

Esta respuesta proporciona una solución a HTTP 403 Prohibido al descargar archivos a través de http utilizando Python. He intentado solo solicitudes y módulos urllib, el otro módulo puede proporcionar algo mejor, pero este es el que usé para resolver la mayoría de los problemas.

Sphynx-HenryAY
fuente
0

Respuesta tardía, pero para python>=3.6que pueda usar:

import dload
dload.save(url)

Instalar dloadcon:

pip3 install dload
CONvid19
fuente
0

Quería descargar todos los archivos de una página web. Lo intenté wgetpero estaba fallando, así que decidí por la ruta de Python y encontré este hilo.

Después de leerlo, hice una pequeña aplicación de línea de comandos soupget, ampliando las excelentes respuestas de PabloG y Stan y agregando algunas opciones útiles.

Utiliza BeatifulSoup para recopilar todas las URL de la página y luego descargar las que tengan las extensiones deseadas. Finalmente, puede descargar varios archivos en paralelo.

Aquí está:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import (division, absolute_import, print_function, unicode_literals)
import sys, os, argparse
from bs4 import BeautifulSoup

# --- insert Stan's script here ---
# if sys.version_info >= (3,): 
#...
#...
# def download_file(url, dest=None): 
#...
#...

# --- new stuff ---
def collect_all_url(page_url, extensions):
    """
    Recovers all links in page_url checking for all the desired extensions
    """
    conn = urllib2.urlopen(page_url)
    html = conn.read()
    soup = BeautifulSoup(html, 'lxml')
    links = soup.find_all('a')

    results = []    
    for tag in links:
        link = tag.get('href', None)
        if link is not None: 
            for e in extensions:
                if e in link:
                    # Fallback for badly defined links
                    # checks for missing scheme or netloc
                    if bool(urlparse.urlparse(link).scheme) and bool(urlparse.urlparse(link).netloc):
                        results.append(link)
                    else:
                        new_url=urlparse.urljoin(page_url,link)                        
                        results.append(new_url)
    return results

if __name__ == "__main__":  # Only run if this file is called directly
    # Command line arguments
    parser = argparse.ArgumentParser(
        description='Download all files from a webpage.')
    parser.add_argument(
        '-u', '--url', 
        help='Page url to request')
    parser.add_argument(
        '-e', '--ext', 
        nargs='+',
        help='Extension(s) to find')    
    parser.add_argument(
        '-d', '--dest', 
        default=None,
        help='Destination where to save the files')
    parser.add_argument(
        '-p', '--par', 
        action='store_true', default=False, 
        help="Turns on parallel download")
    args = parser.parse_args()

    # Recover files to download
    all_links = collect_all_url(args.url, args.ext)

    # Download
    if not args.par:
        for l in all_links:
            try:
                filename = download_file(l, args.dest)
                print(l)
            except Exception as e:
                print("Error while downloading: {}".format(e))
    else:
        from multiprocessing.pool import ThreadPool
        results = ThreadPool(10).imap_unordered(
            lambda x: download_file(x, args.dest), all_links)
        for p in results:
            print(p)

Un ejemplo de su uso es:

python3 soupget.py -p -e <list of extensions> -d <destination_folder> -u <target_webpage>

Y un ejemplo real si quieres verlo en acción:

python3 soupget.py -p -e .xlsx .pdf .csv -u https://healthdata.gov/dataset/chemicals-cosmetics
Gibbone
fuente