关于httpclient处理图片验证码提交的问题

JavaLiver 2013-03-27 04:59:20
本人之前用httpclient 3做了个自动登录网站的程序,实现的功能为登录网站,并在另一个页面post一个请求,请求时有图片验证码。

登录功能没有问题,在后面的post之前,我先从网站用get方法获取这个最新的验证码图片,然后调用本地程序解析成正确的String,但是提交了之后还是回到这个提交页面。

我用浏览器模拟了一下这些操作,提交成功的话应该是返回302,并转到另一个page。如果是验证码错误,就会返回200,并回到提交的页面,原来的字段输入都会保存在页面上(用的应该是aspx的__VIEWSTATE和__EVENTVALIDATION)但不会提示验证码错误。
就因为网站本身不会提示验证码错误,所以我程序返回200,并回到原来的页面我就无从判断到底是什么原因,因为我在本地程序里看到的验证码的确是解析正确的。

猜测会不会是cookie的问题,但我登录之后,每次操作前都会获取一下cookie,并且在get或者post前,用httpclient再把cookie set回request里,这样跳转页面的话,session还能保持的。

或者是验证码重复刷新的问题,但是我用fiddler看过浏览器的请求过程,它先用get获取那个要提交的页面,然后会自动用get获取那个验证码,再人工点击提交form。我只不过是直接用get获取了那个验证码,然后post提交了那个页面。

也怀疑过是aspx的__VIEWSTATE和__EVENTVALIDATION,在我的post request里有这两个字段的值,每次用浏览器提交,似乎都是不变的,所以我直接写进request了。如果不包括这两个值,那么如果验证码错误的话,返回到提交页面,上面原来部分输入的字段就是空的要重新输入,所以这两个参数应该是用来记录页面信息并还原的。

