您的位置:首页 > 编程语言 > Python开发

Python3.4 模拟登录校园网 技巧和大坑记录 无验证码

2014-09-10 19:30 676 查看
最近深感python重要,加之raspberry上也需要,关键是能全力地解决问题而不是把时间耗散在实现的细节上,对于完成模型什么的还是非常牛的,于是先写一个模拟登陆来练练手。一开始就挑软柿子捏吧,选了学校的选课网站。无验证码。准备下一次挑个有验证码的玩玩

先把重要的技巧写出来吧,我的的是python3.4,最新版,各种碰壁各种坑,但索性一个个克服过来了,

首先推荐的是http://www.crifan.com/note_about_website_crawl_and_emulate_login/ 这位大神的文章,各种模拟登陆的技巧啊哈哈,本人也受益良多。以下有些部分也是重复的,不过都是自己实际碰上的坑,而且是python3.4版本的,所以还是写下来作为记录

一、辅助工具:wireshark:过滤器那里调到http,然后关闭其他无关的浏览器等等程序,然后再跑python程序,就能很舒服地对python发出的数据包进行查看了哦!当然也可以用Fiddler这个程序,不过urlopen请求的时候要设置代理

2、Fiirebug,调试JS,查看数据包,审查元素什么的都不在话下。不过不能查看python发送的数据包,所以还是需要wireshark配合

二、IDE 推荐Pycharm,知乎上好多人推荐那我也用这个鸟

三、python3对于python2 的改动非常多,而网络上现有的代码大多是基于python2的,所以做好改错的心理准别。如果不想把时间浪费在上面那么就建议直接使用python2,.7版本。其实不能向下兼容真的是一大败笔,尽管设计更加科学了,最大的改动无疑就是urllib模块了,以前杂乱无章的层次被改成了现在的urllib.parser   urllib.request  比如urllib.request.urlopen这样的,cookie模块变成了 http.cookiejar ,具体的查看下方源码吧。

五、编码问题:

首先是总结一下对于编码的做法:python内部用的是unicode,而如果要向外输出,那就需要编码(encode),比如UTF8 UTF16 GBK这类的,如果输入(比如从网络上抓取的网页,比如文件的读取),就需要解码成unicode,然后才能愉快的在python里头显示出各种字符,否则UTF8没有经过解码,直接print,如果英文还算正常,中文的话就会出现\xab\x21\x5b 这样的十六进制表示(三组一个汉字)。于是总结出的通用处理方法就是,输入时候统一解码成unicode,输出时候再统一编码成需要的编码

编码还算是挺容易的,string有encode函数,这在python3 python2一样

但是解码就不一样了

在python3里头已经去掉了decode()这个函数了,这个时候

request = urllib.request.Request('http://xxxxxxxxxx',None, headers1)
response = urllib.request.urlopen(request)
text = response.read()
text得到的是bytes字节数组,目前较好的的做法(不知道有没有其他更好的方法呢?)是
text.decode("utf-8")
或者 str(text,encoding='utf-8')
byte数组有decode方法来解码bytes对象

关于编码的问题如果想深入了解可以参考http://blog.csdn.net/kiki113/article/details/4062063  不过这篇文章仍旧是2.x版本的做法,不过原理并无二致

https://mail.python.org/pipermail/tutor/2014-February/100119.html  在python这个邮件组里头也有过2.x版本和3.x版本编码的讨论,觉得非常赞。文章里提到

With the move from Python 2 to Python 3 string handling was changed

py2     --> py3

-----------------

str     --> bytes

unicode --> str

意思就是原来py2的str到python3就是bytes对象,原来的unicode成了python3的str

六、cookie头部设置问题:如果期望http.cookiejar自动在请求包header里附加cookie项目,那你就绝对不要手动在header里头设置cookie,否则是不会自动加上cookie的

以下是错误示范  
headers1 = {'User-Agent': ' Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': ' zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3',
'Referer': 'http://xxxxxxxx',
'Connection': 'keep-alive',
'Content-Length': '0',
'Content-Type': '    application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest'
'Cookie':'xxxxxxx'
 }
