Como faço o download de um ficheiro através de HTTP usando Python?

eu tenho um pequeno utilitário que eu uso para baixar um MP3 de um site em um horário e, em seguida, constrói/atualiza um arquivo podcast XML que eu obviamente adicionei ao iTunes.

o processamento de texto que cria/actualiza o ficheiro XML está escrito em Python. Uso o wget dentro de um ficheiro Windows .bat para transferir o MP3 actual. Mas preferia ter todo o utilitário escrito em Python.

Eu lutei para encontrar uma maneira de carregar o arquivo em Python, assim porque recorri a wget.

Então, como faço o download do ficheiro usando Python?

Author: kilojoules, 2008-08-22

21 answers

No Python 2, use o urllib2 que vem com a biblioteca padrão.

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

Esta é a forma mais básica de usar a biblioteca, menos qualquer manipulação de erros. Você também pode fazer coisas mais complexas, como mudar cabeçalhos. A documentação pode ser encontrada aqui.

 391
Author: Corey, 2014-06-05 11:06:21

Mais uma, usando urlretrieve:

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

(para o Python 3+ use ' import urllib.pedido e urlib.pedido.urlretrieve)

Mais um, com uma "barra de progresso"

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()
 963
Author: PabloG, 2016-08-19 12:34:18

Em 2012, use a biblioteca de Pedidos python

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

Os pedidos têm muitas vantagens sobre as alternativas porque a API é muito mais simples. Isto é especialmente verdadeiro se você tiver que fazer autenticação. urllib e urllib2 são muito pouco intuitivos e dolorosos neste caso.


2015-12-30

As pessoas expressaram admiração pela barra de progresso. Tudo bem, claro. Existem várias soluções fora da prateleira agora, incluindo 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 é essencialmente a implementação @kvance descrita há 30 meses.

 302
Author: hughdbrown, 2015-12-31 16:45:47
import urllib2
mp3file = urllib2.urlopen("http://www.example.com/songs/mp3.mp3")
with open('test.mp3','wb') as output:
  output.write(mp3file.read())

O wb em open('test.mp3','wb') abre um ficheiro (e apaga QUALQUER ficheiro existente) no modo binário para que possa gravar dados com ele em vez de apenas texto.

 148
Author: Grant, 2016-03-10 17:14:43

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

Python 2

  • urllib2.urlopen (Corey.)

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

    import urllib
    urllib.urlretrieve('http://www.example.com/songs/mp3.mp3', 'mp3.mp3')
    
 69
Author: bmaupin, 2018-01-03 14:00:12

Uma versão melhorada do 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)
 18
Author: Stan, 2017-08-06 06:32:19

Escreveu wget biblioteca em Python puro apenas para este fim. É bombeado {[[0]} com estas características a partir da versão 2.0.

 16
Author: anatoly techtonik, 2013-09-25 17:55:16

Usar o módulo wget:

import wget
wget.download('url')
 16
Author: Sara Santana, 2015-03-25 12:59:25

Concordo com o Corey, urllib2 é mais completo do que urllib e deve, provavelmente, o módulo usado se você quiser fazer coisas mais complexas, mas para tornar as respostas mais completas, urllib é um simples módulo, se você quer apenas o básico:

import urllib
response = urllib.urlopen('http://www.example.com/sound.mp3')
mp3 = response.read()
Vai funcionar bem. Ou, se você não quiser lidar com o objeto "resposta" você pode chamar Leia() diretamente:
import urllib
mp3 = urllib.urlopen('http://www.example.com/sound.mp3').read()
 12
Author: akdom, 2008-08-22 15:58:52

Simples mas Python 2 & Python 3 o caminho compatível vem com six biblioteca:

from six.moves import urllib
urllib.request.urlretrieve("http://www.example.com/songs/mp3.mp3", "mp3.mp3")
 12
Author: Akif, 2018-01-16 12:05:10

A seguir estão as chamadas mais usadas para descarregar ficheiros em 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 e urlretrieve apresentam um desempenho relativamente mau com o download de ficheiros grandes (tamanho > 500 MB). requests.get guarda o ficheiro na memória até o download estar completo.

 11
Author: Jaydev, 2016-09-19 12:45:10

Você pode obter o feedback do progresso com urlretrieve também:

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)
 6
