Как узнать, успешен ли вызов urllib.urlretrieve?
Функция urllib.urlretrieve
возвращает результат без каких-либо сообщений, даже если файл не существует на удаленном HTTP-сервере. В этом случае вместо ожидаемого файла просто сохраняется HTML-страница под заданным именем. Например:
urllib.urlretrieve('http://google.com/abc.jpg', 'abc.jpg')
В этом случае функция выполняется без каких-либо уведомлений, даже если файл abc.jpg
не существует на сервере google.com. Сгенерированный файл abc.jpg
оказывается недействительным JPG-файлом - это на самом деле HTML-страница. Я предполагаю, что заголовки, возвращенные в ответе (экземпляр httplib.HTTPMessage
), можно использовать для определения успешности загрузки файла, но я не могу найти документации для httplib.HTTPMessage
.
Может кто-то предоставить информацию или советы по решению этой проблемы?
5 ответ(ов)
Рекомендуется использовать urllib2
, если это возможно в вашем случае. Этот модуль более продвинутый и проще в использовании, чем urllib
.
Вы можете легко обнаружить любые ошибки HTTP:
>>> import urllib2
>>> resp = urllib2.urlopen("http://google.com/abc.jpg")
Traceback (most recent call last):
<<МНОГО СТРОК ПРОПУЩЕНО>>
urllib2.HTTPError: HTTP Error 404: Not Found
На самом деле resp
— это объект HTTPResponse
, с которым вы можете делать множество полезных вещей:
>>> resp = urllib2.urlopen("http://google.com/")
>>> resp.code
200
>>> resp.headers["content-type"]
'text/html; charset=windows-1251'
>>> resp.read()
"<<АКТУАЛЬНЫЙ HTML>>"
Вот простой способ загрузки файла с индикатором прогресса, используя Python:
# Простое скачивание с индикатором прогресса, автор Cees Timmerman, 16мар12.
import urllib2
remote = r"http://some.big.file" # URL файла
local = r"c:\downloads\bigfile.dat" # Путь для сохранения файла
u = urllib2.urlopen(remote) # Открываем URL
h = u.info() # Получаем информацию о файле
totalSize = int(h["Content-Length"]) # Получаем размер файла
print "Скачивание %s байт..." % totalSize,
fp = open(local, 'wb') # Открываем локальный файл для записи
blockSize = 8192 # Размер блока для чтения
count = 0
while True:
chunk = u.read(blockSize) # Читаем блоки файла
if not chunk: break # Если блок пустой, выходим из цикла
fp.write(chunk) # Записываем блок в файл
count += 1
if totalSize > 0: # Если размер известен
percent = int(count * blockSize * 100 / totalSize) # Рассчитываем процент завершения
if percent > 100: percent = 100 # Ограничиваем процент 100
print "%2d%%" % percent, # Выводим процент
if percent < 100:
print "\b\b\b\b\b", # Стираем "NN% "
else:
print "Готово." # Если загрузка завершена
fp.flush()
fp.close() # Закрываем файл
if not totalSize: # Если размер неизвестен
print
Этот код позволяет вам скачать файл с указанного URL и отображает процент выполнения загрузки. Убедитесь, что у вас есть необходимые права на запись в указанную директорию.
Вы можете реализовать собственный метод retrieve
, используя библиотеку pycurl
, которая поддерживает больше протоколов, чем urllib/urllib2. Вот пример реализации, который может быть полезен другим:
import tempfile
import pycurl
import os
def get_filename_parts_from_url(url):
fullname = url.split('/')[-1].split('#')[0].split('?')[0]
t = list(os.path.splitext(fullname))
if t[1]:
t[1] = t[1][1:]
return t
def retrieve(url, filename=None):
if not filename:
garbage, suffix = get_filename_parts_from_url(url)
f = tempfile.NamedTemporaryFile(suffix='.' + suffix, delete=False)
filename = f.name
else:
f = open(filename, 'wb')
c = pycurl.Curl()
c.setopt(pycurl.URL, str(url))
c.setopt(pycurl.WRITEFUNCTION, f.write)
try:
c.perform()
except:
filename = None
finally:
c.close()
f.close()
return filename
Этот код позволяет загружать файлы по URL и сохранять их с правильными расширениями. Если не указать имя файла, будет создан временный файл. В случае ошибок при выполнении операции вы получите значение None
. Надеюсь, это поможет другим пользователям!
Ваш код использует класс MyURLopener
, который расширяет urllib.FancyURLopener
, чтобы скачать файл с указанного URL. Однако в вашем коде есть несколько моментов, которые стоит обсудить. В частности, обработка исключений и использование reporthook
.
Вот пример исправленного кода с небольшими улучшениями:
import urllib
class MyURLopener(urllib.FancyURLopener):
http_error_default = urllib.URLopener.http_error_default
url = "http://page404.com"
filename = "download.txt"
def reporthook(blockcount, blocksize, totalsize):
# Здесь может быть код, который отслеживает прогресс загрузки
if totalsize > 0:
downloaded = blockcount * blocksize
percent = downloaded * 100 / totalsize
print(f"Загружено: {percent:.2f}%")
try:
(f, headers) = MyURLopener().retrieve(url, filename, reporthook)
print(f"Файл загружен и сохранен как {filename}")
except Exception as e:
print(f"Произошла ошибка: {e}")
Объяснение изменений:
Импорт
urllib
: Не забудьте импортировать нужные модули, чтобы код был самодостаточным.Функция
reporthook
: Я добавил пример кода для уведомления о процессе загрузки. Это даст вам более наглядное представление о текущем статусе загрузки.Обработка исключений: Теперь ошибка будет выводиться с более понятным сообщением.
Обмен
print
: Вместо использованияprint e
, я изменил это на более современный форматированный вывод с f-строкой.
Пожалуйста, имейте в виду, что urllib.FancyURLopener
и urllib.URLopener
устарели в Python 3, и лучше использовать urllib.request
или requests
, если вы можете.
Здравствуйте! Добро пожаловать на Stack Overflow. 😃
Что касается вашего вопроса, вы правильно используете urllib.urlretrieve
для загрузки изображения. В результате у вас получается путь к файлу и заголовки ответа сервера. Давайте немного разберемся с тем, что вы получили.
Как вы отметили, a
— это путь к загруженному файлу, а b
представляет собой строку с заголовками ответа. Чтобы проверить, был ли файл загружен успешно, действительно можно воспользоваться Content-Length
, однако вам стоит учитывать, что это значение может не быть доступным для всех запросов, особенно в случае с некоторыми веб-серверами.
Ваш код для проверки выглядит нормально, но для обеспечения надежности я бы рекомендовал использовать исключения для обработки ошибок сети. Например, вы можете использовать конструкцию try-except
, чтобы отлавливать возможные ошибки при выполнении запроса.
Вот пример, как это может выглядеть:
import urllib
try:
a, b = urllib.urlretrieve(imgURL, saveTo)
print("A:", a)
print("B:", b)
if 'Content-Length' in b:
content_length = int(b['Content-Length'])
if content_length > 0:
print("Файл загружен успешно!")
else:
print("Файл пустой.")
else:
print("Не удалось получить размер содержимого.")
except Exception as e:
print("Ошибка при загрузке:", e)
С помощью этого подхода вы сможете более эффективно обрабатывать возможные сбои при загрузке. Если у вас будут дополнительные вопросы или возникнут сложности, не стесняйтесь задавать их! Удачи!
Как скачать файл по HTTP?
Как выполнить URL-кодирование строки запроса в Python?
Поиск локальных IP-адресов с использованием стандартной библиотеки Python
Python3: JSON POST-запрос БЕЗ библиотеки requests
Как декодировать закодированную url-строку Unicode в Python?