其实就这个问题,本来是很简单的,我自己花了近两个下午才搞定,现在记录一下。也希望能帮助后来的朋友。

先说httpclient

操蛋的httpclent!

  为什么说操蛋呢,因为从httpclient3到httpclient4,有很大的变化,而且我自己水平也不够,在jar包上出了很多问题(例如我不知道还有个httpcore)。

  jar如下:



为了验证我们最后的程序

我们可以先搭建一个带有验证码的登陆demo。

参考如下:

登陆验证码(struts2实现)

分析一下 大致的处理流程

以下面的login.jsp为例

<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<script type="text/javascript">
function changeValidateCode(obj) {
/***
  *   获取当前的时间作为参数,无具体意义
  *   每次请求需要一个不同的参数,否则可能会返回同样的验证码
  *   这和浏览器的缓存机制有关系,也可以把页面设置为不缓存,这样就不用这个参数了。
  */
	var timenow = new Date().getTime();    

	obj.src="randPic?d="+timenow;
}
</script>
</head>

<body>
	<form name="" action="loginWithYZMAction" method="post">
		用户名<input type="text" name="name" > <br>
		验证码<input type="text" name="code" > 

		<img src="randPic" onclick="changeValidateCode(this)" title="点击图片刷新验证码" /> <br />
		<input type="submit" value="登陆" /><input type="reset" value="重置" />
	</form>
</body>
</html>

当我们在浏览器上,输入login.jsp的时候,我们其实向服务器发送了两次请求

第一次请求jsp,在浏览器解析jsp(准确的说是html)的时候发现

<img src="randPic" onclick="changeValidateCode(this)" title="点击图片刷新验证码" /> <br />

然后就第二次向服务器发送了请求。

服务器第一次返回的信息里已经包含了session的id,我们要做的就是记录这个id

然后再向loginWithYZMAction这个action发送请求,当然得带上name,code还有之前得到的sessionid(cookie中保存的东西,除了sessionid,这些东西咱们后面再说)






然后关于验证码的读取,我现在使用的是人工读取,下一个步骤就是引入第三方的接口。









我们看代码说话

package com.zw;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

/*
 * 这个用来测试 bjadmin
 */
public class HttpProxyZW {

	//下面这两个url 第一个是登陆用的地址 第二个是获得验证码的地址
	private static String urlValidate="http://localhost:8600/BJAdmin/yzm/loginWithYZMAction";
	private static String urlGetCookieAndValidate="http://localhost:8600/BJAdmin/yzm/randPic";
	private  String cookie = null;

	/**
	 * 以行为单位读取文件,常用于读面向行的格式化文件
	 */
	public static String getYZM(String fileName) {

		InputStream in = null;
		try {
			Thread.sleep(10000);
			in = new FileInputStream(new File(fileName));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		Scanner s = new Scanner(in);
		while (s.hasNextLine()) {
			return s.nextLine();
		}
		return null;
	}

	public static void main(String[] args) {
		HttpProxyZW hp = new HttpProxyZW();
		hp.getPicAndCookie(hp.urlGetCookieAndValidate);

		List<NameValuePair> params = hp.getParameter();
		hp.getResponse2(hp.urlValidate, params);
	} 

		public List<NameValuePair> getParameter(){
		List<NameValuePair> params=new ArrayList<NameValuePair>();

		params.add(new BasicNameValuePair("eticketNoORIn","123456"));
		params.add(new BasicNameValuePair("passengerName_src","啦啦啦"));
		try {
			params.add(new BasicNameValuePair("passengerName",URLEncoder.encode("啦啦啦", "utf-8")));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		params.add(new BasicNameValuePair("validateFlag","0"));
		params.add(new BasicNameValuePair("invoiceNo",""));
		params.add(new BasicNameValuePair("imgSrc","/tsky/images/loading.gif"));

		params.add(new BasicNameValuePair("eticketNo","123456"));
		params.add(new BasicNameValuePair("invoiceNo",""));

		//这个目前比较操蛋
		//在e盘下 我下载了验证码
		//然后人工读出 后把字符写进src/yzm.txt
		String randCode=getYZM("src/yzm.txt");
		System.out.println(randCode);
		params.add(new BasicNameValuePair("code", randCode));
		return params;
	}

	private void downloadJPG(HttpResponse httpResponse) throws IOException {
		 InputStream input = httpResponse.getEntity().getContent();
         OutputStream output = new FileOutputStream(new File("E:\\1.jpg"));  

         IOUtils.copy(input, output);

         if (output != null) {
        	 output.close();
         }
         output.flush();  

	}

		/*
	 * 获取第一次下载图片的时候 远程服务器给我发的cookie
	 */
	public String getCookie(HttpResponse httpResponse) throws ClientProtocolException, IOException{

		String cookie="";
		Header[] headers=httpResponse.getHeaders("Set-Cookie");
		//BIGipServerpool_ip_port 这个参数是和负载均衡相关的
		//JSESSIONID 这就是sessionid
		for(Header h:headers){
			if (h.getValue().contains("BIGipServerpool_122")) {
				String BIGipServerpool=h.getValue().substring("BIGipServerpool_122.119.122.179_80=".length(),
						h.getValue().indexOf(";"));

				cookie+="BIGipServerpool_122.119.122.179_80="+BIGipServerpool;
			}
			if (h.getValue().contains("JSESSIONID")) {
				String JSESSIONID=h.getValue().substring("JSESSIONID=".length(),
						h.getValue().indexOf(";"));

				cookie+="JSESSIONID="+JSESSIONID;
			}
			//这些参数的作用 我不清楚 加上就是了

			cookie+="Hm_lvt_486e71cc1c3c5d7a07853a6e72364f55=1456716098;__utma=88932958.523101033.1456716098.1456716098.1456716098.1;__utmz=88932958.1456716098.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);CNZZDATA1256052643=1173832624-1456716029-%7C1456884431";

		}

		return cookie;
	}

	public CloseableHttpResponse getPicAndCookie(String url) {
		CloseableHttpClient httpclient = HttpClientBuilder.create().build();
		HttpPost httppost = new HttpPost(url);
		CloseableHttpResponse response =null;
		try {
			 response = httpclient.execute(httppost);
			 getCookie(response);
			downloadJPG(response);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		httppost.releaseConnection();
		return response;
	}

	public  void getResponse2(String url,List<NameValuePair> params)  {
	    CloseableHttpClient httpclient = HttpClientBuilder.create().build();

    	HttpPost httppost = new HttpPost(url);

    	 httppost.setHeader("Host", "www.travelsky.com");
    	 httppost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0");
    	 httppost.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
    	 httppost.setHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
    	 httppost.setHeader("Referer", "http://www.travelsky.com/tsky/validate");
    	 httppost.setHeader("Cookie", cookie);
    	 httppost.setHeader("Connection", "keep-alive");
		try {
			if (params != null)
				httppost.setEntity(new UrlEncodedFormEntity(params, "utf-8"));

			CloseableHttpResponse response = httpclient.execute(httppost);

			HttpEntity entity = response.getEntity();
			String jsonStr = EntityUtils.toString(entity, "utf-8");
			System.out.println("final result" + jsonStr);
			httppost.releaseConnection();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

参考资料

Cookie/Session机制详解

HttpClient4.x 使用cookie保持会话

HttpClient 解决中文乱码

使用HttpClient时遇到的 java.net.SocketException: Socket closed异常

HttpClient4登陆有验证码的网站的更多相关文章

  1. 模拟Post登陆带验证码的网站

    前言: 作者在一个项目需求 模拟用户登陆,获取该用户的订单记录. 该系统需要用户名,密码,验证码 (验证码为正楷的数字4位),于是参考网络一些文章,并进行了很多测试,总结步骤如下: 步骤1 : 通过h ...

  2. 利用htmlunit登陆带验证码图片的网站

    http://htsoft.org/html/y2011/822_using-htmlunit-landing-site-with-captcha-image.html 利用htmlunit登陆带验证 ...

  3. Jsoup爬取带登录验证码的网站

    今天学完爬虫之后想的爬一下我们学校的教务系统,可是发现登录的时候有验证码.因此研究了Jsoup爬取带验证码的网站: 大体的思路是:(需要注意的是__VIEWSTATE一直变化,所以我们每个页面都需要重 ...

  4. 用HttpWebRequest提交带验证码的网站

    using System; using System.Drawing; using System.IO; using System.Net; using System.Text; using Syst ...

  5. C# 利用 HttpWebRequest 和 HttpWebResponse 模拟登录有验证码的网站

    原文:C# 利用 HttpWebRequest 和 HttpWebResponse 模拟登录有验证码的网站 我们经常会碰到需要程序模拟登录一个网站,那如果网站需要填写验证码的要怎样模拟登录呢?这篇文章 ...

  6. php使用curl模拟登录带验证码的网站[开发篇]

    需求是这样的,需要登录带验证码的网站,获取数据,但是不可能人为一直去记录数据,想通过自动采集的方式进行,如下是试验出来的结果代码!有需要的可以参考下! <?php namespace Home\ ...

  7. JEECG--去掉(增加)登陆页面验证码功能 - CSDN博客

    JEECG--去掉(增加)登陆页面验证码功能 - CSDN博客https://blog.csdn.net/KooKing_L/article/details/79711379

  8. 登陆时验证码的制作(asp.net)

    登陆时验证码的制作(asp.net) 1.显示样式: 2.新建一个页,Default2.aspx 3.在Page_load事件拷入如下代码 stringtmp = RndNum(4); HttpCoo ...

  9. php使用curl模拟登录带验证码的网站

    需求是这样的,需要登录带验证码的网站,获取数据,但是不可能人为一直去记录数据,想通过自动采集的方式进行,如下是试验出来的结果代码!有需要的可以参考下! <?php namespace Home\ ...

随机推荐

  1. PySC2是DeepMind的“星际争霸II学习环境”(SC2LE)的Python组件

    PySC2是DeepMind的"星际争霸II学习环境"(SC2LE)的Python组件. 它暴露了暴雪娱乐公司的星际争霸II机器学习API作为Python RL环境. 这是Deep ...

  2. 浅谈@RequestMapping @ResponseBody 和 @RequestBody 注解的用法与区别

    浅谈@RequestMapping @ResponseBody 和 @RequestBody 注解的用法与区别 Spring 2.5 版本新增了注解功能, 通过注解,代码编写简化了很多:但熟悉注解的使 ...

  3. ios html5 audio 不能自动播放

    //修复ios 浏览器不能自动播放音频的问题 在加载时创建新的audio 用的时候更换src即可 Xut.fix = Xut.fix||{}; if (Xut.plat.isBrowser & ...

  4. easyui datagrid 动态表头2

    前端 function goqry() { $("#form").form("submit", { url: "CJCK_bjcjfx_yfsl.as ...

  5. C# TextBox 焦点

    TextBox焦点问题 1.失焦 KeyBoard.ClearFocus(); 存在一个问题,失去焦点之后,中文通过输入法依旧是可以输入的. 如果是中文文本框,按Enter失焦,同时禁止输入中文,可以 ...

  6. Ubuntu安装与配置KVM

    事前检查 查看一下linux是32位还是64位 file /bin/ls 确认一下 CPU支持硬件虚拟化(不支持也没关系,可以继续) egrep -o '(vmx|svm)' /proc/cpuinf ...

  7. iOS不能交互的几种情况

    alpha <=0.01 hidden = YES userInteraction = NO 父试图不允许交互,子试图也不允许交互: 在父试图可见范围内,可以交互,超出部分失效,不能交互

  8. 学习笔记:Zookeeper选举机制

    1.Zookeeper选举机制 Zookeeper虽然在配置文件中并没有指定master和slave 但是,zookeeper工作时,是有一个节点为leader,其他则为follower Leader ...

  9. 分布式一致性协议Raft原理与实例

    分布式一致性协议Raft原理与实例 1.Raft协议 1.1 Raft简介 Raft是由Stanford提出的一种更易理解的一致性算法,意在取代目前广为使用的Paxos算法.目前,在各种主流语言中都有 ...

  10. Android图表库MPAndroidChart(一)——了解他的本质,方能得心应手

    Android图表库MPAndroidChart(一)--了解他的本质,方能得心应手 我们项目中经常会遇到一些统计图,比如折线图,线形图等,在一些运动健康类的App中尤其的常见,这画起来要命,我以前就 ...