本人之前用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了。如果不包括这两个值,那么如果验证码错误的话,返回到提交页面,上面原来部分输入的字段就是空的要重新输入,所以这两个参数应该是用来记录页面信息并还原的。请有经验的朋友指教指教,如果能解决,立马结贴,谢谢!Httpclient 验证码登录 自动登录程序

解决方案 »

  1.   

    顺便说一下,显示我的结贴率为0,因为这个id很久没用了,之前一直用另一个id的。这次特地上来把这个id里的分给用完。
      

  2.   

    关键就是没有错误信息,我上面也提到,最后那个post的页面,我用浏览器去访问并且用错误验证码去提交的话,结果会是继续返回到这个提交页面,然后系统刷新了一下那个验证码,并不会有报错。如果我用程序去post,然后打印出200 response的结果,也是返回到这个页面,但是我用的是正确的验证码,所以有点怀疑post之后是不是系统又刷新了一下验证码,但是用wiresharp和fiddler并没有看到,也没有理由post后服务器会去调用get刷新验证码。所以怀疑cookie/session的问题,但每次我都是设置cookie了的所以是不是做这种程序还有什么特别要注意的地方。 实在不行,打算用httpclient4做一下,或者模仿浏览器访问的流程,登录后先get一下这个提交页面,然后从上面拿下那个验证码图片 
      

  3.   

    我觉得这样的描述,不太容易找到原因。
    你用httpwatch看一下。这里有范例http://www.cnblogs.com/mayingbao/archive/2007/11/30/978530.html
      

  4.   

    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", "[email protected]");
    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方法中所使用到的。
    }
      

  5.   

    上面getFinalPostMethod里面
    post.setRequestBody(new NameValuePair[] { _EVENTTARGET, _EVENTARGUMENT,
     _VIEWSTATE, _EVENTVALIDATION, t1, t2, CheckCode, 
     CheckCode });
    上面多输入了一个CheckCode,实际代码里是没有的。
      

  6.   

    看着没啥问题
    httpClient.getCookieStore().getCookies()
    获取cookie,看看有没有set进去吧
      

  7.   

    调试通了!!!Cookie没问题。是一个很低级的问题,这个网站通过获取另个值来判断是否实际做了操作的,而我提交的那个值的name打错了一个字母,等于没提交成功。。瀑布汗。。依然谢谢楼上看了我的代码,并回复。 我顺便在这里问最后个问题,如果我要同时用3个用户名登录网站,都做一遍上面这个操作,(3个依次做也可以),是不是要用3个httpclient呢?怎么实现效率较高呢?最好不要用线程,感觉太麻烦。谢谢回答!
      

  8.   

    如果用一个httpclient依次做,会不会有问题?
    还是说要new多个httpclient?
      

  9.   

    网站把验证码写在cookie里??这种方式也太不安全了吧一般的做法都是直接放在session啊
    最近一直在研究验证码,有兴趣交流。