HttpClient4登陆有验证码的网站
其实就这个问题,本来是很简单的,我自己花了近两个下午才搞定,现在记录一下。也希望能帮助后来的朋友。
先说httpclient
操蛋的httpclent!
为什么说操蛋呢,因为从httpclient3到httpclient4,有很大的变化,而且我自己水平也不够,在jar包上出了很多问题(例如我不知道还有个httpcore)。
jar如下:
为了验证我们最后的程序
我们可以先搭建一个带有验证码的登陆demo。
参考如下:
分析一下 大致的处理流程
以下面的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登陆有验证码的网站的更多相关文章
- 模拟Post登陆带验证码的网站
前言: 作者在一个项目需求 模拟用户登陆,获取该用户的订单记录. 该系统需要用户名,密码,验证码 (验证码为正楷的数字4位),于是参考网络一些文章,并进行了很多测试,总结步骤如下: 步骤1 : 通过h ...
- 利用htmlunit登陆带验证码图片的网站
http://htsoft.org/html/y2011/822_using-htmlunit-landing-site-with-captcha-image.html 利用htmlunit登陆带验证 ...
- Jsoup爬取带登录验证码的网站
今天学完爬虫之后想的爬一下我们学校的教务系统,可是发现登录的时候有验证码.因此研究了Jsoup爬取带验证码的网站: 大体的思路是:(需要注意的是__VIEWSTATE一直变化,所以我们每个页面都需要重 ...
- 用HttpWebRequest提交带验证码的网站
using System; using System.Drawing; using System.IO; using System.Net; using System.Text; using Syst ...
- C# 利用 HttpWebRequest 和 HttpWebResponse 模拟登录有验证码的网站
原文:C# 利用 HttpWebRequest 和 HttpWebResponse 模拟登录有验证码的网站 我们经常会碰到需要程序模拟登录一个网站,那如果网站需要填写验证码的要怎样模拟登录呢?这篇文章 ...
- php使用curl模拟登录带验证码的网站[开发篇]
需求是这样的,需要登录带验证码的网站,获取数据,但是不可能人为一直去记录数据,想通过自动采集的方式进行,如下是试验出来的结果代码!有需要的可以参考下! <?php namespace Home\ ...
- JEECG--去掉(增加)登陆页面验证码功能 - CSDN博客
JEECG--去掉(增加)登陆页面验证码功能 - CSDN博客https://blog.csdn.net/KooKing_L/article/details/79711379
- 登陆时验证码的制作(asp.net)
登陆时验证码的制作(asp.net) 1.显示样式: 2.新建一个页,Default2.aspx 3.在Page_load事件拷入如下代码 stringtmp = RndNum(4); HttpCoo ...
- php使用curl模拟登录带验证码的网站
需求是这样的,需要登录带验证码的网站,获取数据,但是不可能人为一直去记录数据,想通过自动采集的方式进行,如下是试验出来的结果代码!有需要的可以参考下! <?php namespace Home\ ...
随机推荐
- fatal error LNK1104: 无法打开文件“lua51.lib”
今天学习C++与Lua通信,遇到了问题:fatal error LNK1104: 无法打开文件"lua51.lib" 开发环境: VS2012 cocos版本:cocos2d-x- ...
- C语言程序设计第四次作业-选择结构
(一)改错题 输出三角形的面积和周长,输入三角形的三条边a.b.c,如果能构成一个三角形,输出面积area和周长perimeter(保留2位小数):否则,输出"These sides do ...
- django 发送手机验证码
一.流程分析: 1.用户在项目前端,输入手机号,然后点击[获取验证码],将手机号发到post到后台. 2.后台验证手机号是否合法,是否已被占用,如果通过验证,则生成验证码,并通过运行脚本,让短信运营商 ...
- JS区分中英文字符的两种方法: 正则和charCodeAt()方法
1.正则regExpForm.onblur=function(){ entryVal=this.value; entryLen=entryVal.length; cnChar=entryVal.mat ...
- Big Christmas Tree(poj-3013)最短路
Big Christmas Tree Time Limit: 3000MS Memory Limit: 131072K Total Submissions: 25823 Accepted: 5 ...
- SSH(struts2+hibernate+spring)总结
1 前三个文章 是我对ssh的具体实现 虽然没有真的写一个ssh的例子出来 但是 意思应该传达到了 主要还是注解注入的ssh太模块化了 感觉写出来意义不大 个人水平有限 说不清 2 我一开是写的是st ...
- centos 7 安装nvidia显卡驱动
How to install Nvidia drivers in CentOS 7 - Tutorial : http://www.dedoimedo.com/computers/centos-7- ...
- Webpack 4 Tutorial: from 0 Conf to Production Mode
webpack 4 is out! The popular module bundler gets a massive update. webpack 4, what's new? A massive ...
- 详解BLE 空中包格式—兼BLE Link layer协议解析
BLE有几种空中包格式?常见的PDU命令有哪些?PDU和MTU的区别是什么?DLE又是什么?BLE怎么实现重传的?BLE ACK机制原理是什么?希望这篇文章能帮你回答以上问题. 虽然BLE空中包(pa ...
- Git之(六)标签管理
发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本.将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来.所以,标签也是版本库的一个快照 ...