Hemen zaude: Hasiera Komunitatea Dokumentazioa Errezetak Web bidez fitxategi bat deskargatu, zatika

Web bidez fitxategi bat deskargatu, zatika

Imaginatu: web formulario baten bidez erabiltzaileari irudi baten url-a eskatzen diozu, gero zure webgunean erakusteko. Gainera irudi horren informazioa gorde nahi duzu: irudi mota eta tamaina. Hala ere ez zara fidatzen erabiltzaileak bidaliko dizun URLaz...

Azalpenik behar ez dutenentzat:

 1      import urllib2
 2      import io
 3      from PIL import Image
 4
 5      def identify_image(url,chunk=5000, max_download=5000000):
 6          current_byte = 0
 7          end_byte = chunk-1
 8          stream = io.BytesIO()
 9          image = None
10
11          while image is None:
12              headers = {
13                  'Range': 'bytes=%s-%s' % (current_byte, end_byte)
14              }
15              req = urllib2.Request(url, headers=headers)
16              print "Downloading chunk: %s" % headers['Range']
17              response = urllib2.urlopen(req)
18              if response.headers['Content-Type'][:5] != 'image':
19                  raise TypeError("Not supported image type: Content-Type")
20              stream.seek(0,2) #bukaerara goaz
21              stream.write(response.read())
22              stream.seek(0)
23              try:
24                  image = Image.open(stream)
25              except IOError:
26                  if int(response.headers['Content-Length']) < chunk:
27                      raise TypeError("Not supported image type: unknown file")
28                  current_byte += chunk
29                  end_byte += chunk
30                  if end_byte > max_download:
31                      raise TypeError("Not supported image type: Max download")
32
33          return (image.size, image.format)

Imaginatu: web formulario baten bidez erabiltzaileari irudi baten url-a eskatzen diozu, gero zure webgunean erakusteko. Gainera irudi horren informazioa gorde nahi duzu: irudi mota eta tamaina.

Hau izan daiteke modu sinplena::
>>> import urllib2
>>> from PIL import Image
>>> bat = urllib2.urlopen('http://www.gisa-elkartea.org/hasiera/1/1/katua_etzanda.jpg/image')
>>> bi = io.BytesIO(bat.read())
>>> im = Image.open(bi)
>>> im.size
(231, 184)
>>> im.format
'JPEG'

Gauza arraro bakarra BytesIO erabiltzearena da, Image.open funtzioak seek funtzioa behar du, eta urlopen-ek ematen diguna ez duenez BytesIO bat erabili behar dugu.

Honek arazo bat du: erabiltzaile gaizto batek izugarri handia den fitxategi bat bidaltzea. Kasu honetan zerbitzariak fitxategi osoa deskargatuko luke, memoria erabat kontsumituz.

Konponbide moduan, fitxategiaren hasierako zati txiki bat bakarrik eskuratu dezakegu. Horretarako HTTP protokoloaren Range goiburukoa erabiliko dugu (12-15 lerroak).

Hasierako zati horretan erantzunaren Content-Type-a begiratu dezakegu; irudia ez bada ez dugu jarraituko (19 lerroa).

Hasierako zati hau PIL bidez egiaztatzen saiatzen gara (24 lerroan); ezezaguna bada IOError salbuespena abiaraziko du. Kasu honetan fitxategiaren hurrengo zatia eskatzen dugu.

Zati berri hau BytesIO-ra gehitu behar dugu. Ezin dugu ziurtatu PIL-ek osorik irakurri duenik, beraz lehenbizi irakurketa kurtsorea bukaerara eramaten dugu, gero jaso dugun zati berria gehitu eta azkenik kurtsorea berriro hasierako puntura eramaten dugu (20-22 lerroak).

Irakurri dugun zatia oraindik nahikoa ez bada eta azkenekoa bada, hau da, eskatu ditugun byte baino gehiago jaso baldin baditugu salbuespena abiarazten dugu (26 lerroa). Berdin deskargatzeko muga gainditu baldin badugu (30 lerroan).

Adibide batzuk:

>>> url = 'http://www.gisa-elkartea.org/hasiera/1/1/katua_etzanda.jpg/image'
>>> # Saiatu 500 byte irakurriz
>>> try:
>>>     print deskargatu(url, chunk=500)
>>> except TypeError as e:
>>>     print e
Downloading chunk: bytes=0-499
((231, 184), 'JPEG')
>>> # Saiatu 50 byte bakarrik irakurriz, 200 baino gutxiago
>>> try:
>>>     print deskargatu(url, chunk=50, max_download=200)
>>> except TypeError as e:
>>>     print e
Downloading chunk: bytes=0-49
Downloading chunk: bytes=50-99
Downloading chunk: bytes=100-149
Downloading chunk: bytes=150-199
Not supported image type: Max download
>>> # Saiatu 50 byte bakarrik irakurriz, muga handiarekin
>>> try:
>>>     print deskargatu(url, chunk=50, max_download=5000)
>>> except TypeError as e:
>>>     print e
Downloading chunk: bytes=0-49
Downloading chunk: bytes=50-99
Downloading chunk: bytes=100-149
Downloading chunk: bytes=150-199
Downloading chunk: bytes=200-249
Downloading chunk: bytes=250-299
Downloading chunk: bytes=300-349
((231, 184), 'JPEG')