新浪微博提醒脚本

2012-02-07

无意中在微博上看到@乌云-漏洞报告平台 提起了一个关于“消息提醒未授权访问”的BUG。大致的看了一下网站上的截图,配合新浪微博的API 文档的介绍,估摸着弄了一下这个漏洞的实现脚本。其实,从实用的角度来看,这个BUG,基本上算不上严重(乌云的自评级才到3),也没有啥利用价值。又或者,像某位网友说的那样“由于这个接口流量过大而省去了认证环节”,而故意为之。

那,我为什么想着用脚本实现去利用这个漏洞呢?缘起放假前的一个idea。那段时间(包括现在)每天都在刷微博,浏览各种新闻网站,对网络产生了一种病态的依赖。想着,如果有一套提醒系统,在我关心的信息出现时,就自动推送给我,那该多好啊。而微博提醒自然可以通过其提供的API 来轻易实现。只不过当时玩API的时候没有注意别人的消息而已。

最近在看python 有关的书。目前,第二本已经看了一大半。寻思着练手的时候,正好可以借这个机会发挥一下。所以,这篇博客算是一个菜鸟看书笔记吧。如我微博所言,随便扫描了一圈,发现名人、艺人的微博信息普遍过载,而草根和技术流的微博都比较清静。下面是截图:这里是另外一张

python 脚本:

#coding: gbk
import urllib,sys

#appkey = 从sina API申请

class SINA(object):
    '''简单的调用新浪微博OPEN API
    DEMO:
    s = SINA()
    flag = s.init_api_object(appkey, u'陈坤')
    if flag:
        uid = s.get_uid()
    '''
    api_base_path = 'http://api.t.sina.com.cn/users/show.json?source='    

    def __init__(self):
        self.sina = {}

    @staticmethod
    def build_api_url(appkey, user_screen_name):
        '''生成新浪API URL
        '''
        if appkey and user_screen_name:
            try:
                return SINA.api_base_path + str(appkey) + '&screen_name=' \
                    + urllib.quote(user_screen_name.decode(sys.stdin.encoding).encode('utf8'))
            except :
                return False
        else:
            return None

    def init_api_object(self, appkey, user_screen_name):
        ''' 初始化API对象
        appkey:从 [http://open.weibo.com/]申请
        user_screen_name:就是微博界面上显示的名称
        '''
        try:
            api = SINA.build_api_url(appkey, user_screen_name)
            if api:
                dic = urllib.urlopen(api).read()
                dic = eval(str(dic).replace('false', 'False').replace('true', 'True').replace('null', 'None'))
                if dic.has_key('error'):
                    return False
                else:
                    self.sina = dic
            else:
                return False
        except:
            return False
        else:
            return True

    def get_uid(self):
        '''获取UID
        '''
        if self.sina:
            return self.sina['id']
        else:
            return None

    def get_description(self):
        '''获取自我介绍
        '''
        if self.sina:
            return self.sina['description']
        else:
            return None

    def get_gender(self):
        '''获取用户性别
        '''
        gender = {'m': 'male', 'f':'femail'}
        if self.sina:
            return gender[self.sina['gender']]
        else:
            return None

    def get_followers_count(self):
        '''获取粉丝数量
        '''
        if self.sina:
            return self.sina['followers_count']
        else:
            return None

    def get_friends_count(self):
        '''获取关注数量
        '''
        if self.sina:
            return self.sina['friends_count']
        else:
            return None

    def get_statuses_count(self):
        '''获取微博数量
        '''
        if self.sina:
            return self.sina['statuses_count']
        else:
            return None

    def get_favourites_count(self):
        '''获取微博收藏数量
        '''
        if self.sina:
            return self.sina['favourites_count']
        else:
            return None

    def get_image_url(self):
        '''获取微博头像
        '''
        if self.sina:
            return self.sina['profile_image_url']
        else:
            return None

    def get_domain(self):
        '''获取微博地址
        '''
        if self.sina:
            return self.sina['domain']
        else:
            return None

    def get_location(self):
        '''获取所在位置
        '''
        if self.sina:
            return self.sina['location']
        else:
            return None

