Java 爬蟲之識別圖片驗證碼後登錄

這幾年Python爬蟲特別的火,我有個朋友是一個Python爬蟲工程師,本人菜雞Java開發工程師一名,最近所做的一個項目是需要去爬一個網頁的數據,但是進入網頁需要登錄,登錄需要輸入圖片驗證碼。爬蟲的第三方jar包用的是jsoup,圖片識別用的是tesj4j。話不多碩,上demo,奧利給!

一、下載jsoup.jar、tess4j的jar包,或者maven引入jsoup和tess4j的jar包。在windows環境下,但是tess4j本地開發需要調用dll文件還是需要的的,下載地址:點我。如下圖一,是tess4j下載解壓的完整目錄,dist放的是tess4j的jar包,如果你用的是maven,就直接導入這個tess4j版本的jar,lib放的是windows執行的dll文件和開發中需要用的、依賴的jar包,tessdata是字庫,我這裏是純識別數字,所以沒有引入中文字庫。我用的是maven,所以就只需要lib和tessdata這個兩個文件夾。

二、獲取驗證碼圖片,識別圖片中的驗證碼,設置用戶名、密碼,保持會話進行登錄。

     /**
     * 
     * @param url 系統地址
     * @param user 用戶名
     * @param pwd 密碼
     * @param tess4jpath tess4j的地址 如G:\test\Tess4J-3.4.8-src\Tess4J
     * @return
     */
    public Map login(String url, String user, String pwd,String tess4jpath) {
        Map<String,String> map = null;
        Connection.Response LoginResponse = null;
        try {
            LoginResponse = Jsoup.connect(url).method(Connection.Method.GET).execute();
            map = LoginResponse.cookies();//獲取會話,登錄後需要保持會話
            Document document = LoginResponse.parse();
            Element element = document.getElementById("驗證碼圖片標籤");
            String codeimgurl = url+element.attr("src");
            String codeimgpath = tess4jpath+"\\codeimg";
            //下載驗證碼圖片
            byte[] codeimgdata = Jsoup.connect(codeimgurl).ignoreContentType(true).execute().bodyAsBytes();
            FileUtils.saveImg(codeimgdata, codeimgpath, "codeimg.jpg");
            //識別樣本輸出地址
            String ocrResult = codeimgpath+"\\codetmpimgtmp.jpg";
            String OriginalImg = codeimgpath+"\\codeimg.jpg";
            //去噪點
            FileUtils.removeBackground(OriginalImg, ocrResult);
            ITesseract instance =new Tesseract();
            instance.setDatapath(tess4jpath);
            File imgDir =new File(ocrResult);
            String code = instance.doOCR(imgDir);//識別驗證碼
            System.out.println("code:"+code); 
            Map datas = new HashMap();
            datas.put("user", user);
            datas.put("pwd", pwd);
            datas.put("ident",code);
            Connection connection = Jsoup.connect(url+"/login?op=userLogin");
            //輸入用戶名和密碼保持會話登錄
            Connection.Response response1 = connection.data(datas).cookies(map).method(Connection.Method.POST).execute();
        } catch (IOException e) {
            map = null;
            e.printStackTrace();
        } catch (TesseractException e) {
            map = null;
            e.printStackTrace();
        }finally {
            return map;
        }
    }

上述代碼中使用的工具類

public class FileUtils {
    /**
     * 級聯創建目錄
     * @param path
     */
    public static void creatDir(String path) {
        File file = new File(path);
        if(!file.exists()) {
            file.mkdirs();
        }
    }
    /**
     * 驗證碼圖片處理
     * @param imgUrl
     * @param resUrl
     */
    public static void removeBackground(String imgUrl, String resUrl){
        //定義一個臨界閾值
        int threshold = 300;
        try{
            BufferedImage img = ImageIO.read(new File(imgUrl));
            int width = img.getWidth();
            int height = img.getHeight();
            for(int i = 1;i < width;i++){
                for (int x = 0; x < width; x++){
                    for (int y = 0; y < height; y++){
                        Color color = new Color(img.getRGB(x, y));
                        //System.out.println("red:"+color.getRed()+" | green:"+color.getGreen()+" | blue:"+color.getBlue());
                        int num = color.getRed()+color.getGreen()+color.getBlue();
                        if(num >= threshold){
                            img.setRGB(x, y, Color.WHITE.getRGB());
                        }
                    }
                }
            }
            for(int i = 1;i<width;i++){
                Color color1 = new Color(img.getRGB(i, 1));
                int num1 = color1.getRed()+color1.getGreen()+color1.getBlue();
                for (int x = 0; x < width; x++)
                {
                    for (int y = 0; y < height; y++)
                    {
                        Color color = new Color(img.getRGB(x, y));

                        int num = color.getRed()+color.getGreen()+color.getBlue();
                        if(num==num1){
                            img.setRGB(x, y, Color.BLACK.getRGB());
                        }else{
                            img.setRGB(x, y, Color.WHITE.getRGB());
                        }
                    }
                }
            }
            File file = new File(resUrl);
            if (!file.exists())
            {
                File dir = file.getParentFile();
                if (!dir.exists())
                {
                    dir.mkdirs();
                }
                try
                {
                    file.createNewFile();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
            ImageIO.write(img, "jpg", file);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 保存文件
     * @param imgdata
     * @param filePath
     * @param filename
     */
    public static void saveImg(byte[] imgdata,String filePath,String filename) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        File dir = new File(filePath);
        try {
            if(!dir.exists()&&dir.isDirectory()) {
                dir.mkdirs();
            }
            file = new File(filePath+File.separator+filename);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(imgdata);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(bos!=null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fos!=null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

注意:並不是所有的系統的驗證碼都能識別,就拿這個12306來說,我也不知道怎麼識別,關鍵是我也不敢問啊!我識別的驗證碼是簡單的數字驗證碼,原始驗證碼  ,去噪的驗證碼    ,去噪後的驗證碼便於識別數字。

不管怎麼樣,希望你使用的Java爬蟲要用在正途上,畢竟最近也聽說了有爬蟲工程師被抓判刑的消息,所謂細水長流,我們要走可持續發展的道路。

發佈了44 篇原創文章 · 獲贊 44 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章