本节将改进上一节中发微博的程序,主要的改进功能是:能够保存授权的access_token,不用进行重复授权。先看一下本节工程的目录结构(如图1所示)。
图1
send_weibo.py为发微博的主程序,与上一节中的程序没有什么差别。目录initclient是我自己定义的一个包,目录中的initclient.py封装了授权过程,后面详细解释,token-record.log是一个数据文件,用来存储授权的access_token,__init__.py是自定义包所必须的,文件为空(关于__init__.py不明白的朋友可以查看Python相关文档)。
首先看一下initclient.py的内容:
#! /usr/bin/python import weibo import urllib import time import os class myAPIClient(weibo.APIClient): """ myAPIClient类继承自weibo包中的APIClient类,对其进行了扩展。SDK中的APIClient类没有根据已授权的access_token获取授权详细信息的接口。另外,SDK中 的APIClient不能保存当前授权用户的uid,该继承类实现了这两个功能,使得用起来更加方便。 """ def __init__(self, app_key, app_secret, redirect_uri=None, response_type='code', domain='api.weibo.com', version='2'): weibo.APIClient.__init__(self, app_key, app_secret, redirect_uri=None, response_type='code', domain='api.weibo.com', version='2') #保存当前授权用户的uid self.uid = "" def request_access_token_info(self, at): """ 该接口传入参数at为已经授权的access_token,函数将返回该access_token的详细信息,返回Json对象,与APIClient类的request_access_token类似。 """ r = weibo._http_post('%s%s' % (self.auth_url, 'get_token_info'), access_token = at) current = int(time.time()) expires = r.expire_in + current remind_in = r.get('remind_in', None) if remind_in: rtime = int(remind_in) + current if rtime < expires: expires = rtime return weibo.JsonDict(expires=expires, expires_in=expires, uid=r.get('uid', None)) def set_uid(self, uid): self.uid = uid TOKEN_FILE = 'token-record.log' def load_tokens(filename=TOKEN_FILE): acc_tk_list = [] try: filepath = os.path.join(os.path.dirname(__file__), filename) f = open(filepath) acc_tk_list.append(f.readline().strip()) print "===> Get the access_token from file token-record.log : ", acc_tk_list[0] except IOError: print "===> File token-record.log does not exist." f.close() return acc_tk_list def dump_tokens(tk, filename=TOKEN_FILE): try: filepath = os.path.join(os.path.dirname(__file__), filename) f = open(filename, 'a') f.write(tk) f.write('\n') except IOError: print "===> File token-record.log does not exist." f.close() print "===> The new access_token has been written to file token-record.log." def get_client(appkey, appsecret, callback): client = myAPIClient(appkey, appsecret, callback) at_list = load_tokens() if at_list: access_token = at_list[-1] r = client.request_access_token_info(access_token) expires_in = r.expires_in print "===> The access_token's expires_in : %f" % expires_in #授权access_token过期 if r.expires_in <= 0: return None client.set_uid(r.uid) else: auth_url = client.get_authorize_url() print "===> auth_url : " + auth_url print """===> Note! The access_token is not available, you should be authorized again. Please open the url above in your browser, then you will get a returned url with the code field. Input the code in the follow step.""" code = raw_input("===> input the retured code : ") r = client.request_access_token(code) access_token = r.access_token expires_in = r.expires_in print "===> the new access_token is : ", access_token dump_tokens(access_token) client.set_access_token(access_token, expires_in) client.set_uid(r.uid) return client
【说明】:
(1)myAPIClient类继承自weibo包中的APIClient类,增加了两个功能:第一,保存当前授权用户的uid,该值在后面需要用到,所以保存到类成员变量中;第二,根据授权的access_token获取授权信息,这里实际是调用新浪微博提供的API,具体参考官方文档(http://open.weibo.com/wiki/Oauth2/get_token_info);
(2)load_tokens和dump_tokens两个函数分别用于从文件token-record.log读取授权的access_token和将access_token写入文件;
(3)get_client是获取授权的myAPIClient对象的接口,也是该模块最关键的函数,也很简单,就是读取文件token-record.log,如果读到access_token就调用myAPIClient类的函数request_access_token_info获取该access_token的详细信息(主要是expires_in),如果文件中没有读到则需要重新授权(跟上一节中的内容一样),最后返回授权的client对象。图2中显示了该过程。
图2
下面看一下send_weibo.py的内容:
#! /usr/bin/python from initclient import initclient APP_KEY = '2024******' APP_SECRET = '91a57******' CALL_BACK = 'http://bingbingrobot.sinaapp.com/' def run(): #调用initclietn模块创建授权的client对象 client = initclient.get_client(APP_KEY, APP_SECRET, CALL_BACK) if not client: return #根据用户输入内容发微博 while True: print "Ready! Do you want to send a new weibo?(y/n)" choice = raw_input() if choice == 'y' or choice == 'Y': content = raw_input('input the your new weibo content : ') if content: client.statuses.update.post(status=content) print "Send succesfully!" break; else: print "Error! Empty content!" if choice == 'n' or choice == 'N': break if __name__ == "__main__": run()【说明】:
(1)注意第3行的import语句,表示从包(目录)initclient中引入initclient模块,要求initclient目录中必须含有__init__.py文件(不了解的朋友请查看相关文档);
(2)有了initclient包后,主程序send_weibo.py变得非常简单,获取授权client只需要一行代码即可,而且程序功能也变得非常合理了,只要上一次授权的access_token没有过期,这一次就不需要重复授权了。而且该initclient包是可以重复利用的,后面需要开发其他功能直接使用该包即可;
(3)运行结果如图3所示。
图3
【补充】:
大家有没有注意到load_tokens函数中读取access_token是用的一个list存储的,而且dump_tokens中写入access_token是用的追加模式,这样写实为了程序的扩展,将来如果想把自己的应用发布,有很多用户使用时,每个授权用户都会有一个access_token,这样就可以把所有用户的access_token存在文件中,根据登陆用户的access_token去文件中查找是否已经授权。本程序中都是用我自己的账户登陆的,所以是有一个access_token,所以initclient.py的第63行读取的是at_list[-1],即读取文件中的最后一个access_token。
代码打包下载:http://download.csdn.net/detail/lewsn2008/5583803
By: