Created
October 20, 2016 18:01
-
-
Save comzyh/815cdd9d21dff239adcd540297742fc1 to your computer and use it in GitHub Desktop.
weibo_login.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
# Thanks @xianhu | |
# referer: https://github.com/xianhu/LearnPython/blob/master/python_weibo.py | |
import requests | |
import urllib | |
import base64 | |
import time | |
import json | |
import logging | |
import binascii | |
import re | |
import rsa | |
class WeiBoLogin(object): | |
def __init__(self): | |
self.logger = logging.getLogger('WeiBoLogin') | |
self.s = requests.session() | |
self.s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) '\ | |
'AppleWebKit/537.36 \(KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36' | |
@classmethod | |
def get_username_quoted(cls, username): | |
""" | |
get username, encrypt file: http://tjs.sjs.sinajs.cn/t5/register/js/page/remote/loginLayer.js | |
""" | |
username_quote = urllib.parse.quote_plus(username) | |
username_base64 = base64.b64encode(username_quote.encode("utf-8")) | |
return username_base64.decode("utf-8") | |
@classmethod | |
def get_password(cls, password, servertime, nonce, pubkey): | |
""" | |
get legal password, encrypt file: http://tjs.sjs.sinajs.cn/t5/register/js/page/remote/loginLayer.js | |
""" | |
string = (str(servertime) + '\t' + str(nonce) + '\n' + str(password)).encode("utf-8") | |
public_key = rsa.PublicKey(int(pubkey, 16), int("10001", 16)) | |
password = rsa.encrypt(string, public_key) | |
password = binascii.b2a_hex(password) | |
return password.decode() | |
def get_prelogin_data(self, su_value): | |
""" | |
get the value of "servertime", "nonce", "pubkey", "rsakv" and "showpin", etc | |
""" | |
try: | |
resp = self.s.get('http://login.sina.com.cn/sso/prelogin.php?', params= { | |
"entry": "weibo", | |
"callback": "sinaSSOController.preloginCallBack", | |
"rsakt": "mod", | |
"checkpin": "1", | |
"client": "ssologin.js(v1.4.18)", | |
"su": su_value, | |
"_": int(time.time()*1000), | |
}) | |
prelogin_data = json.loads(re.search("\((?P<data>.*)\)", resp.text).group("data")) | |
except Exception as excep: | |
prelogin_data = {} | |
logging.error("WeiBoLogin get_prelogin_data error: %s", excep) | |
logging.debug("WeiBoLogin get_prelogin_data: %s", prelogin_data) | |
return prelogin_data | |
def login(self, username, password): | |
# (1) 打开weibo.com/login.php,先请求一些必要的cookie信息 | |
self.s.get("http://weibo.com/login.php", headers={ | |
'referer': "http://weibo.com/" | |
}) | |
# (2) 根据用户名获取加密后的用户名 | |
s_username = self.get_username_quoted(username) | |
# (3) 利用加密后的用户名,获取其他一些数据:json格式 | |
prelogin_data = self.get_prelogin_data(s_username) | |
if not prelogin_data: | |
return False | |
# (4) 根据第三步得到的json数据,获取加密后的密码 | |
s_password = self.get_password(password, prelogin_data["servertime"], prelogin_data["nonce"], prelogin_data["pubkey"]) | |
# (5) 构造登录中用到的postdata | |
post_dict = { | |
"entry": "weibo", | |
"gateway": "1", | |
"from": "", | |
"savestate": "7", | |
"userticket": "1", | |
"vsnf": "1", | |
"service": "miniblog", | |
"encoding": "UTF-8", | |
"pwencode": "rsa2", | |
"sr": "1280*800", | |
"prelt": "529", | |
"url": "http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack", | |
"rsakv": prelogin_data["rsakv"], | |
"servertime": prelogin_data["servertime"], | |
"nonce": prelogin_data["nonce"], | |
"su": s_username, | |
"sp": s_password, | |
"returntype": "TEXT", | |
} | |
# (6) 判断是否需要输入验证码,如果需要,获取验证码并进行打码操作 | |
if prelogin_data.get("showpin", None) == 1: | |
url = "http://login.sina.com.cn/cgi/pin.php?r=%d&s=0&p=%s" % (int(time.time()), prelogin_data["pcid"]) | |
with open("captcha.jpeg", "wb") as file_out: | |
file_out.write(self.s.get(url).content) | |
code = input("请输入验证码:") | |
# cid, code = self.yundama.get_captcha(self.opener.open(url).read(), "captcha.jpeg", "image/jpeg", codetype="1005") | |
# if not code: | |
# return False | |
post_dict["pcid"] = prelogin_data["pcid"] | |
post_dict["door"] = code | |
# (7) 根据构造的postdata,登录微博 | |
try: | |
json_data_1 = self.s.post( | |
url="http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)&_=%d" % int(time.time()), | |
data=post_dict, | |
headers={'referer': 'http://weibo.com/login.php'} | |
).json() | |
except Exception as e: | |
raise | |
else: | |
assert(json_data_1['retcode'] == '0') | |
try: | |
resp = self.s.get("https://passport.weibo.com/wbsso/login", params={ | |
"callback": "sinaSSOController.callbackLoginStatus", | |
"ticket": json_data_1["ticket"], | |
"ssosavestate": int(time.time()), | |
"client": "ssologin.js(v1.4.18)", | |
"_": int(time.time()*1000), | |
}) | |
json_data_2 = json.loads(re.search("\((?P<result>.*)\)", resp.text).group("result")) | |
except Exception as e: | |
raise | |
if json_data_2["result"] is True: | |
self.user_uniqueid = json_data_2["userinfo"]["uniqueid"] | |
self.user_nick = json_data_2["userinfo"]["displayname"] | |
logging.warning("WeiBoLogin succeed: %s", json_data_2) | |
else: | |
logging.warning("WeiBoLogin failed: %s", json_data_2) | |
def main(): | |
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s\t%(levelname)s\t%(message)s") | |
weibo = WeiBoLogin() | |
weibo.login("foo", "bar") | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment