0

Как узнать, успешен ли вызов urllib.urlretrieve?

15

Функция 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 ответ(ов)

0

Рекомендуется использовать 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>>"
0

Вот простой способ загрузки файла с индикатором прогресса, используя 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 и отображает процент выполнения загрузки. Убедитесь, что у вас есть необходимые права на запись в указанную директорию.

0

Вы можете реализовать собственный метод 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. Надеюсь, это поможет другим пользователям!

0

Ваш код использует класс 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}")

Объяснение изменений:

  1. Импорт urllib: Не забудьте импортировать нужные модули, чтобы код был самодостаточным.

  2. Функция reporthook: Я добавил пример кода для уведомления о процессе загрузки. Это даст вам более наглядное представление о текущем статусе загрузки.

  3. Обработка исключений: Теперь ошибка будет выводиться с более понятным сообщением.

  4. Обмен print: Вместо использования print e, я изменил это на более современный форматированный вывод с f-строкой.

Пожалуйста, имейте в виду, что urllib.FancyURLopener и urllib.URLopener устарели в Python 3, и лучше использовать urllib.request или requests, если вы можете.

0

Здравствуйте! Добро пожаловать на 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)

С помощью этого подхода вы сможете более эффективно обрабатывать возможные сбои при загрузке. Если у вас будут дополнительные вопросы или возникнут сложности, не стесняйтесь задавать их! Удачи!

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь