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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章