[Python代码]人人网登录脚本(含登录失败及验证码处理)
用Python实现的人人网登录脚本在网上并不少见,但是一般都没有对登录失败和验证码进行处理,而本文中的代码将对登录失败的情况进行具体的错误提示,并通过自动下载验证码手动输入的方式处理验证码问题。
本文中的代码是去年一次活动中,为了获得人人墙中的状态而编写的,代码中的一些部分参考了网上其他的脚本,今天又做了一定的修改。
在去年实现代码的过程时,人人墙还需要登录才能看到其中的状态,今天再看的时候发现人人墙已经不需要登录就可以查看状态了。而当初会遇到验证码的问题也是误打误撞,因为在脚本里把密码写错了,才碰到了大家一般没有碰到的验证码问题。
下面的代码是配置信息,文件为config.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# -*- coding: utf-8 -*- LOGINURL = r'http://www.renren.com/PLogin.do' ICODEURL = r'http://icode.renren.com/getcode.do?t=login&rnd=Math.random()' EMAIL = r'您的邮箱' PASSWORD = r'您的密码' # FailCode via "login-v6.js" FAILCODE = { '-1': '登录成功', '0': '登录系统错误,请稍后尝试', '1': '您的用户名和密码不匹配', '2': '您的用户名和密码不匹配', '4': '您的用户名和密码不匹配', '8': '请输入帐号,密码', '16': '您的账号已停止使用', '32': '帐号未激活,请激活帐号', '64': '您的帐号需要解锁才能登录', '128': '您的用户名和密码不匹配', '512': '请您输入验证码', '4096': '登录系统错误,稍后尝试', } |
其中,LOGINURL是登录用的地址,ICODEURL是获得验证码的地址。FAILCODE是登录失败时的错误信息,其来源是人人网登录时的一个javascript脚本(目前名为login-v6.js,约1080行位置处)。其中1、2、4、128均表示用户名和密码不匹配,实测知道4表示密码错误,128表示帐号不存在,另外两个不清楚。
在提交登录后,发现获得的response中的url是如下图所示的homeUrl所示的地址,用正则表达式获得其中的failCode字段的数据,和上面对应的信息匹配,输出错误信息。
上图中,还可以看到一个catchaCount字段,这是记录同一个邮箱地址密码错误的次数,当次数大于3时,即要求输入验证码,但此时更改邮箱地址则不会要求输入验证码。
下面是登录人人网时候post过去的数据,包括email(邮箱)、autoLogin(勾选自动登录时为true)、icode(提交的验证码)、origURL(登录后的目标页,默认为如图所示)、domain(域)、key_id(不清楚含义)、captcha_type(验证码类型)、password(密码)、rkey(不清楚用途)。
经过验证,一般情况下只需要提供email和password两项即可,不过为了应对登录后跳转的其他页面的应用,下面的脚本也加入了origURL字段。而对于要求输入验证码时,再加入icode字段。
下面的代码文件名为renren.py,是具体的实现代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# -*- coding: utf-8 -*- import urllib import urllib2 import cookielib import re import config class Renren(object): def __init__(self): self.operate = '' # response的对象(不含read) self.requestToken = self.rtk = '' self.icode = '' # 验证码 self.is_login = False self.cj = cookielib.CookieJar() self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj)) urllib2.install_opener(self.opener) self.requestToken_pattern = re.compile(r"get_check:'([-0-9]*)'") self.rtk_pattern = re.compile(r"get_check_x:'([a-zA-Z0-9]+)'") def login(self, email='', password='', origURL=''): postdata = { 'email': email, 'password': password, 'origURL': origURL, } ruid_pattern = re.compile(r"'ruid':'(\d+)'") failCode_pattern = re.compile(r"&failCode=(\d+)") print 'Login...' while not self.is_login: self.operate = self._get_response(config.LOGINURL, postdata) cur_url = self.operate.geturl() web_content = self.operate.read() ruid = ruid_pattern.search(web_content) if ruid: self.is_login = True print "用户 %s %s" % (ruid.group(1), config.FAILCODE['-1']) return True else: failCode = failCode_pattern.search(cur_url) if not failCode: print '无法获得错误代码' else: definate_failCode = failCode.group(1) # 确切的failCode字符串 if definate_failCode in config.FAILCODE.keys(): print config.FAILCODE[definate_failCode] if definate_failCode == '512': self._get_icode_img() self.icode = raw_input("请输入验证码: ") postdata['icode'] = self.icode continue else: print '未知错误' return False def _get_response(self, url, data = None): if data is not None: req = urllib2.Request(url, urllib.urlencode(data)) else: req = urllib2.Request(url) response = self.opener.open(req) return response def _get_requestToken(self, data): self.requestToken = self.requestToken_pattern.search(data).group(1) self.rtk = self.rtk_pattern.search(data).group(1) def _get_icode_img(self): icode_img = self._get_response(config.ICODEURL).read() self._write_file('icode.jpg', icode_img) def _write_file(self, filename, data): try: output_file = open(filename, 'wb') output_file.writelines(data) output_file.close() print '文件 %s 写入完成!' % filename except IOError: print "写文件失败!" |
在登录中,我们目前还没有用到_get_requestToken
。
在这段代码中,我的处理逻辑如下:
当已登录标志位为False时,执行循环:post数据执行模拟登录,获取当前网址(cur_url)、网页内容(web_content)、用户ID(ruid)。如果获取到ruid,则表示登录成功;否则,登录失败,获取失败代码failCode,输出失败信息,如果是需要输入验证码,则下载验证码图片,手动输入,重新执行循环,否则结束登录操作。下图是对应的流程图。
在这里,ruid是登录后页面源代码中均含有的一个选项,在XN.namespace( 'user' );
后面。由于目前不太清楚id和ruid有什么区别,并且看到的两个值是相同的,暂时使用的是ruid。
login.py是一个demo程序,用于实验登录效果。具体使用时根据具体的需求修改。
1 2 3 4 5 6 7 8 |
# -*- coding: utf-8 -*- import config import renren if __name__ == "__main__": my_account = renren.Renren() my_account.login(config.EMAIL, config.PASSWORD, '') |
博主你知道你的代码显示不出来么
擦…发表完评论就出来了,学习!
好帖子 实验一下可以不
当然可以,不过这个代码时间比较久了,不能确定现在还一定OK
好牛逼的说。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
好牛逼的说哈啊哈哈。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
不错。怎么看不到完整代码啊。
厉害,跑来看看icode