最近在做一个很恶搞的东西,利用httpClient来模拟登录校园网的网页认证,最开始有这个想法是因为那个烦人的数字验证码,天天要打开浏览器输入验证码,而且登录成功以后又要给浏览器设置代理上外网,于是悲剧发生了...浏览器的网页认证会半小时掉线一次,不得不重新输入验证码登录,非常的烦人。虽然后来发现使用火狐和Ghrome浏览器分别负责认证和上网浏览可以大大减少掉线几率,但是始终还是觉得不爽,尤其是在任务栏上总是要保留一个网页认证的任务条,看着总觉得心里别扭。
于是冒出了这么一个想法,我是不是可以用java来做一个数字验证码图像识别,然后利用httpClient来模拟登录认证呢,并且,认证成功后我将程序托盘化,方便下线或者切换网络。虽然好像听起来没什么太大的用途,但是我还是颇为激动的苦心摸索了将近一个月来实现这个东西。
首先是图像识别,记得上数字图像处理课程的时候,真是恨不得要杀了上课的老师,这讲的什么玩意儿,一大堆数学理论,真是听着要人命。后来在网上找了一堆关于如何使用java来处理图像的文章看了下,貌似简单的一些处理真是不难。验证码识别的具体流程我是这样实现的:首先必须要保证这个验证码图片的访问是在httpClient的会话之内,这一点很重要,否则你取到的验证码图片即使识别出来了,也是不能用来提交的。取下验证码图片先保存在本地磁盘上,然后使用java的io读取到内存中,通过字节级别的处理转换成像素矩阵,接下来的事情就好办了。首先进行灰度化,把验证码图片由彩色变成黑白的;然后进行二值化,这里的阈值呢就需要自己通过对大量验证码图片的测试情况来判断和设定了;因为验证码图片很简单,二值化以后基本上就可以得到一个很清晰的白色背景的黑色数字图片了;接下来的事情应该做什么呢,我是这样干的,首先建立一个动态分割的模块来动态划分出每个数字的最小矩形,因为每个数字占用的范围不一样,而且出现在图片中的位置会有变动,所以必须要动态的去找每个数字所在的矩形区域,找到以后提取出来保存成一个像素集,针对0-9都提取一次;至此,识别图像的工作已经完成了大半,现在就可以来对登录的时候随机出现的验证码图片进行识别了,识别的过程非常简单,还是从网上取下图片来,灰度化,二值化,动态分割,与我们前面保存出来的0-9的像素集进行对比,能对得上那个像素集就表明是数字几,至此,随机验证码图片识别完成。
接下来就是模拟登录了,这个事情就更简单了,首先我们利用HttpWatch来监视一下IE,将登录过程中所要POST的参数全部记下来,中间有一些参数是服务器返回的,有一些是js转换生成的,分析起来有点麻烦,用户名密码什么我做了一个GUI,由界面上的文本框作为输入接口来获取。最后还有一点要注意的就是这个程序的运行流程,因为这个东西要保持这个会话的状态,所以程序运行以后要一直保持运行状态,并且还要定时查询当前账户的余额和是否掉线了。这里第一次做的程序很粗糙,用了大量的静态方法,并且因为静态变量出现了很多空指针错误,然后不得不再次大量增加静态变量,虽然后来功能上实现了,但是心里一直觉得有一种缺憾。还好,这个校园网认证平台前天升级了,去掉了验证码,只需要输入账号和密码了,并且调整了POST的参数,使得我做的客户端果断登录不上去了。针对这种情况,我不得不重新鼓鼓气再一次来进行调整,同时因为这个情况的逼迫,我重新进行了设计,舍弃了辛辛苦苦弄好的随机验证码识别,并且决心不能再这么被静态变量和静态方法纠缠来纠缠去,到最后自己都弄不清楚程序很多部分的生命周期了。
这一次程序的修改所花的时间大大少于第一次设计这个程序所花的时间,感谢我第一次的设计,没有将图像处理和模拟登录以及GUI的功能混合得太深,所以这一次修改很轻松的删掉了图像处理模块,保留原有的GUI,对模拟登录模块的大量修改也是比较重复性的工作,一天时间我就将重新分析出来的新版网页认证流程融入到了修改后的校园网认证客户端之中。看着一成没变的GUI界面,谁能知道更新它背后的模拟登录功能的艰辛呢。
最后来说一下另外一个小小的更新吧,上一次设计的时候就想做这个事情,但是没做出来。这一次参考了网上的一段代码,成功实现了,觉得很有意义,特别分享到这里。
这个事情就是用win32程序来包装jar程序,上一次的实现非常的土,但是效率很高。上一次是用stdlib中的system()函数直接调用命令行,整个程序是void main的控制台程序,很土吧,但是效率很高,并且伴随着一个非常严重的问题,没有图标,找了很多资料,气氛上是不能给控制台程序设置图标,终于还是放弃了。
作为一个win32程序,怎么可以没有图标,这样的程序我第一反应就会认为它是木马或者病毒什么的,这一次我找到了比较完美的图标式win32实现办法。具体过程如下(VC6环境下):
1.新建一个Win32 Application的工程
2.插入->资源->Icon->新建或者引入->保存Script1.rc文件
3.工程->增加到工程->文件->选择Script1.rc和resource.h
4.新建一个cpp文件,并且使用如下代码:
5.编译工程,得到的exe文件的图标就是所指定的IDI_ICON1
特别注意:这个win32程序中没有再使用很土的system()函数,而是使用了比较高级的CreateProcess()函数来创建一个javaw的进程,这样做的原因有两个:
1.不会出现cmd闪烁一下的现象
2.万恶的360会瞬间屏蔽掉使用了system()函数的win32程序
至此,从心里感觉到这个程序所有流程基本上都在可控制的范围内了,那些static和NullPointer的纠结往事终于算是解开了。
于是冒出了这么一个想法,我是不是可以用java来做一个数字验证码图像识别,然后利用httpClient来模拟登录认证呢,并且,认证成功后我将程序托盘化,方便下线或者切换网络。虽然好像听起来没什么太大的用途,但是我还是颇为激动的苦心摸索了将近一个月来实现这个东西。
首先是图像识别,记得上数字图像处理课程的时候,真是恨不得要杀了上课的老师,这讲的什么玩意儿,一大堆数学理论,真是听着要人命。后来在网上找了一堆关于如何使用java来处理图像的文章看了下,貌似简单的一些处理真是不难。验证码识别的具体流程我是这样实现的:首先必须要保证这个验证码图片的访问是在httpClient的会话之内,这一点很重要,否则你取到的验证码图片即使识别出来了,也是不能用来提交的。取下验证码图片先保存在本地磁盘上,然后使用java的io读取到内存中,通过字节级别的处理转换成像素矩阵,接下来的事情就好办了。首先进行灰度化,把验证码图片由彩色变成黑白的;然后进行二值化,这里的阈值呢就需要自己通过对大量验证码图片的测试情况来判断和设定了;因为验证码图片很简单,二值化以后基本上就可以得到一个很清晰的白色背景的黑色数字图片了;接下来的事情应该做什么呢,我是这样干的,首先建立一个动态分割的模块来动态划分出每个数字的最小矩形,因为每个数字占用的范围不一样,而且出现在图片中的位置会有变动,所以必须要动态的去找每个数字所在的矩形区域,找到以后提取出来保存成一个像素集,针对0-9都提取一次;至此,识别图像的工作已经完成了大半,现在就可以来对登录的时候随机出现的验证码图片进行识别了,识别的过程非常简单,还是从网上取下图片来,灰度化,二值化,动态分割,与我们前面保存出来的0-9的像素集进行对比,能对得上那个像素集就表明是数字几,至此,随机验证码图片识别完成。
接下来就是模拟登录了,这个事情就更简单了,首先我们利用HttpWatch来监视一下IE,将登录过程中所要POST的参数全部记下来,中间有一些参数是服务器返回的,有一些是js转换生成的,分析起来有点麻烦,用户名密码什么我做了一个GUI,由界面上的文本框作为输入接口来获取。最后还有一点要注意的就是这个程序的运行流程,因为这个东西要保持这个会话的状态,所以程序运行以后要一直保持运行状态,并且还要定时查询当前账户的余额和是否掉线了。这里第一次做的程序很粗糙,用了大量的静态方法,并且因为静态变量出现了很多空指针错误,然后不得不再次大量增加静态变量,虽然后来功能上实现了,但是心里一直觉得有一种缺憾。还好,这个校园网认证平台前天升级了,去掉了验证码,只需要输入账号和密码了,并且调整了POST的参数,使得我做的客户端果断登录不上去了。针对这种情况,我不得不重新鼓鼓气再一次来进行调整,同时因为这个情况的逼迫,我重新进行了设计,舍弃了辛辛苦苦弄好的随机验证码识别,并且决心不能再这么被静态变量和静态方法纠缠来纠缠去,到最后自己都弄不清楚程序很多部分的生命周期了。
这一次程序的修改所花的时间大大少于第一次设计这个程序所花的时间,感谢我第一次的设计,没有将图像处理和模拟登录以及GUI的功能混合得太深,所以这一次修改很轻松的删掉了图像处理模块,保留原有的GUI,对模拟登录模块的大量修改也是比较重复性的工作,一天时间我就将重新分析出来的新版网页认证流程融入到了修改后的校园网认证客户端之中。看着一成没变的GUI界面,谁能知道更新它背后的模拟登录功能的艰辛呢。
最后来说一下另外一个小小的更新吧,上一次设计的时候就想做这个事情,但是没做出来。这一次参考了网上的一段代码,成功实现了,觉得很有意义,特别分享到这里。
这个事情就是用win32程序来包装jar程序,上一次的实现非常的土,但是效率很高。上一次是用stdlib中的system()函数直接调用命令行,整个程序是void main的控制台程序,很土吧,但是效率很高,并且伴随着一个非常严重的问题,没有图标,找了很多资料,气氛上是不能给控制台程序设置图标,终于还是放弃了。
作为一个win32程序,怎么可以没有图标,这样的程序我第一反应就会认为它是木马或者病毒什么的,这一次我找到了比较完美的图标式win32实现办法。具体过程如下(VC6环境下):
1.新建一个Win32 Application的工程
2.插入->资源->Icon->新建或者引入->保存Script1.rc文件
3.工程->增加到工程->文件->选择Script1.rc和resource.h
4.新建一个cpp文件,并且使用如下代码:
#include <windows.h>
#include "resource.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));//设定图标
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(si);
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW;
if (!CreateProcess(
NULL,
"javaw.exe -Xbootclasspath/a:lib/httpclient-4.2.1.jar;lib/httpcore-4.2.1.jar;lib/commons-logging-1.1.1.jar -jar lib/login.jar", //带参数的执行程序
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi))
{
MessageBox(NULL,"创建进程出错!","提示",0);
}
return 0;
}
5.编译工程,得到的exe文件的图标就是所指定的IDI_ICON1
特别注意:这个win32程序中没有再使用很土的system()函数,而是使用了比较高级的CreateProcess()函数来创建一个javaw的进程,这样做的原因有两个:
1.不会出现cmd闪烁一下的现象
2.万恶的360会瞬间屏蔽掉使用了system()函数的win32程序
至此,从心里感觉到这个程序所有流程基本上都在可控制的范围内了,那些static和NullPointer的纠结往事终于算是解开了。