¿Cómo descargar un archivo a través de HTTP?

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

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

Luché por encontrar una manera de descargar el archivo en Python, por lo que recurrí a usar wget.

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

preguntado el 22 de agosto de 08 a las 13:08

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 de archivo de 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 simplemente invocar wget de Python. -

Solución corta para Python 3: import urllib.request; s = urllib.request.urlopen('http://example.com/').read().decode() -

25 Respuestas

Utilice las urllib.request.urlopen():

import urllib.request
with urllib.request.urlopen('http://www.example.com/') as f:
    html = f.read().decode('utf-8')

Esta es la forma más básica de usar la biblioteca, menos el manejo de errores. También puede hacer cosas más complejas, como cambiar encabezados.

En Python 2, el método está en urllib2:

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

Respondido el 21 de junio de 20 a las 16:06

Esto no funcionará si hay espacios en la URL que proporcionas. En ese caso, deberá analizar la URL y codificar la ruta con urlencode. - jason sundram

Aquí está la solución de Python 3: stackoverflow.com/questions/7243750/… - tommy.carstensen

Solo para referencia. La forma de codificar urlen la ruta es urllib2.quote - André Puel

@JasonSundram: si hay espacios en él, no es un URI. - Zaz

Esto no funciona en Windows con archivos más grandes. ¡Necesitas leer todos los bloques! - Avia

Uno más, usando urlretrieve:

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

(para uso de Python 3+ import urllib.request y 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()

Respondido 16 Abr '19, 16:04

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. - En caída libre

Error: file_size_dl + = block_sz debería ser + = len (búfer) ya que la última lectura a menudo no es un block_sz completo. También en Windows es necesario abrir el archivo de salida como "wb" si no es un archivo de texto. - Berenjena Jeff

Yo también urllib y urllib2 no funcionaron pero urlretrieve funcionó bien, se estaba frustrando - gracias :) - funk-shun

Envuelva todo (excepto la definición de file_name) con if not os.path.isfile(file_name): para evitar sobrescribir los podcasts. útil cuando se ejecuta como un cronjob con las URL que se encuentran en un archivo .html - Sriram Murali

Según la documentación, urllib.request.urlretrieve es una "interfaz heredada" y "podría quedar obsoleta en el futuro. docs.python.org/3/library/urllib.request.html#legacy-interface - Luis Yang

En 2012, utilice el biblioteca de solicitudes de Python

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

Tu puedes correr pip install requests para conseguirlo.

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


2015-12-30

La gente ha expresado su admiración por la barra de progreso. Es genial, seguro. Ahora hay varias soluciones listas para usar, 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.

respondido 24 mar '20, 12:03

¿Cómo maneja esto archivos grandes, todo se almacena en la memoria o se puede escribir en un archivo sin un gran requisito de memoria? - bibstha

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. - avance

¿Por qué una biblioteca de URL debería tener una función de descompresión de archivos? Lea el archivo de la url, guárdelo y luego descomprímalo de la forma que tenga su barco. Además, un archivo zip no es una 'carpeta' como se muestra en Windows, es un archivo. - Harel

@Ali: r.text: Para contenido de texto o 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

Creo que un chunk_size el argumento es deseable junto con stream=True. El valor por defecto chunk_size is 1, lo que significa que cada fragmento puede ser tan pequeño como 1 byte y, por lo tanto, es muy ineficiente. - haridsv

import urllib2
mp3file = urllib2.urlopen("http://www.example.com/songs/mp3.mp3")
with open('test.mp3','wb') as output:
  output.write(mp3file.read())

Los programas wb in open('test.mp3','wb') abre un archivo (y borra cualquier archivo existente) en modo binario para que pueda guardar datos con él en lugar de solo texto.

respondido 10 mar '16, 17:03

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 para archivos grandes en un sistema pequeño como un enrutador con memoria RAM limitada. - triplete

@tripplet, ¿cómo solucionaríamos eso? - Lucas Henriquez

Para evitar leer todo el archivo en la memoria, intente pasar un argumento a file.read ese es el número de bytes a leer. Ver: gist.github.com/hughdbrown/c145b8385a2afa6570e2 - hughdbrown