class SINA_NOTIFICATION(object):
    '''SINA 微博消息API
    DEMO:
    s = SINA()
    flag = s.init_api_object(APPKEY, u'陈坤')
    if flag:
        uid = s.get_uid()
        sn = SINA_NOTIFICATION()
        nf_flag = sn.init_notification(APPKEY, uid)
        if nf_flag:
            ns = sn.notifications()
            for item in ns:
                print "%s: %d"%(SINA_NOTIFICATION.dic[item],sn.get(item))
    '''
    api_base_path = 'http://api.t.sina.com.cn/remind/unread_count.json?source='

    dic = {'attention':u'有新的粉丝',
           'comment':u'有新的评论',
           'msg':u'有新的私信',
           'atme':u'有新提及我的微博',
           'atcmt':u'有新提及我的评论',
           'group':u'有新的微群消息',
           'notice':u'有新通知',
           'invite':u'有新的邀请',
           'badge':u'有新的徽章',
           'photo':u'有新的相册消息'}

    def __init__(self):
        self.nf = {}

    @staticmethod
    def build_api_url(appkey, uid):
        '''生成API URL
        '''
        if appkey and uid:
            try:
                return SINA_NOTIFICATION.api_base_path + str(appkey) + '&user_id=' + str(uid)
            except:
                return False
        else:
            return False

    def init_notification(self, appkey, uid):
        '''初始化提醒对象
        '''
        try:
            api = SINA_NOTIFICATION.build_api_url(appkey, uid)
            if api:
                dic = urllib.urlopen(api).read()
                import os
                self.nf = eval(dic.replace('\r\n', os.linesep))#Linux support
            else:
                return False
        except:
            return False
        else:
            return True

    def notifications(self):
        '''呈现消息
        '''
        n_list = []
        if self.nf:
            for item in self.nf:
                if item == 'feed':
                    continue
                if self.nf[item] > 0:
                    n_list.append(item)
            return n_list
        else:
            return None

    def has_notification(self):
        '''是否有新的微博消息
        '''
        if self.nf:
            cnt = 0
            for item in self.nf:
                if item == 'feed':
                    continue
                cnt += self.nf[item]
            if cnt > 0:
                return True
            else:
                return False

    def get_atme(self):
        '''新提及我的微博数
        '''
        if self.nf:
            return self.nf['atme']
        else:
            return None

    def get_private_message(self):
        '''新私信数
        '''
        if self.nf:
            return self.nf['msg']
        else:
            return None

    def get_comment(self):
        '''新评论数
        '''
        if self.nf:
            return self.nf['comment']
        else:
            return None

    def get_atcmt(self):
        '''@新提及我的评论数
        '''
        if self.nf:
            return self.nf['atcmt']
        else:
            return None

    def get_group(self):
        '''微群消息未读数
        '''
        if self.nf:
            return self.nf['group']
        else:
            return None

    def get_photo(self):
        '''相册消息未读数
        '''
        if self.nf:
            return self.nf['photo']
        else:
            return None

    def get_invite(self):
        '''新邀请未读数
        '''
        if self.nf:
            return self.nf['invite']
        else:
            return None

    def get_badge(self):
        '''新勋章数
        '''
        if self.nf:
            return self.nf['badge']
        else:
            return None

    def get_notice(self):
        '''新通知未读数
        '''
        if self.nf:
            return self.nf['notice']
        else:
            return None

    def get_attention(self):
        '''新粉丝数
        '''
        if self.nf:
            return self.nf['attention']
        else:
            return None

    def get(self, lable):
        '''
        '''
        if lable not in ("attention","comment","msg","atme","atcmt","group","notice","invite","badge","photo"):
            return None
        if self.nf:
            return self.nf[lable]
        else:
            return None

if __name__ == '__main__':
    name = raw_input('请输入需要查询的昵称:')
    s = SINA()
    flag = s.init_api_object(appkey, name)
    if flag:
        uid = s.get_uid()
        sn = SINA_NOTIFICATION()
        nf_flag = sn.init_notification(appkey, uid)
        if nf_flag:
            if sn.has_notification():
                ns = sn.notifications()
                for item in ns:
                    print "%s: %d"%(SINA_NOTIFICATION.dic[item],sn.get(item))
            else:
                print '暂时还没有新的微博提醒'
        else:
            print 'something is error'.title()
    else:
        print ('没有找到与%s匹配的信息!'%name).title()

就在写博客的时候,我忽然想到可以把这个接口的数据进行稍微的梳理。比如找出名人堂里影响力排行榜前50的大V们,谁获得的@最多,谁私信最多,谁新增的粉丝最多,谁收到的评论最多…等等。于是停下了博客的更新,顺手写下了后面的这个脚本。虽然,拿到的数据也没有什么商业价值,但起码,对于一个刚刚熟悉脚本的人来说,算是玩尽兴了。ok, 上代码:

#coding: gbk
from sina import SINA, SINA_NOTIFICATION

