本节将改进上一节中发微博的程序,主要的改进功能是:能够保存授权的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: