2009-06-12 3 views
48

urllib.urlretrieve возвращает молча, даже если файл не существует на удаленном http-сервере, он просто сохраняет html-страницу в указанном файле. Например:Как узнать, успешно ли urllib.urlretrieve?

urllib.urlretrieve('http://google.com/abc.jpg', 'abc.jpg') 

просто возвращает молча, даже если abc.jpg не существует на сервере google.com, сгенерированный abc.jpg не является допустимым файлом JPG, это на самом деле HTML-страницы. Я думаю, что возвращенные заголовки (экземпляр httplib.HTTPMessage) могут использоваться для фактического определения того, успешен ли поиск или нет, но я не могу найти какой-либо документ для httplib.HTTPMessage.

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

ответ

22

Рассмотрите возможность использования 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

Может ли urllib2 обеспечить кэширование поведения urlretrieve? Или нам нужно переопределить его? – Kiv

+0

Просмотреть этот бесплатный рецепт из ActiveState: http://code.activestate.com/recipes/491261/ Мы используем его в нашем текущем проекте, работает безупречно –

+1

urlopen не предоставляет функцию hook (чтобы показать индикатор выполнения для пример), как urlretrieve. –

2

Согласно документации является undocumented

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

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

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

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

dir(b) 

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

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

, например

b.items() 

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

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

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

needparam=[] 
for each in dir(b): 
    x='b.'+each+'()' 
    try: 
     eval(x) 
     print x 
    except: 
     needparam.append(x) 
+0

Нет статуса для меня, и ваш код работает только один раз. Попробуйте 'for k in b: print"% s:% r "% (k, b [k])' –

1

Я закончил с моей 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 
2

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

How to catch 404 error in urllib.urlretrieve

6

Я держать его просто:

# 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 
+0

Лучшей идеей является 'shutil.copyfileobj'. – lericson

+1

Как так, lericson? –

0
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 
0

:) Мой первый пост на StackOverflow, были Lurker в течение многих лет. :)

К сожалению, у вас не хватает полезной информации. Так из этой темы до сих пор я пытался писать так:

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

b.getheader ('Content-length') обычно будет больше 0 даже на 404 (если файл не существует) –

0

Результаты на другом сервере/сайте - что возвращается в «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 байт.

Смежные вопросы