转载自:http://www.douban.com/note/201767245/
PC 登录新浪微博时, 在客户端用js预先对用户名、密码都进行了加密, 而且在POST之前会GET 一组参数,这也将作为POST_DATA 的一部分。 这样, 就不能用通常的那种简单方法来模拟POST 登录( 比如 人人网 )。
由于要用的一部分微博数据用API获取不方便, 所以还是要自己写个小爬虫, 模拟登录是必不可少的。琢磨了一下这个东西,最终登录成功。
1, 在提交POST请求之前, 需要GET 获取两个参数。
地址是:http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.3.18)
得到的数据中有 "servertime" 和 "nonce" 的值, 是随机的,其他值貌似没什么用。
2, 通过httpfox 观察POST 的数据, 参数较复杂,其中 “su" 是加密后的username, "sp"是加密后的password。"servertime" 和 ”nonce" 是上一步得到的。其他参数是不变的。
username 经过了BASE64 计算: username = base64.encodestring( urllib.quote(username) )[:-1];
password 经过了三次SHA1 加密, 且其中加入了 servertime 和 nonce 的值来干扰。
即: 两次SHA1加密后, 将结果加上 servertime 和 nonce 的值, 再SHA1 算一次。
将参数组织好, POST请求。 这之后还没有登录成功。
POST后得到的内容中包含一句 location.replace("http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack&retcode=101&reason=%B5%C7%C2%BC%C3%FB%BB%F2%C3%DC%C2%EB%B4%ED%CE%F3");
这是登录失败时的结果, 登录成功后结果与之类似, 不过retcode 的值是0 。接下来再请求这个URL,这样就成功登录到微博了。
记得要提前build 缓存。
下面是完整代码(没加注释,凑合看吧):
#! /usr/bin/env python
#coding=utf8
import urllib
import urllib2
import cookielib
import base64
import re
import json
import time
import hashlib
cj = cookielib.LWPCookieJar()
cookie_support = urllib2.HTTPCookieProcessor(cj)
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
postdata = {
'entry': 'weibo',
'gateway': '1',
'from': '',
'savestate': '7',
'userticket': '1',
'ssosimplelogin': '1',
'vsnf': '1',
'vsnval': '',
'su': '',
'service': 'miniblog',
'servertime': '',
'nonce': '',
'pwencode': 'wsse',
'sp': '',
'encoding': 'UTF-8',
'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
'returntype': 'META'
}
def get_servertime():
url = 'http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=dW5kZWZpbmVk&client=ssologin.js(v1.3.18)&_=1329806375939'
data = urllib2.urlopen(url).read()
p = re.compile('\((.*)\)')
try:
json_data = p.search(data).group(1)
data = json.loads(json_data)
servertime = str(data['servertime'])
nonce = data['nonce']
return servertime, nonce
except:
print 'Get severtime error!'
return None
def get_pwd(pwd, servertime, nonce):
pwd1 = hashlib.sha1(pwd).hexdigest()
pwd2 = hashlib.sha1(pwd1).hexdigest()
pwd3_ = pwd2 + servertime + nonce
pwd3 = hashlib.sha1(pwd3_).hexdigest()
return pwd3
def get_user(username):
username_ = urllib.quote(username)
username = base64.encodestring(username_)[:-1]
return username
def login():
username = '@qq.com'
pwd = ''
url = 'http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.5)'
try:
servertime, nonce = get_servertime()
except:
return
global postdata
postdata['servertime'] = servertime
postdata['nonce'] = nonce
postdata['su'] = get_user(username)
postdata['sp'] = get_pwd(pwd, servertime, nonce)
postdata = urllib.urlencode(postdata)
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux i686; rv:8.0) Gecko/20100101 Firefox/8.0'}
req = urllib2.Request(
url=url,
data=postdata,
headers=headers
)
result = urllib2.urlopen(req)
text = result.read()
p = re.compile('location\.replace\(\"(.*?)\"\)')
try:
login_url = p.findall(text)[0]
print login_url
urllib2.urlopen(login_url)
print "登录成功!"
except Exception, ex:
print 'Login error!' + ex.message
if __name__ == '__main__':
login()
url = "http://weibo.com/u/"
precode = urllib2.urlopen(url)
while True:
time.sleep(10);
nowcode = urllib2.urlopen(url)
if precode == nowcode:
pass
else:
print "happy " + url
precode = nowcode
各种NC,居然想到这种东西。。。我要吐血了。。。不过以后我能发展到各种自动提醒业务哦。嘿嘿。。。
先把新浪登录记下一笔。
话说新浪的登录可真是麻烦哦,幸好直接百度代码了,不然也不知道要研究到什么时候呢!
看到上面的解释就各种头疼了。。。