日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

轻松把玩HttpClient之封装HttpClient工具类(七),新增验证码识别功能

發布時間:2024/1/1 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 轻松把玩HttpClient之封装HttpClient工具类(七),新增验证码识别功能 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ?這個HttpClientUtil工具類分享在GitHub上已經半年多的時間了,并且得到了不小的關注,有25顆star,被fork了38次。有了大家的鼓勵,工具類一直也在完善中。最近比較忙,兩個多月前的修改在今天剛修改測試完成,今天再次分享給大家。


? ? ? ?驗證碼識別這項技術并不是本工具類的功能,而是通過一個開源的api來識別驗證碼的。這里做了一個簡單的封裝,主要是用來解決登陸時的驗證碼的問題。在線驗證碼識別官網:http://lab.ocrking.com/,github地址:https://github.com/AvensLab/OcrKing/,是一個功能非常強大的工具。


? ? ? ?好了,言歸正傳,本次封裝的工具重要代碼如下:

/** * 識別驗證碼* * @author arron* @date 2016年3月24日 上午9:44:35 * @version 1.0 */ public class OCR {/*** 接口說明:* https://github.com/AvensLab/OcrKing/blob/master/線上識別http接口說明.txt*/private static final String apiUrl = "http://lab.ocrking.com/ok.html";private static final String apiKey = PropertiesUtil.getProperty("OCR.key");private static final String boundary = "----------------------------OcrKing_Client_Aven_s_Lab";private static final String end="\r\n--" + boundary + "--\r\n";private static final Header[] headers = HttpHeader.custom() .referer("http://lab.ocrking.com/?javaclient0.1)").build();private static final Map<String, Object> map = getParaMap();private static HttpClient client =null; //=HCB.custom().proxy("127.0.0.1", 8888).build();public static void debug(){client =HCB.custom().proxy("127.0.0.1", 8888).build();}public static void exitDebug(){client =null;}//獲取固定參數private static Map<String, Object> getParaMap(){//加載所有參數Map<String , Object> map = new HashMap<String, Object>();map.put("service", "OcrKingForCaptcha");map.put("language", "eng");map.put("charset", "7");//7-數字大寫小寫,5-數字大寫字母map.put("type", "http://www.unknown.com");map.put("apiKey", apiKey);return map;}/*** 識別本地校驗碼(英文:字母+大小寫)* * @param imgFilePath 驗證碼地址* @return*/public static String ocrCode(String filePath){return ocrCode(filePath, 0);}/*** 識別本地校驗碼(英文:字母+大小寫)* * @param imgFilePath 驗證碼地址* @param limitCodeLen 驗證碼長度(如果結果與設定長度不一致,則返回獲取失敗的提示)* @return*/@SuppressWarnings("resource")public static String ocrCode(String imgFilePath, int limitCodeLen){byte[] data = null;String fileName = imgFilePath.replaceAll("[^/]*/|[^\\\\]*\\\\", "");StringBuffer strBuf = new StringBuffer();for (Entry<String, Object> entry : map.entrySet()) {strBuf.append("\r\n").append("--").append(boundary).append("\r\n");strBuf.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n");strBuf.append(entry.getValue());}strBuf.append("\r\n").append("--").append(boundary).append("\r\n");strBuf.append("Content-Disposition: form-data; name=\"ocrfile\"; filename=\"" + fileName + "\"\r\n");strBuf.append("Content-Type:application/octet-stream\r\n\r\n");//讀取文件File f = new File(imgFilePath);if(!f.exists()){return "Error:文件不存在!";}//內容長度=參數長度+文件長度+結尾字符串長度ByteArrayOutputStream bos = new ByteArrayOutputStream(strBuf.length()+(int)f.length()+end.length()); try {bos.write(strBuf.toString().getBytes());//轉化參數內容BufferedInputStream in = new BufferedInputStream(new FileInputStream(f)); int buf_size = 1024;int len = 0; byte[] buf = new byte[buf_size]; while (-1 != (len = in.read(buf, 0, buf_size))) { bos.write(buf, 0, len); } bos.write(end.getBytes());data= bos.toByteArray(); } catch (IOException e) { e.printStackTrace();}Map<String , Object> m = new HashMap<String, Object>();m.put(Utils.ENTITY_BYTES, data);String html;try {html = HttpClientUtil.post(HttpConfig.custom().client(client).url(apiUrl).headers(headers).map(m));//System.out.println(html);String[] results = StringUtil.regex("<Result>([^<]*)</Result>\\s*<Status>([^<]*)</Status>", html);if(results.length>0){//System.out.println(results[0]);if(limitCodeLen<=0 || limitCodeLen==results[0].length()){//不判斷長度或者長度一致時,直接返回return results[0];}}} catch (HttpProcessException e) {e.printStackTrace();}return "Error:獲取失敗!";}/*** 直接獲取網絡驗證碼(驗證碼不刷新)* * @param imgUrl 驗證碼地址* @return*/public static String ocrCode4Net(String imgUrl){return ocrCode4Net(imgUrl, 0);}/*** 直接獲取網絡驗證碼(驗證碼不刷新)* * @param imgUrl 驗證碼地址* @param limitCodeLen 驗證碼長度* @return*/public static String ocrCode4Net(String imgUrl, int limitCodeLen){Map<String, Object> map = getParaMap();map.put("url", imgUrl);Header[] headers = HttpHeader.custom().userAgent("Mozilla/5.0 (Windows NT 5.1; zh-CN; rv:1.9.1.3) Gecko/20100101 Firefox/8.0").build();try {String html = HttpClientUtil.post(HttpConfig.custom().client(client).url(apiUrl).headers(headers).map(map));//System.out.println(html);String[] results = StringUtil.regex("<Result>([^<]*)</Result>\\s*<Status>([^<]*)</Status>", html);if(results.length>0){//System.out.println(results[0]);if(limitCodeLen<=0 || limitCodeLen==results[0].length()){//不判斷長度或者長度一致時,直接返回return results[0];}}} catch (HttpProcessException e) {e.printStackTrace();}return "Error:獲取失敗!";}/*** 直接獲取網絡驗證碼(通過獲取圖片流,然后識別驗證碼)* * @param config HttpConfig對象(設置cookie)* @param savePath 圖片保存的完整路徑(值為null時,不保存),如:c:/1.png* @return*/public static String ocrCode4Net(HttpConfig config, String savePath){return ocrCode4Net(config, savePath, 0);}/*** 直接獲取網絡驗證碼(通過獲取圖片流,然后識別驗證碼)* * @param config HttpConfig對象(設置cookie)* @param savePath 圖片保存的完整路徑(值為null時,不保存),如:c:/1.png* @param limitCodeLen 驗證碼長度* @return*/@SuppressWarnings("resource")public static String ocrCode4Net(HttpConfig config, String savePath, int limitCodeLen){byte[] data = null;StringBuffer strBuf = new StringBuffer();for (Entry<String, Object> entry : map.entrySet()) {strBuf.append("\r\n").append("--").append(boundary).append("\r\n");strBuf.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n");strBuf.append(entry.getValue());}strBuf.append("\r\n").append("--").append(boundary).append("\r\n");strBuf.append("Content-Disposition: form-data; name=\"ocrfile\"; filename=\"" + "aaa" + "\"\r\n");strBuf.append("Content-Type:application/octet-stream\r\n\r\n");//下載圖片ByteArrayOutputStream out = new ByteArrayOutputStream();try {out = (ByteArrayOutputStream) HttpClientUtil.down(config.client(client).out(out));if(savePath==null || savePath.equals("")){}else{//本地測試,可以保存一下圖片,方便核驗FileOutputStream fos = new FileOutputStream(savePath);fos.write(out.toByteArray());}ByteArrayOutputStream bos = new ByteArrayOutputStream(out.size()+strBuf.length()+end.length());bos.write(strBuf.toString().getBytes());bos.write(out.toByteArray());bos.write(end.getBytes());data= bos.toByteArray();} catch (HttpProcessException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}Map<String , Object> m = new HashMap<String, Object>();m.put(Utils.ENTITY_BYTES, data);String html;try {html = HttpClientUtil.post(config.client(client).url(apiUrl).headers(headers).map(m));//System.out.println(html);String[] results = StringUtil.regex("<Result>([^<]*)</Result>\\s*<Status>([^<]*)</Status>", html);if(results.length>0){//System.out.println(results[0]);if(limitCodeLen<=0 || limitCodeLen==results[0].length()){//不判斷長度或者長度一致時,直接返回return results[0];}}} catch (HttpProcessException e) {e.printStackTrace();}return "Error:獲取失敗!";} } ? ? ? ?其實這個類中,主要用3個方法,第一個是識別本地圖片,第二個是識別網絡上的固定圖片,第三個是識別網絡上可刷新的驗證碼圖片。當然不管哪個方法,核心代碼都是讀取圖片字節流,上傳到api接口,通過接口進行識別。


? ? ? ?上面代碼中用到了StringUtil.regex方法,具體如下:

/*** 通過正則表達式獲取內容* * @param regex 正則表達式* @param from 原字符串* @return*/public static String[] regex(String regex, String from){Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(from);List<String> results = new ArrayList<String>();while(matcher.find()){for (int i = 0; i < matcher.groupCount(); i++) {results.add(matcher.group(i+1));}}return results.toArray(new String[]{});} ? ? ? ?由于識別驗證碼的api需要用到ke'y,所以就寫了一個配置文件config.properties,用于設置ke'y的值。同時提供了一個簡單的配置文件工具類: /*** 最簡單的屬性文件讀取工具類* * @author arron* @date 2016年1月14日 下午5:37:18 * @version 1.0*/ public class PropertiesUtil {/*** 默認屬性集合(文件在Constants中配置)*/protected static Properties defaultProp = null;/*** 所有讀取過的屬性集合* 文件名 <-> 屬性集合*/protected static Map<String, Properties> allProps = new HashMap<String, Properties>();// 初始化默認的屬性集合static {if (defaultProp == null) {defaultProp = loadProperties("config.properties");allProps.put("config.properties", defaultProp);}}/*** 讀取屬性文件,并將讀出來的屬性集合添加到【allProps】當中* 如果該屬性文件之前已讀取過,則直接從【allProps】獲得*/public static Properties getProperties(String fileName) {if (fileName==null || "".equals(fileName)) {return defaultProp;} else {Properties prop = allProps.get(fileName);if(prop == null) {prop = loadProperties(fileName);allProps.put(fileName, prop);}return prop;}} /*** 解析屬性文件,將文件中的所有屬性都讀取到【Properties】當中*/protected static Properties loadProperties (String fileName) {Properties prop = new Properties();InputStream ins = null;ins = PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName);if (ins == null) {System.err.println("Can not find the resource!");} else {try {prop.load(ins);} catch (IOException e) {System.err.println("An error occurred when reading from the input stream, "+e.getMessage());} catch (IllegalArgumentException e) {System.err.println("The input stream contains a malformed Unicode escape sequence, "+e.getMessage());}}return prop;}/*** 從指定的屬性文件中獲取某一屬性值* 如果屬性文件不存在該屬性則返回 null*/public static String getProperty(String fileName, String name){return getProperties(fileName).getProperty(name);}/*** 從默認的屬性文件中獲取某一屬性值* 如果屬性文件不存在該屬性則返回 null*/public static String getProperty(String name){return getProperties(null).getProperty(name);} } ? ? ? ?代碼也就這么多。在最后,提供一段測試代碼來測試該功能:核心邏輯就是通過HttpClientUtil的download方法獲取圖片,然后通過api進行識別,然后通過請求特定網址進行驗證識別的結果是否正確。 public static void main(String[] args) throws InterruptedException, HttpProcessException {String qq = "123456789";//qq號String imgUrl = "http://qqxoo.com/include/vdimgvt.php?t="+Math.random(); //獲取驗證碼圖片地址String verifyUrl = "http://qqxoo.com/include/vdcheck.php";String saveCodePath = "C:/1.png";//保存驗證碼圖片路徑Header[] headers = HttpHeader.custom().referer("http://qqxoo.com/main.html?qqid="+qq).build();//設置referer,是為了獲取對應qq號的驗證碼,否則報錯HttpConfig config = HttpConfig.custom().headers(headers).context(HttpCookies.custom().getContext());//必須設置context,是為了攜帶cookie進行操作String result =null;//識別結果do {if(result!=null){System.err.println("本次識別失敗!");}//獲取驗證碼//OCR.debug(); //開始Fiddler4抓包(127.0.0.1:8888)String code = OCR.ocrCode4Net(config.url(imgUrl), saveCodePath);while(code.length()!=5){//如果識別的驗證碼位數不等于5,則重新識別if(code.equals("親,apiKey已經過期或錯誤,請重新獲取")){System.err.println(code);return;}code = OCR.ocrCode4Net(config.url(imgUrl), saveCodePath);}System.out.println("本地識別的驗證碼為:"+code);System.out.println("驗證碼已保存到:"+saveCodePath);//開始驗證識別的驗證碼是否正確result = HttpClientUtil.get(config.url(verifyUrl+"?vc="+code+"&qqid="+qq));} while (result.contains("succeed"));System.out.println("識別驗證碼成功!反饋信息如下:\n" + result);} ? ? ? ?運行結果如下:



? ? ? ?最新的完整代碼請到GitHub上進行下載:https://github.com/Arronlong/httpclientUtil?。

? ? ? ?httpclientUtil (QQ交流群:548452686?)

總結

以上是生活随笔為你收集整理的轻松把玩HttpClient之封装HttpClient工具类(七),新增验证码识别功能的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。