一直用類比登陸的方法擷取微博資料。突然感覺好老土,最重要的是,soga,好慢。所以摸索下API的使用,體驗高大上的感覺。
作者@廖雪峰 貢獻了SDK。Demo懵懵懂懂,實踐出真知。廢話不多說。開始。 1. API下載及應用建立
微博API首頁地址:點擊開啟連結。
1、首先要填寫個人開發人員或者企業開發的資訊。時間太久,這不是痛點,不詳細說明。
2、下面開始建立應用,我選擇的是站內應用。這個也很簡單。
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 APIClientimport MySQLdb, webbrowserimport urllib3if __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報錯:
原因正是CALLBACK_URL填寫錯誤。
於是百度,果斷的,找的資訊都沒用。都是說去下圖的地方填寫
試了不行。於是我試著填寫應用資料。填寫站內應用地址後,搞定。如下圖所示:
最終結果就是第三四個圖了。擷取code成功。
(2014.05.21註:今天找到了教程,為啥我需要的時候沒找到捏。參考:新浪微博API使用初步介紹——解決回調地址的問題 作者@monsion)
code的值在地址欄裡。接下來開始擷取資料。
(2014。05.21註:博主玩著玩著就掉到自動擷取code的坑裡了,資料擷取慢慢道來,以後更新。。。) 2. 自動擷取code的值 博主自己慢慢琢磨,中間擷取 關鍵參數ticket時遇到問題,問題如下: 問題1:錯誤:urllib2.URLError: <urlopen error unknown url type: https>
解決方案:很多都說是沒有安裝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<mailto: zhanh121823 at sina.com>}@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 APIClientimport MySQLdb, webbrowser, re, jsonimport urllib, urllib2, urllib3, cookielibimport hashlib, base64, rsa, binascii # encryptclass 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 rvclass SinaAPI(): """ # @author: U{The_Third_Wave/huan zhan<mailto: zhanh121823 at sina.com>} # 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
如果這篇博文對您有協助,為了好的網路環境,不建議轉載,建議收藏。如果您一定要轉載,請帶上尾碼和本文地址。