Pregunta

Tengo una pequeña utilidad que uso para descargar un MP3 de un sitio web según un cronograma y luego compila/actualiza un archivo XML de podcast que obviamente agregué a iTunes.

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

Sin embargo, me costó encontrar una manera de descargar el archivo en Python, por eso recurrí a wget.

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

¿Fue útil?

Solución

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 utilizar la biblioteca, menos el manejo de errores.También puedes hacer cosas más complejas, como cambiar encabezados.La documentación se puede encontrar. aquí.

Otros consejos

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

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 admiración por la barra de progreso.Es genial, seguro.Actualmente existen varias soluciones disponibles en el mercado, entre ellas 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.

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

El wb en 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.

Pitón 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')
    

Pitón 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')
    

utilizar el módulo wget:

import wget
wget.download('url')

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)

Escribió obtener biblioteca en Python puro solo para este propósito.esta inflado urlretrieve con estas características a partir de la versión 2.0.

Simple todavía 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")

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 de "respuesta", puede llamar leer() directamente:

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

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: urlopen y urlretrieve Se ha descubierto que funcionan relativamente mal al descargar archivos grandes (tamaño > 500 MB). requests.get almacena el archivo en la memoria hasta que se completa la descarga.

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

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)

Si tiene wget instalado, puede usar paralelo_sync.

instalación de pip sincronización_paralela

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 error e incluso puede descargar archivos en una máquina remota.

En python3 puedes usar las bibliotecas urllib3 y Shutil.Descárgalos usando pip o pip3 (dependiendo de si python3 es el 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 urllib3 pero usa urllib en codigo

Si la velocidad te importa, hice una pequeña prueba de rendimiento de los módulos. urllib y wget, y respecto a wget Lo intenté una vez con la barra de estado y otra 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é bajo el 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 fue utilizando 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 mas rapido

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 manejar FTP, redirecciones, servidores proxy HTTP, puede evitar volver a descargar archivos existentes (-nc), y aria2 Puede realizar descargas con múltiples conexiones, lo que potencialmente puede 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

El código fuente puede ser:

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

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 archivo .zip de prueba de 4 MB desde mi sitio web.

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

Puede que esto sea un poco tarde, pero vi el código de pabloG y no pude evitar agregar un os.system('cls') para que se vea IMPRESIONANTE.É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 que no sea 'cls'.En MAC OS X y Linux debería estar "claro".

urlretrieve y request.get son simples, pero en 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 archivos a través de http usando Python.Solo probé los módulos request y urllib, el otro módulo puede proporcionar algo mejor, pero este es el que usé para resolver la mayoría de los problemas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top