请有经验的朋友指教指教,如果能解决,立马结贴,谢谢!
...全文
324 点赞 收藏 12
写回复
12 条回复
lzzgym 2013年10月14日
网站把验证码写在cookie里??这种方式也太不安全了吧 一般的做法都是直接放在session啊。。。 最近一直在研究验证码,有兴趣交流。。。。
回复 点赞
JavaLiver 2013年03月29日
如果用一个httpclient依次做,会不会有问题? 还是说要new多个httpclient?
回复 点赞
花谢尊前不敢香 2013年03月28日
看着没啥问题 httpClient.getCookieStore().getCookies() 获取cookie,看看有没有set进去吧
回复 点赞
花谢尊前不敢香 2013年03月28日
并发问题。。
回复 点赞
JavaLiver 2013年03月28日
调试通了!!!Cookie没问题。是一个很低级的问题,这个网站通过获取另个值来判断是否实际做了操作的,而我提交的那个值的name打错了一个字母,等于没提交成功。。瀑布汗。。。。。。。。。。。 依然谢谢楼上看了我的代码,并回复。 我顺便在这里问最后个问题,如果我要同时用3个用户名登录网站,都做一遍上面这个操作,(3个依次做也可以),是不是要用3个httpclient呢?怎么实现效率较高呢?最好不要用线程,感觉太麻烦。谢谢回答!
回复 点赞
JavaLiver 2013年03月27日
上面getFinalPostMethod里面 post.setRequestBody(new NameValuePair[] { _EVENTTARGET, _EVENTARGUMENT, _VIEWSTATE, _EVENTVALIDATION, t1, t2, CheckCode, CheckCode }); 上面多输入了一个CheckCode,实际代码里是没有的。
回复 点赞
JavaLiver 2013年03月27日
HttpClient client = new HttpClient(); client.getHostConfiguration().setHost(LOGON_SITE, LOGON_PORT, "http"); client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); client.getParams().setParameter(HttpMethodParams.USER_AGENT, "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko/20100101 Firefox/11.0"); HttpMethod method_post = getPostMethod(); // 使用 POST 方式提交数据 method_post.getParams().setParameter("http.protocol.cookie-policy", CookiePolicy.BROWSER_COMPATIBILITY); client.executeMethod(method_post); method_post.releaseConnection(); String tmpcookies = GetCookies(client); GetCheckCode(client, tmpcookies); HttpMethod final_post = getFinalPostMethod(); final_post.getParams().setParameter("http.protocol.cookie-policy", CookiePolicy.BROWSER_COMPATIBILITY); tmpcookies = GetCookies(client); final_post.setRequestHeader("cookie", tmpcookies); client.executeMethod(final_post); int statuscode = final_post.getStatusCode(); if (statuscode == 200) { String response = final_post.getResponseBodyAsString(); System.out.println(response); //如果验证码错误,返回的应该是200 } if (statuscode == 302) { //如果验证码正确,并且正确提交,返回的应该是302 Header header = final_post.getResponseHeader("location"); newuri = header.getValue(); System.out.println("final_post newuri:" + newuri); if ((newuri == null) || (newuri.equals(""))) newuri = "/"; GetMethod redirect = new GetMethod(newuri); tmpcookies = GetCookies(client); redirect.setRequestHeader("cookie", tmpcookies); client.executeMethod(redirect); System.out.println("==========Final Redirect:==========\n" + redirect.getStatusLine().toString()); System.out.println(redirect.getResponseBodyAsString()); redirect.releaseConnection(); } final_post.releaseConnection(); private static HttpMethod getPostMethod() { PostMethod post = new PostMethod("/login.aspx"); NameValuePair username = new NameValuePair("name", "my name"); NameValuePair password = new NameValuePair("password", "pass"); post.setRequestBody(new NameValuePair[] { username, password}); return post; } private static HttpMethod getFinalPostMethod() { PostMethod post = new PostMethod("/finalpost.aspx?m1=100"); NameValuePair _EVENTTARGET = new NameValuePair("__EVENTTARGET", ""); NameValuePair _EVENTARGUMENT = new NameValuePair("__EVENTARGUMENT", ""); NameValuePair _VIEWSTATE = new NameValuePair( "__VIEWSTATE", "/asdfuovansodfhasdhsdfkasdf="); NameValuePair _EVENTVALIDATION = new NameValuePair( "__EVENTVALIDATION", "/sdfgsdfasdfasdf=="); NameValuePair t1 = new NameValuePair("t1", "test"); NameValuePair t2 = new NameValuePair("t2", "test@sina.com"); NameValuePair CheckCode = new NameValuePair("CheckCode", code); post.setRequestBody(new NameValuePair[] { _EVENTTARGET, _EVENTARGUMENT, _VIEWSTATE, _EVENTVALIDATION, t1, t2, CheckCode, CheckCode }); post.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8"); post.setRequestHeader("referer","http://fortest.com.cn/finalpost.aspx?m1=100"); return post; } private static String GetCookies(HttpClient client) { String tmpcookies = ""; Cookie[] cookies = client.getState().getCookies(); for (Cookie c : cookies) { tmpcookies += c.toString() + ";"; } return tmpcookies; } public static void GetCheckCode(HttpClient client, String tmpcookies) throws HttpException, IOException { /********** Get Checkcode **********/ GetMethod getcode = new GetMethod("/getCode.aspx"); getcode.setRequestHeader("cookie", tmpcookies); client.executeMethod(getcode); System.out.println("getting code status: " + getcode.getStatusLine().toString()); InputStream inStream = getcode.getResponseBodyAsStream(); BufferedImage iag = ImageIO.read(inStream); //以下省略了较长的解析代码,弄成本地图片在本地解析,然后赋值到这个public类的String类型的code字段,code字段是在getFinalPostMethod方法中所使用到的。 }
回复 点赞
花谢尊前不敢香 2013年03月27日
没错误,就上代码先。
回复 点赞
-AJ- 2013年03月27日
我觉得这样的描述,不太容易找到原因。 你用httpwatch看一下。这里有范例http://www.cnblogs.com/mayingbao/archive/2007/11/30/978530.html
回复 点赞
JavaLiver 2013年03月27日
关键就是没有错误信息,我上面也提到,最后那个post的页面,我用浏览器去访问并且用错误验证码去提交的话,结果会是继续返回到这个提交页面,然后系统刷新了一下那个验证码,并不会有报错。如果我用程序去post,然后打印出200 response的结果,也是返回到这个页面,但是我用的是正确的验证码,所以有点怀疑post之后是不是系统又刷新了一下验证码,但是用wiresharp和fiddler并没有看到,也没有理由post后服务器会去调用get刷新验证码。所以怀疑cookie/session的问题,但每次我都是设置cookie了的。。。所以是不是做这种程序还有什么特别要注意的地方。 实在不行,打算用httpclient4做一下,或者模仿浏览器访问的流程,登录后先get一下这个提交页面,然后从上面拿下那个验证码图片。。。
回复 点赞
花谢尊前不敢香 2013年03月27日
具体错误信息。
回复 点赞
JavaLiver 2013年03月27日
顺便说一下,显示我的结贴率为0,因为这个id很久没用了,之前一直用另一个id的。这次特地上来把这个id里的分给用完。
回复 点赞
发动态
发帖子
Web 开发
创建于2007-09-28

5.2w+

社区成员

34.1w+

社区内容

Java Web 开发
社区公告
暂无公告