Hatena::Grouppython

Pythonで遊ぶよ

 | 

2009-08-11

Google App Engineではgzipファイルをダウンロードできない?(解決)

22:49

の続き。

http://wedata.net/databases/AutoPagerize/items.json

は1MBを超えてるけど、ミラーのほうで gzip 圧縮した

http://ss-o.net/json/wedataAutoPagerize.json.gz

は100KBちょっとしかないよ、と教えてもらった。


じゃあ gzip ダウンロードに挑戦してみよう、ってことでやってみたのだけど、何故か SDK、本番環境とも動かない。


まずは普通の Python スクリプト

import urllib, gzip, StringIO

response = urllib.urlopen('http://ss-o.net/json/wedataAutoPagerize.json.gz')
raw_data = response.read()
print 'data length : '+str(len(raw_data))
stream = StringIO.StringIO(raw_data)
decompressor = gzip.GzipFile(fileobj=stream)
text = decompressor.read()
print 'json length : '+str(len(text))

GzipFile(fileobj=stream) というところがポイント。擬似的なファイルっぽいオブジェクトとして gzip を開ける。

結果。

% python download.py 
data length : 186577
json length : 1062763

うまくいってる。


しかし、Google App EngineSDK でやると、こんなエラーが。

% dev_appserver.py -c .
WARNING:root:Could not read datastore data from /var/folders/kY/kYtckUvwG+q0apltUK4XwE+++TM/-Tmp-/dev_appserver.datastore
WARNING:root:Could not read datastore data from /var/folders/kY/kYtckUvwG+q0apltUK4XwE+++TM/-Tmp-/dev_appserver.datastore.history
WARNING:root:Could not initialize images API; you are likely missing the Python "PIL" module. ImportError: No module named _imaging
DEBUG:root:Could not import "icglue": Disallowed C-extension or built-in module
WARNING:root:Stripped prohibited headers from URLFetch request: ['Host']
DEBUG:root:Making HTTP request: host = ss-o.net, url = http://ss-o.net/json/wedataAutoPagerize.json.gz, payload = None, headers = {'Host': 'ss-o.net', 'Referer': 'http://localhost/', 'Accept-Encoding': 'gzip', 'User-Agent': 'Python-urllib/1.17 AppEngine-Google; (+http://code.google.com/appengine)'}
ERROR:root:Not a gzipped file
Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 507, in __call__
    handler.get(*groups)
  File "/Users/atsushi/Dropbox/Programming/gae/Atsushuu/siteinfo.py", line 275, in get
    json = decompressor.read()
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/gzip.py", line 220, in read
    self._read(readsize)
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/gzip.py", line 263, in _read
    self._read_gzip_header()
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/gzip.py", line 164, in _read_gzip_header
    raise IOError, 'Not a gzipped file'
IOError: Not a gzipped file

どうやら gzipダウンロードしているのに response.read() した時点で既に普通のテキストファイルになっている模様。

本番環境だと、普通のテキストファイルになって、さらにそれが 1MB を超えているので、途中でぶった切られてしまう。

urllib じゃなくて urlfetch を使っても同じ。本番だと ResponseTooLargeError が出る。


DEBUG:root:Could not import "icglue": Disallowed C-extension or built-in module というのが怪しい気もするけど、違う気もする。


なんでだ。

メーリングリストで聞いてみた


自動展開されるみたい

どうやら gzip ファイルとしてダウンロードされているんだけど、自動的に展開されるみたい。

SDKサーバー上で cProfile を使って確認したところ、gzip.py が呼ばれてる。

import cProfile
profile = cProfile.run("urlfetch.fetch('http://***.gz')")

もうちょっと調べると、

/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/urlfetch_stub.py

というファイルで import gzip してるのを発見。

        if http_response.getheader('content-encoding') == 'gzip':
          gzip_stream = StringIO.StringIO(http_response_data)
          gzip_file = gzip.GzipFile(fileobj=gzip_stream)
          http_response_data = gzip_file.read()    # ← ここと
        response.set_content(http_response_data[:MAX_RESPONSE_SIZE])  # ← ここに注目

ぶった切られていた理由が分かった。余計なことしやがって…

とりあえず、gzip ファイルがダウンロードできないわけではないことは分かった。

サーバーContent-Encoding : gzip で送ってこなければ gzip ファイルでも展開されないっぽい。


SITEINFO に関しては

os0x さんに頼んで http://ss-o.net/json/wedataAutoPagerize を http://ss-o.net/json/wedataAutoPagerize.json.gz への alias にしてもらったので、そっちを使えば Content-Encoding : gzip が付いてないので上の手順でダウンロード & 展開できる。

トラックバック - http://python.g.hatena.ne.jp/edvakf/20090811
 |