ファイルのダウンロード

連番を開くスクリプトを書いたので、せっかくだから開いたurlからファイルをダウンロードするスクリプトをつくってみようかと思ったのだけれど巧くいかない。
urllibのリファレンスに

urlretrieve( url[, filename[, reporthook[, data]]])

URL で表されるネットワーク上のオブジェクトを、必要に応じてローカルなファイルにコピーします

ってあったので使ってみたのだけれど、コレ、404ファイルもダウンロード(?)してきちゃう。
指定したurlが間違っていても気付かない。困った。
とりあえず、吐き出すモンぜんぶ吐き出させて指定したurlのファイル有無を判定できるか調べてみる。

#!/bin/env python
# -*- coding: shift_jis -*-
import urllib

def feedback(count,size, total):
    print "count :%d" % count
    print "size  :%d" % size
    print "total :%d" % total

(file, header) = urllib.urlretrieve("http://www.google.co.jp/","test.html",feedback)
print file
print header 

feedback ダウンロードのレポート(ブロックのカウントとサイズ、トータル)
file   指定したファイル名
header HTTP応答ヘッダ

応答ヘッダで判定すればいいのかな?
とりあえずググッてみたら、外人さんのソースにこんなのがあった。

(tmp, headers) = urllib.urlretrieve("http://www.google.co.jp/","test.html")
if str(headers).count("Content-Length") == 0:
    print "ERROR: File not found (404 error)"

headersの中のContent-Lengthの数を数えて、それが0だったら404エラーと判定しているみたい。
でも、これだとContent-Lengthさえ応答ヘッダに含まれていればやっぱり存在しないファイルでもダウンロードしてきちゃうよ〜ん
とりあえず試してみた

#!/bin/env python
# -*- coding: shift_jis -*-
import urllib

(tmp, headers) = urllib.urlretrieve("http://www.google.co.jp/aa/bb/cc.gif","test.gif")
print str(headers).count("Content-Length")
print headers
if str(headers).count("Content-Length") == 0:
   print "ERROR: File not found (404 error)"
else:
   print "OK"

ちゃんと"ERROR: File not found (404 error)"がでた。
でも、よく見るとgoogleの応答ヘッダには「Content-length: 1223」とある。
う〜ん「Length」では「length」をカウントしないので404を出してしまう。やっぱり駄目ジャン。
要再考。

追記urllib2モジュールでは、ちゃんと404を検出するらしい。

>>> import urllib
>>> urllib.urlopen("http://www.google.co.jp/aa/bb/cc.gif")
>
>>> import urllib2
>>> urllib2.urlopen("http://www.google.co.jp/aa/bb/cc.gif")

Traceback (most recent call last):
  File "", line 1, in -toplevel-
    urllib2.urlopen("http://www.google.co.jp/aa/bb/cc.gif")
  File "c:\Python23\lib\urllib2.py", line 129, in urlopen
    return _opener.open(url, data)
  File "c:\Python23\lib\urllib2.py", line 326, in open
    '_open', req)
  File "c:\Python23\lib\urllib2.py", line 306, in _call_chain
    result = func(*args)
  File "c:\Python23\lib\urllib2.py", line 901, in http_open
    return self.do_open(httplib.HTTP, req)
  File "c:\Python23\lib\urllib2.py", line 895, in do_open
    return self.parent.error('http', req, fp, code, msg, hdrs)
  File "c:\Python23\lib\urllib2.py", line 352, in error
    return self._call_chain(*args)
  File "c:\Python23\lib\urllib2.py", line 306, in _call_chain
    result = func(*args)
  File "c:\Python23\lib\urllib2.py", line 412, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
HTTPError: HTTP Error 404: Not Found
>>> 

ちゃんと例外がでる、urllib2を使ったほうがいいみたい。
※参考
urllib.urlopen() fails to raise exception
http://mail.python.org/pipermail/python-bugs-list/2004-July/023990.html