Author: Marcin Cuprjak, 2014-01-26 13:12:54

Se tiver o wget instalado, poderá usar o parallel_sync.

Pip instalar 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

Isto é muito poderoso. Ele pode baixar arquivos em paralelo , repetir a falha, e pode até baixar arquivos em uma máquina remota.
 5
Author: max, 2015-11-19 23:48:06

Se a velocidade é importante para ti, fiz um pequeno teste de desempenho para os módulos urllib e wget, e em relação a wget tentei uma vez com a barra de estado e uma vez sem ela. Eu tomei três arquivos diferentes 500MB para testar com (arquivos diferentes-para eliminar a chance de que há algum caching acontecendo sob o capô). Testada na máquina debian, com python2.

Primeiro, estes são os resultados (são semelhantes em diferentes corridas):

$ 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
==============

A forma como realizei o teste é usando "perfil" decorador. Este é o 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 o mais rápido

 3
Author: Omer Dagan, 2017-11-03 14:25:38

Em python3 pode usar urllib3 e libraires de shutil. Transfere-os usando o pip ou o pip3 (dependendo se o python3 é por omissão ou não)

pip3 install urllib3 shutil

Então execute 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)

Note que você descarrega urllib3 mas usa urllib no código

 3
Author: Apoorv Agarwal, 2018-02-08 17:37:15

O código-fonte pode ser:

import urllib
sock = urllib.urlopen("http://diveintopython.org/")
htmlSource = sock.read()                            
sock.close()                                        
print htmlSource  
 2
Author: Sherlock Smith, 2013-11-26 14:25:14

Eu escrevi o seguinte, que funciona em vanilla Python 2 ou 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:

  • suporta uma chamada de "barra de progresso".
  • o Download é um teste de 4 MB .nada do meu site.
 1
Author: imallett, 2017-05-13 21:52:30
Urlretrieve e requests.get é simples, no entanto a realidade não. Eu tenho obtido dados para alguns sites, incluindo texto e imagens, os dois acima provavelmente resolver a maioria das tarefas. mas para uma solução mais universal sugiro o uso de urlopen. Como está incluído na Biblioteca Padrão Python 3, o seu código pode ser executado em qualquer máquina que execute Python 3 sem pré-instalação do site-par
import urllib.request
url_request = urllib.request.Request(url, headers=headers)
url_connect = urllib.request.urlopen(url_request)
len_content = url_content.length

#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 resposta fornece uma solução para HTTP 403 proibida ao transferir o ficheiro por http usando Jiboia. Eu tentei apenas pedidos e módulos urllib, o outro módulo pode fornecer algo melhor, mas este é o que eu usei para resolver a maioria dos problemas.

 0
Author: Sphynx-HenryAY, 2017-03-13 13:12:19
Isto pode ser um pouco tarde, mas vi o código do pabloG e não pude deixar de adicionar um so.sistema ('cls') para fazê-lo parecer incrível! Topa-me isto.
    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()

Se estiver a correr num ambiente diferente do Windows, terá de usar outra coisa, depois 'cls'. Em MAC OS X e Linux deve ser 'claro'.

 0
Author: JD3, 2017-05-16 16:46:21

Só por uma questão de exaustividade, também é possível chamar qualquer programa para obter arquivos usando o pacote subprocess. Os programas dedicados à obtenção de ficheiros são mais potentes do que as funções Python como urlretrieve, por exemplo wget podem transferir pastas recursivamente (-R), podem lidar com FTP, redirectos, proxies HTTP, podem evitar o re-download de ficheiros existentes (-nc), e aria2 podem paralelizar as transferências.

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

No caderno Jupyter, também se pode chamar programas directamente com a sintaxe !:

!wget -O example_output_file.html https://example.com
 0
Author: Robin Dinse, 2018-08-29 12:24:49

Pode usar o PycURL nos Python 2 e 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()
 0
Author: gzerone, 2018-09-10 06:01:38