七、仍旧是header的设置问题。不要设置Accept-Encoding项目,否则你还要自己解压完才能识别编码,时间宝贵,多一步不如少一步不是?
#  'Accept-Encoding': 'gzip, deflate',#大坑。加入后要手动对gzip解压后才会有可识别的内容
八、关于如何调试cookie,可以用wireshark抓包,也可以
cj = http.cookiejar.LWPCookieJar()
-------省略若干行------------
if cj:
for cookie in cj:
print(cookie)
因为cookiejar是一个可迭代对象(sdk手册里提到),所以可以用迭代器遍历所有cookie并且打印咯

八、有些待发送数据的生成是依靠javascript代码的,比如时间戳,比如密码的加密传输。这就靠firebug,各种审查元素,各种断点来调试出来了。

比如这一次就比较容易,密码
makeTransferPwd: function (name, pwdPlain){
dojo.require("dojox.encoding.digests.MD5");
var dxd=dojox.encoding.digests;
var inp= "NS" + name + pwdPlain;
var r_hex= dxd.MD5(inp, dxd.outputTypes.Hex);
return r_hex;
},
太直观了吧。。md5加密的NS+用户名+密码 字符串。python的hashlib库分分钟解决啊有木有。

九、并不是所有界面都会派发session的cookie的。这次这个登录界面就没有。难道是post用户密码时候根本就不对有没有session进行检查吧?



tip说完了就直接上源代码了。涉及隐私部分一律xxxxxxxxx代替,仅仅提供模板的作用,因为各个网站千差万别。

# coding=utf-8
import urllib
import hashlib
import http.client
import http.cookiejar
import http.cookies

#post数据接收和处理的页面(我们要向这个页面发送我们构造的Post数据)
posturl = 'http://xxxxxxxxxxxx/xxxxxx.do'  #从提交数据包中分析出,处理post请求的url

#设置一个cookie处理器,它负责从服务器下载cookie到本地,并且在发送请求时带上本地的cookie
cj = http.cookiejar.LWPCookieJar()
cookie_support = urllib.request.HTTPCookieProcessor(cj)
opener = urllib.request.build_opener(cookie_support, urllib.request.HTTPHandler)
urllib.request.install_opener(opener)
#打开登录主页面(他的目的是从页面下载cookie,这样我们在再送post数据时就有cookie了,否则发送不成功,当然有的网站也不对此做要求,那就省去这一步)
h = urllib.request.urlopen('http://xxxxx.edu.cn/ntms/index.do')

#构造header,一般header至少要包含一下两项。这两项是从抓到的包里分析得出的。

headers = {'User-Agent': ' Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0',
           'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
           'Accept-Language': ' zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3',
           #  'Accept-Encoding': 'gzip, deflate',#大坑。加入后要手动对gzip解压后才会有可识别的内容
           'Referer': 'http://xxxxx/userlogin.jsp?reason=login',
           'Connection': 'keep-alive',
           'Content-Type': 'application/x-www-form-urlencoded',
}
#构造Post数据,也是从抓大的包里分析得出的。

postData = {'j_username': 'xxxxxxxx',
            'j_password': 'fc5700426c8d6a74b0cdf987b63922d3',  #你的密码,密码可能是明文传输也可能是密文,如果是密文需要调用相应的加密算法加密,需查看js代码
#才知我就直接硬编码了
            'save_cookie': 'none'
}

#需要给Post数据编码
postData = urllib.parse.urlencode(postData).encode(encoding='UTF-8')

#通过urllib.request提供的Request方法来向指定Url发送我们构造的数据,并完成登录过程
request = urllib.request.Request(posturl, postData, headers)
response = urllib.request.urlopen(request)
text = response.read()

#测试是否成功登陆,这里是请求用户信息,如果成功登陆,那么cookie发到这个页面之后就会返回用户资料,否则提示错误,也知道自己登陆失败了
headers1 = {'User-Agent': ' Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language': ' zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3',
            #  'Accept-Encoding': 'gzip, deflate',#大坑。加入后要手动对gzip解压后才会有可识别的内容
            'Referer': 'http://xxxx.edu.cn/ntms/userLogin.jsp?reason=logout',
            'Connection': 'keep-alive',
            'Content-Length': '0',
            'Content-Type': '    application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With': 'XMLHttpRequest'
}
request = urllib.request.Request('http://xxxx.edu.cn/action/getCurrentUserInfo.do', None, headers1)
response = urllib.request.urlopen(request)
text = response.read()
#打印回应的内容
print(str(text, encoding='utf-8', errors='strict'))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息