@hughdbrown Encontré su secuencia de comandos útil, pero tengo una pregunta: ¿puedo usar el archivo para el posprocesamiento? supongo que descargo un archivo jpg que quiero procesar con OpenCV, ¿puedo usar la variable 'datos' para seguir trabajando? ¿O tengo que volver a leerlo del archivo descargado? - Rodrigo E. Príncipe

Utilice las shutil.copyfileobj(mp3file, output) en lugar de. - Aurelien Ooms

3 Python

  • 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: Según la documentación, urllib.request.urlretrieve es una "interfaz heredada" y "podría quedar obsoleta en el futuro" (gracias Gerrit)

2 Python

  • 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')
    

respondido 30 mar '20, 13:03

Seguro que tomó un tiempo, pero finalmente está la API sencilla y directa que espero de un stdlib de Python :) - ThorInvocador

Muy buena respuesta para python3, ver también docs.python.org/3/library/… - Eduardo Thiel

@EdouardThiel Si hace clic en urllib.request.urlretrieve arriba lo llevará a ese enlace exacto. ¡Salud! - bmaupin

urllib.request.urlretrieve está documentado como una "interfaz heredada" y "podría quedar obsoleta en el futuro". - Gerrit

Debe mencionar que está obteniendo un montón de bytes que deben manejarse después de eso. - Thoroc

utilizan el módulo wget:

import wget
wget.download('url')

Respondido el 25 de junio de 20 a las 20:06

El repositorio parece haber sido eliminado. - Bahman Eslami

El proyecto fue movido a github, pero luego archivado por su autor - aleo

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")

respondido 05 nov., 18:11

Gracias, también, reemplace with open(file_name,... con with open('thisname'...) porque puede arrojar un error - anindya prithvi

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)

Respondido 06 ago 17, 07:08

Quitaría los paréntesis de la primera línea, porque no es una característica demasiado antigua. - Arpad Horvath

Simple pero Python 2 & Python 3 forma compatible viene con six biblioteca:

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

Respondido el 16 de enero de 18 a las 12:01

Esta es la mejor manera de hacerlo para la compatibilidad 2 + 3. - fush

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

Respondido el 25 de Septiembre de 13 a las 18:09

¿No tiene opción de guardar con un nombre de archivo personalizado? - Alex

@Alex agregó la opción -o FILENAME a la versión 2.1 - anatoly techtonik

La barra de progreso no aparece cuando utilizo este módulo en Cygwin. - codificador joe

Deberías cambiar de -o a -O para evitar confusiones, como está en GNU wget. O al menos ambas opciones deberían ser válidas. - erik

@eric no estoy seguro de querer hacer wget.py un reemplazo in situ de real wget. -o ya se comporta de manera diferente, es compatible con curl Por aquí. ¿Una nota en la documentación ayudaría a resolver el problema? ¿O es la característica esencial para que una utilidad con ese nombre sea compatible con la línea de comandos? - anatoly techtonik

A continuación se muestran 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: urlopen y urlretrieve tienen un rendimiento relativamente malo con la descarga de archivos grandes (tamaño> 500 MB). requests.get almacena el archivo en la memoria hasta que se completa la descarga.

Respondido el 19 de Septiembre de 16 a las 13:09

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

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

Funcionará bien. O, si no quiere lidiar con el objeto "respuesta", puede llamar leer() directamente:

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

Respondido 22 ago 08, 16:08

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

pip3 install urllib3 shutil

Entonces 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 urllib3 pero usa urllib en codigo

Respondido 08 Feb 18, 17:02

Si tiene wget instalado, puede usar paralel_sync.

pip instalar paralel_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, reintentar en caso de falla e incluso puede descargar archivos en una máquina remota.

respondido 19 nov., 15:23

Tenga en cuenta que esto es solo para Linux: jjj

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)

Respondido el 26 de enero de 14 a las 13:01

