您的位置:首页 > 编程语言 > Python开发

Python2.5使用新浪微博Python SDK遇到的问题与解决方法

2010-10-26 04:08 1371 查看
上周花了一周时间做了一个GAE(Google App Engine)的与新浪微博交互的网络应用——爱颜色。期间遇到了一些问题,经过一番搜索和思考将它们解决。现在分享给大家,也希望对于不妥的地方得到大家的指正。

首先是OAuth验证问题,这事我折腾了很久才弄明白怎么回事,本想自己写一篇总结了,后来想想还是算了,在网上找到了很多很好用但是比较稀缺的资源,如下:

先来一个官方网站:http://oauth.net/

然后是新浪微博官方网站上的:http://open.t.sina.com.cn/wiki/index.php/Oauth_new

广为流传的:http://blog.csdn.net/hereweare2009/archive/2009/03/08/3968582.aspx

说的比较形象的:http://www.skiyo.cn/2010/08/11/understanding-oauth-and-douban-oauth-test/(虽然这个是说豆瓣的,但是原理是一样的)

然后是我找到的唯一一个和Python有关的,使用Python的SDK的一个OAuth验证的Web应用的详细代码(SDK默认提供的是桌面应用验证的代码,要输入PIN值,网络应用不是很方便)(非常感谢这位作者):/article/4885303.html

有了上面那些,应该就不愁新浪微博的OAuth验证了。

然后开始实战,刚动手就遇到问题了,新浪微博Python 2.x的SDK貌似和Python2.5不兼容,这里是下载地址。(我没用过别的版本的Python,所以希望用过高版本的2.X系列的朋友告诉一生是否可以直接使用。)

我用的SDK是20100906版本的。因为api.py这个文件中的197行(就是下面的最后一行)有问题,运行会直接报错。附近代码如下:

return bind_api(
path = '/statuses/upload.json',
method = 'POST',
payload_type = 'status',
require_auth = True,
allowed_param = allowed_param
)(self, *args, post_data=post_data, headers=headers)

后来,我曾尝试上传到GAE的真实环境上,也会报错。说明新浪微博的PythonSDK在Python2.5下是有问题的。最初的解决方法是——暴力法……我直接将这一行后面的(self, *args, post_data=post_data, headers=headers)给注释掉了。所幸在前期开发一切安好。

但到后来我需要调用upload这个方法进行上传图片微博时,遇到了问题。(我上网找了很久,由于这方面信息太少了,基本搜不到用Python SDK开发新浪微博应用的资料,一般像这种东西外国人写的资料会比较多,但无奈新浪微博是中国的应用,所以外国网站是绝不会搜到的……)

然后我通过了很多方法尝试,最主要的是我将之前把这行代码注掉的事情给忘了……

我只能不断的跟踪源码中的关于生成这个post请求的中,生成的header和MIME的信息的部分,希望从中找到答案。新浪微博API文档中关于upload这个方法的描述中的最后部分,有一个测试方法,可以相关工具观看上传图片时,HTTP传送数据的信息。

我试着对比了几次这个信息和API中生成的header和MIME信息中的差别,跟踪了N次也不得其解。后来才想起来我曾注掉的那行代码,然后将它做了如下修改。(后来根据进一步跟进调试得知,由于注释掉了那段代码,所以我的数据其实没有传进去,也就没有post给新浪微博API的服务器。)

""" statuses/upload """
def upload(self, filename, status, lat=None, long=None, source=None):
if source is None:
source=self.source
headers, post_data = API._pack_image(filename, 1024, source=source, status=status, lat=lat, long=long, contentname="pic")
args = [status]
allowed_param = ['status']

if lat is not None:
args.append(lat)
allowed_param.append('lat')

if long is not None:
args.append(long)
allowed_param.append('long')

if source is not None:
args.append(source)
allowed_param.append('source')

