本文转自:http://www.jb51.net/article/44779.htm
1、主函数(WeiboLogin.py)
import urllib2 import cookielib import WeiboEncode import WeiboSearch if __name__ == '__main__': weibologin = WeiboLogin('xxxxxxx', 'xxxxxx')#用户名、密码 if weibologin.Login() == True: print "登陆成功!"
前两个import是加载Python的网络编程模块,后面的import是加载另两个文件WeiboEncode.py和Weiboseach.py(稍后介绍)。主函数新建登陆对象,然后登陆。
2、WeiboLogin类(WeiboLogin.py):
class WeiboLogin: def __init__(self, user, pwd, enableProxy = False): "初始化WeiboLogin,enableProxy表示是否使用代理服务器,默认关闭" print "Initializing WeiboLogin..." self.userName = user self.passWord = pwd self.enableProxy = enableProxy self.serverUrl = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&client=ssologin.js(v1.4.18)&_=1407721000736" self.loginUrl = "http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)" self.postHeader = {'User-Agent': 'Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20140611 Firefox/24.0 Iceweasel/24.6.0'}
初 始化用户名,密码,serverUrl用于第一步获取servertime,nonce等。loginUrl用于第二步,加密后的用户名和密码POST给 这个URL。关于这些步骤是怎么知道的?其实这些数据的传输都可以监视到。像我用的firefox中有一个Httpfox插件就有这个功能。
3、类内的函数还有:
def Login(self): "登陆程序" self.EnableCookie(self.enableProxy)#cookie或代理服务器配置 serverTime, nonce, pubkey, rsakv = self.GetServerTime()#登陆的第一步 postData = WeiboEncode.PostEncode(self.userName, self.passWord, serverTime, nonce, pubkey, rsakv)#加密用户和密码 #print "Post data length:\n", len(postData) req = urllib2.Request(self.loginUrl, postData, self.postHeader) #print "Posting request..." result = urllib2.urlopen(req)#登陆的第二步 text = result.read() try: loginUrl = WeiboSearch.sRedirectData(text)#解析重定位结果 urllib2.urlopen(loginUrl) except: print 'Login error!' return False #print 'Login sucess!' return True
self.EnableCookie用于设置cookie及代理服务器,网络上有很多免费的代理服务器,为防止新浪封IP,可以使用。关于代理IP的方法,我试过会出现登录次数过多的错误。然后是登陆的第一 步,访问新浪服务器得到serverTime等信息,然后利用这些信息加密用户名和密码,构建POST请求;执行第二步,向self.loginUrl发 送用户和密码,得到重定位信息后,解析得到最终跳转到的URL,打开该URL后,服务器自动将用户登陆信息写入cookie,登陆成功。
def EnableCookie(self, enableProxy): "Enable cookie & proxy (if needed)." cookiejar = cookielib.LWPCookieJar()#建立cookie cookie_support = urllib2.HTTPCookieProcessor(cookiejar) if enableProxy: proxy_support = urllib2.ProxyHandler({'http':'http://122.96.59.107:843'})#使用代理 opener = urllib2.build_opener(proxy_support, cookie_support, urllib2.HTTPHandler) print "Proxy enabled" else: opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler) urllib2.install_opener(opener)#构建cookie对应的opener
def GetServerTime(self): "Get server time and nonce, which are used to encode the password" #print "Getting server time and nonce..." serverData = urllib2.urlopen(self.serverUrl).read()#得到网页内容 #print serverData try: serverTime, nonce, pubkey, rsakv = WeiboSearch.sServerData(serverData)#解析得到serverTime,nonce等 return serverTime, nonce, pubkey, rsakv except: print 'Get server time & nonce error!' return None
4、sSearch函数(WeiboSearch.py):
def sServerData(serverData): "Search the server time & nonce from server data" p = re.compile('\((.*)\)') jsonData = p.search(serverData).group(1) data = json.loads(jsonData) serverTime = str(data['servertime']) nonce = data['nonce'] pubkey = data['pubkey'] rsakv = data['rsakv'] # print "Server time is:", serverTime # print "Nonce is:", nonce return serverTime, nonce, pubkey, rsakv
解析过程主要使用了正则表达式和JSON。另外Login中解析重定位结果部分函数也在这个文件中如下:
def sRedirectData(text): p = re.compile('location\.replace\([\'"](.*?)[\'"]\)') loginUrl = p.search(text).group(1) print 'loginUrl:',loginUrl return loginUrl
5、WeiboEncode.py:
import urllib import base64 import rsa import binascii def PostEncode(userName, passWord, serverTime, nonce, pubkey, rsakv): "Used to generate POST data" encodedUserName = GetUserName(userName)#用户名使用base64加密 encodedPassWord = get_pwd(passWord, serverTime, nonce, pubkey)#目前密码采用rsa加密 postPara = { 'entry': 'weibo', 'gateway': '1', 'from': '', 'savestate': '7', 'userticket': '1', 'ssosimplelogin': '1', 'vsnf': '1', 'vsnval': '', 'su': encodedUserName, 'service': 'miniblog', 'servertime': serverTime, 'nonce': nonce, 'pwencode': 'rsa2', 'sp': encodedPassWord, 'encoding': 'UTF-8', 'prelt': '115', 'rsakv': rsakv, 'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack', 'returntype': 'META' } postData = urllib.urlencode(postPara)#网络编码 return postData def GetUserName(userName): "Used to encode user name" userNameTemp = urllib.quote(userName) userNameEncoded = base64.encodestring(userNameTemp)[:-1] return userNameEncoded def get_pwd(password, servertime, nonce, pubkey): rsaPublickey = int(pubkey, 16) key = rsa.PublicKey(rsaPublickey, 65537) #创建公钥 message = str(servertime) + '\t' + str(nonce) + '\n' + str(password) #拼接明文js加密文件中得到 passwd = rsa.encrypt(message, key) #加密 passwd = binascii.b2a_hex(passwd) #将加密信息转换为16进制。 return passwd
PostEncode函数构建POST的消息体,要求构建得到内容与真正登陆所需的信息相同,这些可以通过Httpfox插件查看。关于用户名和密码的加密,原来是SHA1,现在是RSA。
到这里,模拟登录就成功了。输出如下:
loginUrl: http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack&ssosavestate=1390390056&ticket=ST-MzQ4NzQ5NTYyMA==-1387798056-xd-284624BFC19FE242BBAE2C39FB3A8CA8&retcode=0 登录成功
其实登录是否成功只要看返回的url最后的retcode是不是=0。0表示登录成功,4049表示需要验证码,可以通过修改帐号的设置添加不需要登录验证的地区。4040表示登录次数过多。
接下来只需要在main函数内添加需要爬取的模块,比如:
htmlContent = urllib2.urlopen(myurl).read()#得到myurl网页的所有内容(html)