Как узнать, успешно ли urllib.urlretrieve? - PullRequest
53 голосов
/ 12 июня 2009

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.

Кто-нибудь может предоставить информацию об этой проблеме?

Ответы [ 8 ]

26 голосов
/ 12 июня 2009

Попробуйте использовать urllib2, если это возможно в вашем случае. Он более продвинут и прост в использовании, чем urllib.

Вы можете легко обнаружить любые ошибки HTTP:

>>> import urllib2
>>> resp = urllib2.urlopen("http://google.com/abc.jpg")
Traceback (most recent call last):
<<MANY LINES SKIPPED>>
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()
"<<ACTUAL HTML>>"
6 голосов
/ 16 марта 2012

У меня все просто:

# Simple downloading with progress indicator, by Cees Timmerman, 16mar12.

import urllib2

remote = r"http://some.big.file"
local = r"c:\downloads\bigfile.dat"

u = urllib2.urlopen(remote)
h = u.info()
totalSize = int(h["Content-Length"])

print "Downloading %s bytes..." % totalSize,
fp = open(local, 'wb')

blockSize = 8192 #100000 # urllib.urlretrieve uses 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
        print "%2d%%" % percent,
        if percent < 100:
            print "\b\b\b\b\b",  # Erase "NN% "
        else:
            print "Done."

fp.flush()
fp.close()
if not totalSize:
    print
3 голосов
/ 12 июня 2009

Согласно документации есть без документов

чтобы получить доступ к сообщению, похоже, что вы делаете что-то вроде:

a, b=urllib.urlretrieve('http://google.com/abc.jpg', r'c:\abc.jpg')

b - это экземпляр сообщения

Поскольку я узнал, что Python всегда полезно использовать способность Python быть интроспективным, когда я печатаю

dir(b) 

Я вижу множество методов или функций, с которыми можно играть

А потом я начал делать вещи с b

например

b.items()

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

Извините, это ответ такого новичка, но я пытаюсь освоить, как использовать способности самоанализа для улучшения моего обучения, и ваши вопросы только что всплыли.

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

needparam=[]
for each in dir(b):
    x='b.'+each+'()'
    try:
        eval(x)
        print x
    except:
        needparam.append(x)
2 голосов
/ 03 января 2010

Вы можете создать новый URLopener (наследовать от FancyURLopener) и генерировать исключения или обрабатывать ошибки любым удобным для вас способом. К сожалению, FancyURLopener игнорирует 404 и другие ошибки. Смотрите этот вопрос:

Как отловить ошибку 404 в urllib.urlretrieve

1 голос
/ 13 июня 2009

Я закончил с моей собственной реализацией 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
0 голосов
/ 08 марта 2016

Результаты по отношению к другому серверу / веб-сайту - то, что возвращается в «B», немного случайное, но можно проверить на определенные значения:

A: get_good.jpg
B: Date: Tue, 08 Mar 2016 00:44:19 GMT
Server: Apache
Last-Modified: Sat, 02 Jan 2016 09:17:21 GMT
ETag: "524cf9-18afe-528565aef9ef0"
Accept-Ranges: bytes
Content-Length: 101118
Connection: close
Content-Type: image/jpeg

A: get_bad.jpg
B: Date: Tue, 08 Mar 2016 00:44:20 GMT
Server: Apache
Content-Length: 1363
X-Frame-Options: deny
Connection: close
Content-Type: text/html

В «плохом» случае (несуществующий файл изображения) «B» извлек небольшой фрагмент (Googlebot?) HTML-кода и сохранил его в качестве цели, следовательно, Content-Length 1363 байта.

0 голосов
/ 08 марта 2016

:) Мой первый пост на StackOverflow уже много лет скрытно. :)

К сожалению, dir (urllib.urlretrieve) испытывает недостаток в полезной информации. Итак, из этой ветки до сих пор я пытался написать это:

a,b = urllib.urlretrieve(imgURL, saveTo)
print "A:", a
print "B:", b

, который произвел это:

A: /home/myuser/targetfile.gif
B: Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Cache-Control: max-age=604800
Content-Type: image/gif
Date: Mon, 07 Mar 2016 23:37:34 GMT
Etag: "4e1a5d9cc0857184df682518b9b0da33"
Last-Modified: Sun, 06 Mar 2016 21:16:48 GMT
Server: ECS (hnd/057A)
Timing-Allow-Origin: *
X-Cache: HIT
Content-Length: 27027
Connection: close

Полагаю, можно проверить:

if b.Content-Length > 0:

Мой следующий шаг - протестировать сценарий, в котором получение не удается ...

0 голосов
/ 03 марта 2016
class MyURLopener(urllib.FancyURLopener):
    http_error_default = urllib.URLopener.http_error_default

url = "http://page404.com"
filename = "download.txt"
def reporthook(blockcount, blocksize, totalsize):
    pass
    ...

try:
    (f,headers)=MyURLopener().retrieve(url, filename, reporthook)
except Exception, e:
    print e
...