最近深感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
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并且打印咯
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库分分钟解决啊有木有。
# 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'))