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\ ...
随机推荐
- C语言程序第三次作业
(一)改错题 计算f(x)的值:输入实数x,计算并输出下列分段函数f(x)的值,输出时保留1位小数. 输入输出样例1: Enterr x: 10.0 f(10.0) = 0.1 输入输出样例2: En ...
- Linux学习之CentOS(十)----Linux 的账号与群组
Linux 的账号与群组 管理员的工作中,相当重要的一环就是『管理账号』啦!因为整个系统都是你在管理的, 并且所有一般用户的账号申请,都必须要透过你的协助才行!所以你就必须要了解一下如何管理好一个服务 ...
- Centos Git1.7.1升级到Git2.2.1
安装需求: ># yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel asciidoc ># ...
- Python 头部 #!/usr/bin/python 和 #!/usr/bin/env 的区别
这个网址 https://www.cnblogs.com/scofi/p/4867851.html 讲述了Python 头部 #!/usr/bin/python 和 #!/usr/bin/env 的区 ...
- API说明书规范
目录 1 前言 1.1 编写目的 1.2 预期读者 1.3 关于API设计开发 2 API公共说明 3 文档API索引 ...
- 剑指架构师系列-MySQL调优
介绍MySQL的调优手段,主要包括慢日志查询分析与Explain查询分析SQL执行计划 1.MySQL优化 1.慢日志查询分析 首先需要对慢日志进行一些设置,如下: SHOW VARIABLES LI ...
- android NDK的下载-文件太大
需要FQ,建议使用VPN,下载前准备点时间配置网络环境.我的百度网盘好像有~~不过忘记地址了,改天共享,或者私聊我. 2015.4 Android 5.1 Android Studio https:/ ...
- nginx时间设置解析函数
https://trac.nginx.org/nginx/browser/nginx/src/core/ngx_parse.c /* * Copyright (C) Igor Sysoev * Cop ...
- 炫酷:一句代码实现标题栏、导航栏滑动隐藏。ByeBurger库的使用和实现
本文已授权微信公众号:鸿洋(hongyangAndroid)原创首发. 其实上周五的时候已经发过一篇文章.基本实现了底部导航栏隐藏的效果.但是使用起来可能不是很实用.因为之前我实现的方式是继承了系统的 ...
- Useful command for Docker
Copy file from Container to Host: docker cp <containerId>:/file/path/within/container /host/pa ...