Python:新浪微博API的使用及安全的模拟登陆自动获取code值

一直用模拟登陆的方法获取微博数据。突然感觉好老土,最重要的是,soga,好慢。所以摸索下API的使用,体验高大上的感觉。

作者@廖雪峰 贡献了SDK!Demo懵懵懂懂,实践出真知!废话不多说!开始!

1. API下载及应用创建

微博API首页地址:点击打开链接。

1、首先要填写个人开发者或者企业开发的信息。时间太久,这不是难点,不详细说明。

2、下面开始创建应用,我选择的是站内应用。这个也很简单。

Python:新浪微博API的使用及安全的模拟登陆自动获取code值_第1张图片

3、下载对应的SDK,我用的是Python。安装,如果报错,请直接复制weibo.py到你的工程目录。另外一个文件还不知道怎么用(14.05.21注,随时更新)。

SDK下载地址:点击打开链接。

4、使用,参考文章:新浪微博API使用之python接口的使用 作者@monsion 

#!/usr/bin/python 
# -*- coding: utf-8 -*-
"""
# 微博API测试
"""
import sys 
reload(sys)
sys.setdefaultencoding("utf8")

from weibo import APIClient

import MySQLdb, webbrowser
import urllib3

if __name__ == "__main__":
    APP_KEY = u'' # app key
    APP_SECRET = u'' # app secret
    CALLBACK_URL = 'http://apps.weibo.com/zhanhisnshows'
    client = APIClient(app_key=APP_KEY, app_secret=APP_SECRET, redirect_uri=CALLBACK_URL)
    url = client.get_authorize_url()
    print url
    webbrowser.open_new(url)
APP_KEY和APP_SECRET创建应用后就会获得,关键是CALLBACK_URL怎么获得?

随便填个CALLBACK_URL报错:

Python:新浪微博API的使用及安全的模拟登陆自动获取code值_第2张图片

原因正是CALLBACK_URL填写错误。

于是百度,果断的,找的信息都没用。都是说去下图的地方填写

Python:新浪微博API的使用及安全的模拟登陆自动获取code值_第3张图片

试了不行。于是我试着填写应用资料。填写站内应用地址后,搞定。如下图所示:

Python:新浪微博API的使用及安全的模拟登陆自动获取code值_第4张图片

最终结果就是第三四个图了。获取code成功。

(2014.05.21注:今天找到了教程,为啥我需要的时候没找到捏!参考:新浪微博API使用初步介绍——解决回调地址的问题 作者@monsion)

Python:新浪微博API的使用及安全的模拟登陆自动获取code值_第5张图片

code的值在地址栏里。接下来开始获取数据。

(2014。05.21注:博主玩着玩着就掉到自动获取code的坑里了,数据获取慢慢道来,以后更新。。。)

2. 自动获取code的值

博主自己慢慢琢磨,中间获取 关键参数ticket时遇到问题,问题如下:

问题1:错误:urllib2.URLError:

解决方法:很多都说是没有安装OpemSSL,我的已经安装了,还是报错。最后找到的原因是:URL错误。。。我去,完全搞不搞,看起来是没错的,但是复制到浏览器就发现https前面多了点什么,就是这个,搞了几个小时。

好了其他没什么问题。需要提醒大家的是:pcid, servertime, nonce, rsakv, sp, su参数的获取,涉及到模拟登陆,如果不会,可以参考我的sina博客文章:python 新浪微博模拟登陆 & 密码加密分析看完不懂可以在Blog留言或者微博@The_Third_Wave 。

博主搞定ticket后,开始最后的攻坚战,成功。

其中有参考python调用新浪微博API实践 @风行影者 

下载了@风行影者 的代码,运行OK,发现问题。@风行影者 代码中明文传输了用户名和密码,于是重写如下,代码贴出,欢迎批评指正:

#!/usr/bin/python 
# -*- coding: utf-8 -*-
"""
[Filename]
WeiboAPI.py

@author: U{The_Third_Wave/huan zhan}
@copyright: U{Copyright (c) 2014.05.22, huan zhan}
@contact: zhanh121823 at sina.com/QQ:563134080
@version: $1.0$
# 微博API接口
"""
import sys 
reload(sys)
sys.setdefaultencoding("utf8")

from weibo import APIClient

import MySQLdb, webbrowser, re, json
import urllib, urllib2, urllib3, cookielib
import hashlib, base64, rsa, binascii # encrypt

class SmartRedirectHandler(urllib2.HTTPRedirectHandler):
    """
    # 参考:风行影者/Blog:http://www.cnblogs.com/wly923/archive/2013/04/28/3048700.html
    """
    def http_error_301(cls, req, fp, code, msg, headers):
        result = urllib2.HTTPRedirectHandler.http_error_301(cls, req, fp, code, msg, headers)
        result.status = code
        return result

    def http_error_302(cls, req, fp, code, msg, headers):
        result = urllib2.HTTPRedirectHandler.http_error_302(cls, req, fp, code, msg, headers)
        result.status = code
        return result
    
def get_cookie():
    cookies = cookielib.CookieJar()
    return urllib2.HTTPCookieProcessor(cookies)
   
