Как мне загрузить файл по HTTP с помощью Python?
Вопрос
У меня есть небольшая утилита, которую я использую для загрузки MP3 с веб-сайта по расписанию, а затем создает / обновляет XML-файл подкаста, который я, очевидно, добавил в iTunes.
Текстовая обработка, которая создает / обновляет XML-файл, написана на Python.Я использую wget внутри Windows .bat
однако файл для загрузки самого MP3-файла.Однако я бы предпочел, чтобы вся утилита была написана на Python.
Однако я изо всех сил пытался найти способ фактически отключить загрузку файла на Python, поэтому я прибегнул к wget
.
Итак, как мне загрузить файл с помощью Python?
Решение
В 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.request
и urllib.request.urlretrieve
)
Еще один, с "индикатором прогресса"
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())
Тот Самый wb
в open('test.mp3','wb')
открывает файл (и удаляет любой существующий файл) в двоичном режиме, чтобы вы могли сохранять в нем данные, а не просто текст.
Python 3
-
import urllib.request response = urllib.request.urlopen('http://www.example.com/') html = response.read()
-
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
(спасибо ПаблоГ)import urllib urllib.urlretrieve('http://www.example.com/songs/mp3.mp3', 'mp3.mp3')
используйте модуль wget:
import wget
wget.download('url')
Улучшенная версия кода 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.
Простой, но Python 2 & Python 3
совместимый способ поставляется с six
библиотека:
from six.moves import urllib
urllib.request.urlretrieve("http://www.example.com/songs/mp3.mp3", "mp3.mp3")
Я согласен с Кори, urllib2 более полон, чем urllib и, вероятно, это должен быть используемый модуль, если вы хотите делать более сложные вещи, но чтобы сделать ответы более полными, urllib - это более простой модуль, если вам нужны только основы:
import urllib
response = urllib.urlopen('http://www.example.com/sound.mp3')
mp3 = response.read()
Будет работать нормально.Или, если вы не хотите иметь дело с объектом "response", вы можете вызвать читать() непосредственно:
import urllib
mp3 = urllib.urlopen('http://www.example.com/sound.mp3').read()
Ниже приведены наиболее часто используемые вызовы для загрузки файлов в python:
urllib.urlretrieve ('url_to_file', file_name)
urllib2.urlopen('url_to_file')
requests.get(url)
wget.download('url', file_name)
Примечание: urlopen
и urlretrieve
установлено, что они относительно плохо работают при загрузке больших файлов (размер > 500 МБ). requests.get
сохраняет файл в памяти до завершения загрузки.
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")
Вы также можете получать обратную связь о ходе выполнения с помощью 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 устанавливает 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)
Док:https://pythonhosted.org/parallel_sync/pages/examples.html
Это довольно мощно.Он может загружать файлы параллельно, повторять попытку при сбое и даже загружать файлы на удаленный компьютер.
В 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
в коде
Если для вас важна скорость, я провел небольшой тест производительности для модулей 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
кажется, это самый быстрый
Просто для полноты картины, также можно вызвать любую программу для извлечения файлов, используя subprocess
посылка.Программы, предназначенные для извлечения файлов, более мощные, чем функции Python, такие как urlretrieve
.Например, wget
может загружать каталоги рекурсивно (-R
), может работать с FTP, редиректами, HTTP-прокси, может избежать повторной загрузки существующих файлов (-nc
), и aria2
может выполнять загрузку с несколькими подключениями, что потенциально может ускорить ваши загрузки.
import subprocess
subprocess.check_output(['wget', '-O', 'example_output_file.html', 'https://example.com'])
В Jupyter Notebook также можно вызывать программы напрямую с помощью !
синтаксис:
!wget -O example_output_file.html https://example.com
Исходный код может быть:
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()
Примечания:
- Поддерживает обратный вызов "индикатора выполнения".
- Скачать можно в формате test .zip размером 4 МБ с моего веб-сайта.
Вы можете использовать ПикУРЛ на 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()
Возможно, это немного запоздало, но я увидел код pabloG и не смог удержаться, чтобы не добавить os.system ('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 это должно быть "понятно".
urlretrieve и requests.get просты, однако на самом деле это не так.Я собрал данные для пары сайтов, включая текст и изображения, два вышеперечисленных, вероятно, решают большинство задач.но для более универсального решения я предлагаю использовать urlopen .Поскольку он включен в стандартную библиотеку Python 3, ваш код может выполняться на любом компьютере, на котором работает Python 3, без предварительной установки site-package
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()
Этот ответ предоставляет решение проблемы HTTP 403, запрещенной при загрузке файла по http с использованием Python.Я пробовал только модули requests и urllib, другой модуль может предоставить что-то лучшее, но это тот, который я использовал для решения большинства проблем.