Как загрузить файл через HTTP с помощью Python?



у меня есть небольшая утилита, которую я использую для загрузки MP3 с сайта по расписанию, а затем строит/обновляет XML-файл подкаста, который я, очевидно, добавил в iTunes.



обработка текста, которая создает / обновляет XML-файл, написана на Python. Я использую wget внутри Windows .bat файл для загрузки фактического MP3, однако. Я бы предпочел, чтобы вся утилита была написана на Python.



Я изо всех сил пытался найти способ на самом деле вниз загрузить файл в Питон, таким образом, почему я прибегал к wget.



Итак, как мне загрузить файл с помощью Python?

920   21  

21 ответов:

в Python 2 Используйте urllib2, который поставляется со стандартной библиотекой.

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

Это самый простой способ использования библиотеки, за вычетом обработки ошибок. Вы также можете сделать более сложные вещи, такие как изменение заголовков. Документацию можно найти здесь.

еще один, используя urlretrieve:

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

(для Python 3 + Используйте ' import urllib.запрос и urllib.запрос.urlretrieve)

еще один, с "progressbar"

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

в 2012 году, используйте python запрашивает библиотеку

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

вы можете запустить pip install requests, чтобы получить его.

запросы имеют много преимуществ перед альтернативами, потому что API намного проще. Это особенно верно, если вам нужно выполнить аутентификацию. urllib и urllib2 довольно сложным и болезненным в этом случае.


2015-12-30

люди выразили восхищение прогресс-бар. Это круто, конечно. Есть несколько готовые решения теперь, в том числе 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)

это по существу реализация @kvance, описанная 30 месяцев назад.

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

The wb in open('test.mp3','wb') открывает файл (и стирает любой существующий файл) в двоичном режиме, так что вы можете сохранить данные с него, а не просто текст.

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 (спасибо Кори)

    import urllib2
    response = urllib2.urlopen('http://www.example.com/')
    html = response.read()
    
  • urllib.urlretrieve (спасибо PabloG)

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

улучшенная версия кода PabloG для 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)

писал wget библиотека в чистом Python как раз для этой цели. Он накачан urlretrieve с эти функции начиная с версии 2.0.

используйте модуль wget:

import wget
wget.download('url')

Я согласен с Кори, urllib2 является более полным, чем urllib и, вероятно, должен быть модуль, используемый, если вы хотите делать более сложные вещи, но чтобы сделать ответы более полными, urllib-это более простой модуль, если вы хотите только основы:

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

будет работать нормально. Или, если вы не хотите иметь дело с объектом "ответ", вы можете вызвать прочитать() напрямую:

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

простой Python 2 & Python 3 совместим как с six библиотека:

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

Ниже приведены наиболее часто используемые вызовы для загрузки файлов в 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)

Примечание: urlopen и urlretrieve обнаруживаются относительно плохие результаты при загрузке больших файлов (размер > 500 МБ). requests.get сохраняет файл в памяти до завершения загрузки.

вы также можете получить обратную связь о прогрессе с 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)

если у вас установлен wget, вы можете использовать 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

Это довольно мощный. Он может загружать файлы параллельно, повторять попытку при сбое и даже загружать файлы на удаленной машине.

если скорость имеет значение для вас, я сделал небольшой тест производительности для модулей urllib и wget и в отношении wget Я пробовал один раз со строкой состояния и один раз без. Я взял три разных файла по 500 МБ для тестирования (разные файлы-чтобы исключить вероятность того, что под капотом происходит какое-то кэширование). Протестировано на машине debian, с python2.

во-первых, эти результаты (они похожи в разных запусках):

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

как я выполнил тест использует" профиль " декоратора. Это полный код:

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 кажется, самый быстрый

в python3 вы можете использовать urllib3 и shutil libraires. Загрузите их с помощью pip или pip3 (в зависимости от того, является ли python3 по умолчанию или нет)

pip3 install urllib3 shutil

затем запустите этот код

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)

обратите внимание, что вы скачать urllib3 но использовать urllib код

исходный код может быть:

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

Я написал следующее, которое работает в vanilla Python 2 или 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()

Примечания:

  • поддерживает обратный вызов "индикатор выполнения".
  • загрузка-это тест 4 МБ .ЗИП с моего сайта.

urlretrieve и запросы.достать просто, однако реальности нет. Я получил данные для пары сайтов, в том числе текст и изображения, выше два, вероятно, решить большинство задач. но для более универсального решения я предлагаю использовать urlopen. Поскольку он включен в стандартную библиотеку Python 3, ваш код может работать на любой машине, на которой выполняется Python 3 без предварительной установки 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()

этот ответ предоставляет решение для HTTP 403 запрещено при загрузке файла через http с помощью Python. Я пробовал только запросы и модули urllib, другой модуль может предоставить что-то лучше, но это тот, который я использовал для решения большинства проблем.

Это может быть немного поздно, но я видел код pabloG и не мог не добавить ОС.система ('cls'), чтобы она выглядела потрясающе! Проверьте это :

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

Если вы работаете в среде, отличной от Windows, вам придется использовать что-то другое, чем "cls". В MAC OS X и Linux это должно быть "ясно".

просто для полноты картины, также можно вызвать любую программу для извлечения файлов с помощью subprocess пакета. Программы, предназначенные для извлечения файлов, являются более мощными, чем функции Python, такие как urlretrieve, например,wget можно скачать каталоги рекурсивно (-R), может иметь дело с FTP, перенаправляет, HTTP прокси, может избежать повторной загрузки существующих файлов (-nc), и aria2 можно распараллелить загрузки.

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

в ноутбуке Jupyter можно также позвонить программы непосредственно с помощью ! синтаксис:

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

вы можете использовать PycURL на Python 2 и 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()

Comments

    Ничего не найдено.