def get_opener(proxy=False):
    rv=urllib2.build_opener(get_cookie(), SmartRedirectHandler())
    rv.addheaders = [('User-agent', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)')]
    return rv

class SinaAPI():
    """
    # @author: U{The_Third_Wave/huan zhan}
    # get_code_NS()方法为风行影者所写。/Blog:http://www.cnblogs.com/wly923/archive/2013/04/28/3048700.html
    # get_code_NS()明文传输密码,不安全。所以作者@The_Third_Wave 用模拟登陆的方法获取重要参数'ticket'。保证传输过程中不明文传输密码。保证安全。
    # get_code_Security()方法为作者@The_Third_Wave所写安全自动获取code的方法。
    # 有疑问的请Blog:http://blog.csdn.net/zhanh1218/article/details/26383469留言或者sina微博关注作者@The_Third_Wave。
    """
    def __init__(self, CALLBACK_URL, APP_KEY, REDIRECT_URL, USER_ID, USER_PSWD):
        self.CALLBACK_URL = CALLBACK_URL
        self.APP_KEY = APP_KEY
        self.REDIRECT_URL = REDIRECT_URL
        self.USER_ID = USER_ID
        self.USER_PSWD = USER_PSWD
        self.http = urllib3.PoolManager()
        
    def get_username(self, USER_ID):
        # The Encryption Algorithm of username 
        # ssologin.js : ah.su=sinaSSOEncoder.base64.encode(m(aj));
        USER_ID_ = urllib.quote(USER_ID) # encode username, avoid error example:@ &  
        su = base64.encodestring(USER_ID_)[:-1]
        return su
   
    def get_password_rsa(self, USER_PSWD, PUBKEY, servertime, nonce):
        # 密码加密运算sina我已知有两种,这是其中一种。
        # rsa Encrypt :  #when pwencode = "rsa2"
        rsaPubkey = int(PUBKEY, 16)#pubkey from 16 to 10
        key_1 = int('10001', 16) #10001 to 65537 
        key = rsa.PublicKey(rsaPubkey, key_1) #
        message = str(servertime) + "\t" + str(nonce) + "\n" + str(USER_PSWD)
        passwd = rsa.encrypt(message, key)
        passwd = binascii.b2a_hex(passwd) #to 16
        return passwd
      
    def get_parameter(self):
        su = self.get_username(self.USER_ID)
        #su = get_username(USER_ID)‎‎
        url = "https://login.sina.com.cn/sso/prelogin.php?entry=openapi&callback=sinaSSOController.preloginCallBack\
&su="+su+"&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.15)"
        r = self.http.request('GET', url)
        p = re.compile('\((.*)\)')
        json_data = p.search(r.data).group(1)
        data = json.loads(json_data)
        
        PUBKEY = data['pubkey']
        pcid = data['pcid']
        servertime = str(data['servertime'])
        nonce = data['nonce']
        rsakv = str(data['rsakv'])
        sp = self.get_password_rsa(self.USER_PSWD, PUBKEY, servertime, nonce)
        
        #print pcid; print servertime; print nonce; print rsakv; print sp; print su
        return pcid, servertime, nonce, rsakv, sp, su
         
    def get_ticket(self):
        pcid, servertime, nonce, rsakv, sp, su = self.get_parameter()
        fields = urllib.urlencode({
            'entry'        : 'openapi',
            'gateway'      : '1',
            'from'         : '',
            'savestate'    : '0',
            'useticket'    : '1',
            'pagerefer'    :'',
            'pcid'         : pcid,
            'ct'           : '1800',
            's'            : '1',
            'vsnf'         : '1',
            'vsnval'       : '',
            'door'         : '',
            'appkey'       : 'kxR5R',
            'su'           : su,
            'service'      : 'miniblog',
            'servertime'   : servertime,
            'nonce'        : nonce,
            'pwencode'     : 'rsa2',
            'rsakv'        : rsakv,
            'sp'           : sp,
            'sr'           : '1680*1050',
            'encoding'     : 'UTF-8',
            'cdult'        : '2',
            'domain'       : 'weibo.com',
            'prelt'        : '0',
            'returntype'   : 'TEXT',
        })
        headers = {
                   #"请求": "POST /sso/login.php?client=ssologin.js(v1.4.15)&_=1400652171542 HTTP/1.1",
                   #"Accept": "*/*", 
                   "Content-Type": "application/x-www-form-urlencoded",
                   #"Referer": self.CALLBACK_URL,
                   #"Accept-Language": "zh-CN",
                   #"Origin": "https://api.weibo.com",
                   #"Accept-Encoding": "gzip, deflate",
                   #"User-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; EIE10;ZHCNMSE; rv:11.0) like Gecko",
                   #"Host": "login.sina.com.cn",
                   #"Connection": "Keep-Alive",
                   #"Cache-Control": "no-cache",
                   }
        url = "https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)"
        req = urllib2.Request(url, fields, headers)
        f = urllib2.urlopen(req)
        data = json.loads(f.read())
        return data["ticket"]
    
    def get_code_Security(self): 
        ticket = self.get_ticket()
        fields = urllib.urlencode({
            'action': 'submit', # 必须
            'display': 'default',
            'withOfficalFlag': '0', # 必须
            'quick_auth': 'null',
            'withOfficalAccount': '',
            'scope': '',
            'ticket': ticket, # 必须
            'isLoginSina': '',  
            'response_type': 'code', # 必须
            'regCallback': 'https://api.weibo.com/2/oauth2/authorize?client_id='+self.APP_KEY+'\
&response_type=code&display=default&redirect_uri='+self.REDIRECT_URL+'&from=&with_cookie=',
            'redirect_uri': self.REDIRECT_URL, # 必须
            'client_id': self.APP_KEY, # 必须
            'appkey62': 'kxR5R',
            'state': '', # 必须
            'verifyToken': 'null',
            'from': '', # 必须
            'userId': "", # 此方法不需要填写明文ID
            'passwd': "", # 此方法不需要填写明文密码
            })
        LOGIN_URL = 'https://api.weibo.com/oauth2/authorize' 
        headers = {"User-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; EIE10;ZHCNMSE; rv:11.0) like Gecko",
                   "Referer": self.CALLBACK_URL,
                   "Content-Type": "application/x-www-form-urlencoded",
                   }
        req = urllib2.Request(LOGIN_URL, fields, headers)
        req_ =urllib2.urlopen(req)
        return_redirect_uri = req_.geturl()
        code = re.findall(r"(?<=code%3D).{32}|(?<=code=).{32}", return_redirect_uri) # url中=用%3D表示或者=直接表示 
        print code
        return code 
    
    def get_code_NS(self):
        fields = urllib.urlencode({
            'action': 'submit', # 必须
            'display': 'default',
            'withOfficalFlag': '0', # 必须
            'quick_auth': 'null',
            'withOfficalAccount': '',
            'scope': '',
            'ticket': '', # 必须
            'isLoginSina': '',  
            'response_type': 'code', # 必须
            'regCallback': '',
            'redirect_uri': self.REDIRECT_URL, # 必须
            'client_id': self.APP_KEY, # 必须
            'appkey62': 'kxR5R',
            'state': '', # 必须
            'verifyToken': 'null',
            'from': '', # 必须
            'userId': self.USER_ID, # 必须
            'passwd': self.USER_PSWD, # 必须
            })
        LOGIN_URL = 'https://api.weibo.com/oauth2/authorize' 
        headers = {"User-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; EIE10;ZHCNMSE; rv:11.0) like Gecko",
                   "Referer": self.CALLBACK_URL,
                   "Content-Type": "application/x-www-form-urlencoded",
                   }
        r = urllib2.Request(LOGIN_URL, fields, headers)
        opener = get_opener(False) 
        urllib2.install_opener(opener)
        try:  
            f = opener.open(r)  
            return_redirect_uri = f.url   
            print "NS1", return_redirect_uri             
        except urllib2.HTTPError, e:  
            return_redirect_uri = e.geturl()  
            print "NS2", return_redirect_uri  
        # 取到返回的code  
        #code = return_redirect_uri.split('=')[1]
        # 以下我用正则改写,这样不会因为url变化而不能提取code的值
        code = re.findall(r"(?<=code%3D).{32}|(?<=code=).{32}", return_redirect_uri) # url中=用%3D表示或者=直接表示 
        print code
        return code 
 
if __name__ == "__main__":
    APP_KEY = u'' # app key
    APP_SECRET = u'' # app secret
    REDIRECT_URL = 'http://apps.weibo.com/zhanhisnshows'
    client = APIClient(app_key=APP_KEY, app_secret=APP_SECRET, redirect_uri=REDIRECT_URL)
    CALLBACK_URL = client.get_authorize_url()
    print CALLBACK_URL   
    API = SinaAPI(CALLBACK_URL, APP_KEY, REDIRECT_URL, username, password)
    code = API.get_code_Security()
    #code = API.get_code_NS() http://
    """
    #webbrowser.open_new(url) #获取code=后面的内容  
    code = raw_input('输入url中code后面的内容后按回车键:')  
    print code, "code"
    """
    requests = client.request_access_token(code)  
    access_token = requests.access_token # 新浪返回的token,类似abc123xyz456  
    expires_in = requests.expires_in  
    # 设置得到的access_token  
    client.set_access_token(access_token, expires_in)  
    print client.statuses__public_timeline()  
    statuses = client.statuses__public_timeline()['statuses']  
    length = len(statuses)  
    #输出了部分信息  
    for i in range(0,length):  
        print u'昵称:'+statuses[i]['user']['screen_name']  
        print u'简介:'+statuses[i]['user']['description']  
        print u'位置:'+statuses[i]['user']['location']  
        print u'微博:'+statuses[i]['text']  

3. 数据获取详解

具体请看API: http://open.weibo.com/wiki/%E5%BE%AE%E5%8D%9AAPI 。
廖雪峰先生关于API的说明: 点击打开链接 一定要看!
看完上面两篇就知道怎么自定义命令了!很好的教程!廖老师真是做了很多事情的!感谢!
最后编辑于:2014.05.24 9:54

文件免费下载地址:weibo.py &WeiboAPI.py

本文由@The_Third_Wave原创。不定期更新,有错误请指正。

Sina微博关注:@The_Third_Wave 

如果这篇博文对您有帮助,为了好的网络环境,不建议转载,建议收藏!如果您一定要转载,请带上后缀和本文地址。

你可能感兴趣的:(Python,微博API)