#appkey = 才sina API申请
person_list = ['文章同學', '蔡康永', '陈坤', '吴奇隆', '何炅', '杨幂',
               '任志强', '羅志祥','刘忻', '潘石屹', '陆琪', '宋丹丹',
               '方舟子','魏晨','张杰','韩庚', '姚晨', '李开复', '韩志国',
               '薛蛮子', '王力宏','马伊琍','汪东城', '周笔畅', '周立波',
               '舒淇', '陈翔橙', '慕容雪村', '阿信', '宁财神', '范范范瑋琪',
               '乐嘉', '企业家智库', '夢想家林志穎', '郭敬明', '炎亞綸','edc陳冠希',
               '张小娴', '张泉灵', '小霜', '小P老师', '谢娜', '高考直通车', '罗玉凤',
               '黑人建州', '牛尔', '鍾欣桐', '杜海涛Hito', '加措活佛-慈爱基金', '总裁语录'
               ]

def name_to_id(name, appkey):
    s = SINA()
    flag = s.init_api_object(appkey, name)
    if flag:
        return s.get_uid()

import cPickle
def save_id():
    person_id = {}
    try:
        for item in person_list:
            person_id[item] = name_to_id(item, appkey)
        if len(person_id) == 50:
            pfile = open('person_id.dat','wb')
            cPickle.dump(person_id, pfile, protocol=0)
            pfile.close()
        else:
            return False
    except:
        return False
    else:
        return True

def save_dic():
    person_dic = {}
    try:
        pfile = open('person_id.dat','rb')
        ids = cPickle.load(pfile)
        pfile.close()
        for item in person_list:
            uid = ids[item]
            sn = SINA_NOTIFICATION()
            nf_flag = sn.init_notification(appkey, uid)
            if nf_flag:
                person_dic[item] = sn.nf
        if len(person_dic) == 50:
            dic_file = open('person_dic.dat', 'wb')
            cPickle.dump(person_dic, dic_file, protocol=0)
        else:
            return False
    except:
        return False
    else:
        return True

def get_top_atme():
    dic_file = open('person_dic.dat', 'rb')
    dic = cPickle.load(dic_file)
    dic_file.close()
    atme_dic = {}
    for item in person_list:
        atme_dic[item] = dic[item]['atme']

    s_list = sorted(atme_dic.items(), lambda x, y: cmp(x[1],y[1]), reverse = True)
    return s_list[0][0], s_list[1][0], s_list[2][0]

def get_top_cmt():
    dic_file = open('person_dic.dat', 'rb')
    dic = cPickle.load(dic_file)
    dic_file.close()
    cmt_dic = {}
    for item in person_list:
        cmt_dic[item] = dic[item]['comment']

    s_list = sorted(cmt_dic.items(), lambda x, y: cmp(x[1],y[1]), reverse = True)
    return s_list[0][0], s_list[1][0], s_list[2][0]            

def get_top_msg():
    dic_file = open('person_dic.dat', 'rb')
    dic = cPickle.load(dic_file)
    dic_file.close()
    cmt_dic = {}
    for item in person_list:
        cmt_dic[item] = dic[item]['msg']

    s_list = sorted(cmt_dic.items(), lambda x, y: cmp(x[1],y[1]), reverse = True)
    return s_list[0][0], s_list[1][0], s_list[2][0] 

def get_top_new_followers():
    dic_file = open('person_dic.dat', 'rb')
    dic = cPickle.load(dic_file)
    dic_file.close()
    cmt_dic = {}
    for item in person_list:
        cmt_dic[item] = dic[item]['attention']

    s_list = sorted(cmt_dic.items(), lambda x, y: cmp(x[1],y[1]), reverse = True)
    return s_list[0][0], s_list[1][0], s_list[2][0]
import time

if __name__ == '__main__':
    print '现在时刻:',time.ctime()
    if save_id():
        if save_dic():
            func_list = [get_top_atme, get_top_cmt, get_top_msg, get_top_new_followers]
            func_name = {get_top_atme: '@', get_top_cmt: '评论',
                 get_top_msg: '私信', get_top_new_followers: '新粉丝'
                 }
            for item in func_list:
                print '此刻, 获得最多%s的人是:'%func_name[item]
                for it in item():
                    print '\t',it,'\t'
                print '*'*40
    print '处理完成:',time.ctime()

脚本的输出结果:

现在时刻: Wed Feb 08 00:15:36 2012
此刻, 获得最多@的人是:
方舟子
张小娴
edc陳冠希
****************************************
此刻, 获得最多评论的人是:
谢娜
刘忻
张杰
****************************************
此刻, 获得最多私信的人是:
薛蛮子
慕容雪村
阿信
****************************************
此刻, 获得最多新粉丝的人是:
方舟子
张杰
陈坤
****************************************
处理完成: Wed Feb 08 00:17:25 2012

参考资料:

新浪微博API 文档V2

乌云-漏洞报告平台:新浪微博消息提醒未授权漏洞概要

分类:我的程序网络应用 | 标签: |

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>