Si la velocidad te importa, hice una pequeña prueba de rendimiento para los módulos. urllib y wget, y con respecto wget Lo intenté una vez con la barra de estado y una vez sin ella. Tomé tres archivos diferentes de 500 MB para probar (archivos diferentes, para eliminar la posibilidad de que haya algo de almacenamiento en caché debajo del capó). Probado en una 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 fue utilizando el decorador de "perfiles". 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 mas rapido

respondido 03 nov., 17:14

Debe haber algo completamente horrible debajo del capó para que la barra aumente tanto el tiempo. - Alistair Carscadden

Solo para completar, también es posible llamar a cualquier programa para recuperar archivos usando el subprocess paquete. Los programas dedicados a recuperar archivos son más poderosos que las funciones de Python como urlretrieve. Por ejemplo, wget puede descargar directorios de forma recursiva (-R), puede lidiar con FTP, redirecciones, proxies HTTP, puede evitar volver a descargar archivos existentes (-nc), y aria2 puede realizar descargas de múltiples conexiones 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 el ! sintaxis:

!wget -O example_output_file.html https://example.com

Respondido el 10 de diciembre de 18 a las 14:12

El código fuente puede ser:

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

respondido 26 nov., 13:14

Escribí lo siguiente, que funciona en vanilla 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.

contestado el 13 de mayo de 17 a las 22:05

funciona muy bien, ejecútelo a través de jupyter tengo lo que quiero :-) - Samir Ould Saadi

Puedes 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()

Respondido el 02 de enero de 19 a las 12:01

Esto puede ser un poco tarde, ¡pero vi el código de pabloG y no pude evitar agregar un os.system ('cls') para que se vea INCREÍBLE! Échale 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, tendrá que usar algo diferente a 'cls'. En MAC OS X y Linux debería estar "claro".

contestado el 16 de mayo de 17 a las 17:05

cls no hace nada en mi OS X ni en mi servidor Ubuntu. Alguna aclaración podría ser buena. - kww

Creo que deberías usar clear para linux, o incluso mejor reemplace la línea de impresión en lugar de borrar toda la salida de la línea de comandos. - Arijoon

esta respuesta simplemente copia otra respuesta y agrega una llamada a una función obsoleta (os.system()) que lanza un subproceso para borrar la pantalla usando un comando específico de la plataforma (cls). ¿Cómo tiene esto cualquier votos a favor ?? Totalmente inútil "respuesta" en mi humilde opinión. - corey goldberg

urlretrieve y request.get son simples, pero la realidad no. He obtenido datos de un par de sitios, incluidos texto e imágenes, los dos anteriores probablemente resuelvan 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 un archivo a través de http usando Python. He probado 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.

contestado el 03 de mayo de 19 a las 14:05

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

import dload
dload.save(url)

Instale dload con:

pip3 install dload

Respondido 24 Feb 20, 07:02

Puedo preguntar: ¿dónde se guarda el archivo una vez que se ejecuta el programa? Además, ¿hay alguna forma de nombrarlo y guardarlo en una ubicación específica? Este es el enlace con el que estoy trabajando; cuando haces clic en el enlace, se descarga inmediatamente un archivo de Excel: ons.gov.uk/generator?format=xls&uri=/economy/… - Josué Tinashe

Puede proporcionar la ubicación de guardado como segundo argumento, por ejemplo: dload.save(url, "/home/user/test.xls") - Pedro Lobito

Quería descargar todos los archivos de una página web. Lo intenté wget pero estaba fallando, así que me 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 Hermosa Sopa para recopilar todas las URL de la página y luego descargar las que tienen las extensiones deseadas. Finalmente, puede descargar varios archivos en paralelo.

Aquí es:

#!/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

respondido 09 mar '20, 15:03

Otra forma es llamar a un proceso externo como curl.exe. Curl de forma predeterminada muestra una barra de progreso, la velocidad de descarga promedio, el tiempo restante y más, todo en forma ordenada en una tabla. Coloque curl.exe en el mismo directorio que su script

from subprocess import call
url = ""
call(["curl", {url}, '--output', "song.mp3"])

Nota: No puede especificar una ruta de salida con curl, así que haga un cambio de nombre de os.

Respondido el 14 de Septiembre de 20 a las 01:09

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.