kargs = {
'post_data': post_data,
'headers': headers,
}
return bind_api(
path = '/statuses/upload.json',
method = 'POST',
payload_type = 'status',
require_auth = True,
allowed_param = allowed_param
)(self, *args, **kargs)

然后就可以用了。这样post_data和headers的信息才绑定给了api,将数据post给新浪微博API相关的地址。

爱颜色还有一个需求,就是上传文件时不是打开本地的一个文件然后上传。然而新浪微博Python的SDK里只有打开文件上传的方法,而我需要的是动态生成一个颜色的图像的二进制数据,并将图像的二进制数据直接上传到微博API的服务器。

我本不想在SDK的内部动手脚,但没有找到更好的办法。后来在内部加了一个新的upload方法,这里涉及到图像处理的一个内部函数API._pack_image_data,这个方法负责包装post请求的header和MIME信息,重点是包装了图像的二进制信息,它是根据文件名打开文件,然后读取二进制数据再将其以“Content-Transfer-Encoding: binary”方式post给新浪微博api的服务器。

我在这里将打开文件读取二进制数据,然后修改了API._pack_image_data(修改了部分细节,如判断文件大小,判断文件类型的部分,见代码中高亮的部分。),改为直接将图像二进制数据传给API._pack_image_data方法参数的方式,然后API._pack_image_data方法直接处理传进去的二进制数据。具体方法如下:

@staticmethod
def _pack_image_data(file_type, data, imagename, max_size=1024, source=None, status=None, lat=None, long=None, contentname="pic"):
"""Pack image from file into multipart-formdata post body"""
# image must be less than 700kb in size
try:
if len(data) > (max_size * 1024):
raise WeibopError('File is too big, must be less than 700kb.')
#except os.error, e:
except os.error:
raise WeibopError('Unable to access file')

# image must be gif, jpeg, or png
if file_type is None:
raise WeibopError('Could not determine file type')
if file_type not in ['image/gif', 'image/jpeg', 'image/png']:
raise WeibopError('Invalid file type for image: %s' % file_type)

# build the mulitpart-formdata body
BOUNDARY = 'Tw3ePy'
body = []
if status is not None:
body.append('--' + BOUNDARY)
body.append('Content-Disposition: form-data; name="status"')
body.append('Content-Type: text/plain; charset=US-ASCII')
body.append('Content-Transfer-Encoding: 8bit')
body.append('')
body.append(status)
if source is not None:
body.append('--' + BOUNDARY)
body.append('Content-Disposition: form-data; name="source"')
body.append('Content-Type: text/plain; charset=US-ASCII')
body.append('Content-Transfer-Encoding: 8bit')
body.append('')
body.append(source)
if lat is not None:
body.append('--' + BOUNDARY)
body.append('Content-Disposition: form-data; name="lat"')
body.append('Content-Type: text/plain; charset=US-ASCII')
body.append('Content-Transfer-Encoding: 8bit')
body.append('')
body.append(lat)
if long is not None:
body.append('--' + BOUNDARY)
body.append('Content-Disposition: form-data; name="long"')
body.append('Content-Type: text/plain; charset=US-ASCII')
body.append('Content-Transfer-Encoding: 8bit')
body.append('')
body.append(long)
body.append('--' + BOUNDARY)
body.append('Content-Disposition: form-data; name="'+ contentname +'"; filename="%s"' % imagename)
body.append('Content-Type: %s' % file_type)
body.append('Content-Transfer-Encoding: binary')
body.append('')
body.append(data)
body.append('--' + BOUNDARY + '--')
body.append('')
body.append('--' + BOUNDARY + '--')
body.append('')
body = '\r\n'.join(body)
# build headers
headers = {
'Content-Type': 'multipart/form-data; boundary=Tw3ePy',
'Content-Length': len(body)
}

return headers, body

至于动态生成图像二进制数据,我使用了pngCanvas,一个使用纯Python代码的生成png图像的工具。于是关于使用Python2.5和新浪微博SDK上传图片微博就大体折腾完了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