2

I am using a python library (poster) that takes a file-like object as an argument, the documentation states:

The file-like objects must support .read() and either .fileno() or both .seek() and .tell().

I have tried the library using the python open function and it works fine. I am currently downloading an image from a URL using the following:

access_token = "XXXXXXXXXXXXXXXXXXXXX"
postPhotoUrl = "https://graph.facebook.com/me/photos?access_token=%s" % access_token

register_openers()

# get image from external URL
data = urllib2.urlopen("http://example.com/image.png")
data = StringIO(data.read())

### data, headers = multipart_encode({"source":open("file.png")}) <- WORKS FINE
data, headers = multipart_encode({"source":data})
request = urllib2.Request(postPhotoUrl,data,headers)

EDIT: My goal is to fetch an image from an external URL and POST it using the facebook graph api. When I use the python open function I have no issues. When I try to use StringIO, no body is sent with the POST request.

4

1 回答 1

4

If the idea is to use the poster package to do a streaming HTTP upload, you shouldn't be converting the image data into a PIL Image object. Just do...

data = urllib2.urlopen("http://example.com/image.png")
data = StringIO(data.read())

...then you can pass the data variable to poster.

Unless, of course, you wanted to convert the image with PIL first, but you should probably mention that in your question.

Update

As for why it fails with a StringIO, it might be that poster is checking the filename of the open file, and using that to determine the correct Content-Type or somesuch, which it won't be able to do when reading from a StringIO.

I've never used the package, and the examples aren't very comprehensive, but it might be worth checking the difference between the headers variables when you call something like...

from poster.encode import multipart_encode

data = open('example.png', 'rb')
datagen, headers = multipart_encode({"image1": data})

...versus...

from poster.encode import multipart_encode

data = urllib2.urlopen("http://example.com/image.png")
data = StringIO(data.read())
datagen, headers = multipart_encode({"image1": data})

Update #2

Looks like I was right about the Content-Type thing. From the poster source code of encode.py lines 168-174...

        if hasattr(value, 'read'):
            # Looks like a file object
            filename = getattr(value, 'name', None)
            if filename is not None:
                filetype = mimetypes.guess_type(filename)[0]
            else:
                filetype = None

...although there may be other issues if filename is None. Try this...

from poster.encode import multipart_encode, MultipartParam

data = urllib2.urlopen("http://example.com/image.png")
data = StringIO(data.read())
param = MultipartParam(name='source',
                       filename='image.png',
                       filetype='image/png',
                       fileobj=data)
datagen, headers = multipart_encode({"source": param})
于 2013-05-19T16:42:05.547 回答