selenium处理极验滑动验证码

要爬取一个网站遇到了极验的验证码,这周都在想着怎么破解这个,网上搜了好多知乎上看到有人问了这问题https://www.zhihu.com/question/28833985,我按照这思路去大概实现了一下。

1.使用htmlunit(这种方式我没成功,模拟鼠标拖拽后轨迹没生成,可以跳过)

我用的是java,我首先先想到了用直接用htmlunit,我做了点初始化

private void initWebClient() {
        if (webClient != null) {
            return;
        }
        webClient = new WebClient(BrowserVersion.FIREFOX_24);
         webClient.getOptions().setProxyConfig(new ProxyConfig("127.0.0.1",8888));
        webClient.getOptions().setActiveXNative(true);
        webClient.getOptions().setUseInsecureSSL(true); // 配置证书
        webClient.getOptions().setJavaScriptEnabled(true);
        webClient.getOptions().setCssEnabled(true);
        webClient.setCssErrorHandler(new SilentCssErrorHandler());
        webClient.getOptions().setThrowExceptionOnScriptError(false);
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
        CookieManager cookieManager = new CookieManager();
        List<org.apache.http.cookie.Cookie> httpCookies = client.getCookies();//其方式获取的cookie
        for (org.apache.http.cookie.Cookie cookie : httpCookies) {
            cookieManager.addCookie(new com.gargoylesoftware.htmlunit.util.Cookie(cookie));
        }
        webClient.setCookieManager(cookieManager);
    }

初始化代理,cookie..然后就能正常调用了

HtmlPage page = webClient.getPage("http://www.qixin.com/login");//企信宝
gePageInfor(page);

下面就是我获取图片,还原图片并且模拟拖拽,(这里我觉得是有些问题的,可能是拖拽我模拟的不对导致触发的js并没有生成正确的轨迹,还请大家帮忙看看哪里错了)

private void gePageInfor(HtmlPage page) {
        String[] img_slice={"div", "class", "gt_cut_fullbg_slice"};
        String[] img_bg_slice={"div", "class", "gt_cut_bg_slice"};
        HtmlDivision div = (HtmlDivision) page.getElementById("captcha");
        int deCAPTCHA = 0;
        try {
            byte[] img_slice_binary = client.get(getImgUrl(img_slice, div, true)).getBinary();//获取图片byte
            byte[] img_bg_slice_binary = client.get(getImgUrl(img_bg_slice, div, false)).getBinary();
            //获取还原后的图片
            BufferedImage geetestImg = ImgTest.getGeetestImg(img_slice_binary, ImgTest.imgArray);
            BufferedImage geetestImg2 = ImgTest.getGeetestImg(img_bg_slice_binary, ImgTest.imgArray);
            //获得图片移动位置(目前还有问题,需改用第三方图片识别)
            deCAPTCHA =ImgTest.deCAPTCHA(geetestImg,geetestImg2);
            System.out.println(deCAPTCHA);
        } catch (IOException | FetchException e) {
            e.printStackTrace();
        }
        HtmlDivision div_slider_knob = get_div_slider_knob(page,"gt_slider_knob gt_show");//获取要移动div
        HtmlPage mouseOver = (HtmlPage) div_slider_knob.mouseOver();
        HtmlPage mouseDownPage = (HtmlPage)div_slider_knob.mouseDown();
        div_slider_knob = get_div_slider_knob(mouseDownPage,"gt_slider_knob gt_show moving");
        mouseMoveX(deCAPTCHA, div_slider_knob, mouseDownPage);
        HtmlPage newPage =(HtmlPage)div_slider_knob.mouseOver();
//        newPage =(HtmlPage)div_slider_knob.mouseDown();
        System.out.println(newPage.asXml());
        div = (HtmlDivision)newPage.getElementById("captcha");
        HtmlElement htmlElement = div.getElementsByAttribute("div", "class", "gt_slice gt_show moving").get(0);
        System.out.println(htmlElement);
        newPage =(HtmlPage)div_slider_knob.mouseUp();//触发js,轨迹没有生成
        System.out.println("---------------");
        System.out.println(newPage.asXml());
        if (newPage.getElementById("captcha")!=null) {//错误重试
            //gePageInfor(newPage);
        }
    }

    private void mouseMoveX(int deCAPTCHA, HtmlDivision div_slider_knob, HtmlPage mouseDown) {
        MouseEvent mouseEvent = new MouseEvent(div_slider_knob, MouseEvent.TYPE_MOUSE_MOVE, false, false, false, MouseEvent.BUTTON_LEFT);
        mouseEvent.setClientX( mouseEvent.getClientX()+((deCAPTCHA!=0)?deCAPTCHA:99));    //移动x坐标
        ScriptResult scriptResult = mouseDown.getDocumentElement().fireEvent(mouseEvent);
    }
    private HtmlDivision get_div_slider_knob(HtmlPage page,String classString) {
        return (HtmlDivision)(((HtmlDivision) page.getElementById("captcha")).getElementsByAttribute("div", "class", classString).get(0));
    }

    private String getImgUrl(String[] img_slice, HtmlDivision div, boolean isNeedCheckPostion) {
        String url ="";
        int[] postion = new int[2];
        boolean empty = div.getElementsByAttribute(img_slice[0],img_slice[1],img_slice[2]).isEmpty();
        if (div.hasChildNodes() && !empty) {
            List<HtmlElement> elementsByAttribute = div.getElementsByAttribute(img_slice[0],img_slice[1],img_slice[2]);
            for(int i = 0;i<elementsByAttribute.size();i++){
                HtmlDivision div_img = (HtmlDivision)elementsByAttribute.get(i);
                String style = div_img.getAttribute("style");
                String[] imge_url_position = style.split(";");
                if(StringUtils.isBlank(url)){//确认url
                    url = StringUtils.replacePattern(imge_url_position[0], ".*\\(", "").replace(")", "");
                }
                if (isNeedCheckPostion) {//确认图片切割postion,两张图切割方式一样  background-position: -157px -58px
//                    String[] positionS = StringUtils.split(StringUtils.remove(imge_url_position[1], "px").replace("-", "").replaceAll(".*:", ""), null);
                    String[] positionS = StringUtils.split(StringUtils.removePattern(imge_url_position[1], "[^\\d+ \\s]"),null);
                    postion[0] = Integer.parseInt(positionS[0]);
                    postion[1] = Integer.parseInt(positionS[1]);
                    int[] is = ImgTest.imgArray[i];
                    if (is[0]!=postion[0]||is[1]!=postion[1]) {
                        logger.debug("更新分割postion");
                        ImgTest.imgArray[i] = postion;
                    }
                    System.out.println(ImgTest.imgArray);
                    isNeedCheckPostion= false;
                }
            }
        }
        return url;
    }

对比图片获取位移方法(deCAPTCHA)是错的我就不放代码了,下面是其中还原图片用的方法,目前是其实审查元素后你就明白怎么还原这个图片了,这里是每次读的10px,58px

public static BufferedImage getGeetestImg(byte[] binary, int[][] imgArray) throws IOException {
        BufferedImage img = ImageIO.read(new ByteArrayInputStream(binary));
        List<BufferedImage> list = new ArrayList<>();
        for (int i=0;i< imgArray.length;i++) {
            BufferedImage subimage = img.getSubimage(imgArray[i][0], imgArray[i][1], 10, 58);
            list.add(subimage);
//            ImageIO.write(subimage, "jpg", new File("d:\\image\\imgs"+i+".jpg"));
        }
        BufferedImage mergeImageUp = null;
        BufferedImage mergeImageDown = null;
        int mid = list.size()>>>1;
        for (int i = 0; i <mid-1 ; i++) {
            mergeImageUp =  mergeImage(mergeImageUp==null?list.get(i):mergeImageUp, list.get(i+1), true);
        }
        for(int i = mid;i<list.size()-1;i++){
            mergeImageDown = mergeImage(mergeImageDown==null?list.get(i):mergeImageDown,list.get(i+1), true);
        }
        img = mergeImage(mergeImageUp, mergeImageDown, false);
        return img;
    }
     public static BufferedImage mergeImage(BufferedImage img1,
                BufferedImage img2, boolean isHorizontal) throws IOException {
            int w1 = img1.getWidth();
            int h1 = img1.getHeight();
            int w2 = img2.getWidth();
            int h2 = img2.getHeight();
            // 从图片中读取RGB
            int[] ImageArrayOne = new int[w1 * h1];
            ImageArrayOne = img1.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 逐行扫描图像中各个像素的RGB到数组中
            int[] ImageArrayTwo = new int[w2 * h2];
            ImageArrayTwo = img2.getRGB(0, 0, w2, h2, ImageArrayTwo, 0, w2);

            // 生成新图片
            BufferedImage DestImage = null;
            if (isHorizontal) { // 水平方向合并
                DestImage = new BufferedImage(w1+w2, h1, BufferedImage.TYPE_INT_RGB);
                DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
                DestImage.setRGB(w1, 0, w2, h2, ImageArrayTwo, 0, w2);
            } else { // 垂直方向合并
                DestImage = new BufferedImage(w1, h1 + h2,
                        BufferedImage.TYPE_INT_RGB);
                DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
                DestImage.setRGB(0, h1, w2, h2, ImageArrayTwo, 0, w2); // 设置下半部分的RGB
            }

            return DestImage;
        }
    

2.使用selenium

后来我想着是我模拟鼠标这个动作哪里有问题,我就又找到了selenium(2.42.2),他也能操作htmlunit关键他的鼠标动作好像封装比较完全

但是我尝试了以后发现了这个,HtmlUnitMouse这个动作没有实现

 public void mouseMove(Coordinates where, long xOffset, long yOffset) {
    throw new UnsupportedOperationException("Moving to arbitrary X,Y coordinates not supported.");
  }

好吧,于是调用chrome吧

System.setProperty("webdriver.chrome.driver","C:\\chromedriver.exe");
        Proxy proxy = new Proxy();
        //设置代理服务器地址
        proxy.setHttpProxy("127.0.0.1:8888");
//        DesiredCapabilities capabilities = DesiredCapabilities.htmlUnitWithJs();
        DesiredCapabilities capabilities = DesiredCapabilities.chrome();
        capabilities.setCapability(CapabilityType.PROXY, proxy);
//        final WebDriver driver = new HtmlUnitDriver(capabilities);
        WebDriver driver = new ChromeDriver(capabilities);
        driver.get("http://www.qixin.com/login");
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
         checkPage(driver,"return $(‘.gt_cut_fullbg_slice‘);");
        // 获取 网页的 title
        System.out.println("1 Page title is: " + driver.getTitle());
        // 通过 id 找到 input 的 DOM
        String pageSource = driver.getPageSource();
        System.out.println(pageSource);
        org.openqa.selenium.JavascriptExecutor executor = (org.openqa.selenium.JavascriptExecutor)driver;
        boolean equals = executor.executeScript("return document.readyState").equals("complete");
        int moveX =99;//移动位置
        if (equals) {
            WebElement element = driver.findElement(By.className("gt_slider_knob"));//(".gt_slider_knob"));
            Point location = element.getLocation();
            element.getSize();
            Actions action = new Actions(driver);
            //             action.clickAndHold().perform();// 鼠标在当前位置点击后不释放
//             action.clickAndHold(element).perform();// 鼠标在 onElement 元素的位置点击后不释放
//             action.clickAndHold(element).moveByOffset(location.x+99,location.y).release().perform(); //选中source元素->拖放到(xOffset,yOffset)位置->释放左键
             action.dragAndDropBy(element, location.x+moveX,location.y).perform();
//            action.dragAndDrop(element,newelement).perform();
            pageSource = driver.getPageSource();
        }
        //更新cookie
        Set<org.openqa.selenium.Cookie> cookies = driver.manage().getCookies();
        Set<Cookie> cookies2 = new HashSet<>();
        for (org.openqa.selenium.Cookie cookie : cookies) {
            cookies2.add((Cookie) new Cookie(cookie.getDomain(), cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getExpiry(), true));
        }
        for (Cookie cookie : cookies2) {
            org.apache.http.cookie.Cookie httpClient = cookie.toHttpClient();
        }
        System.out.println(pageSource);

这样提交的表单确实是有轨迹的,这里移动位置我先写了个固定值,可以由上面图片还原,以及一些开源的图片识别工具识别出位置。以上应该就能解决这个滑动验证码了

时间: 2024-10-04 17:18:43

selenium处理极验滑动验证码的相关文章

破解极验滑动验证码

阅读目录 一 介绍 二 实现 三 说明 一 介绍 一些网站会在正常的账号密码认证之外加一些验证码,以此来明确地区分人/机行为,从一定程度上达到反爬的效果,对于简单的校验码Tesserocr就可以搞定,如下 但一些网站加入了滑动验证码,最典型的要属于极验滑动认证了,极验官网:http://www.geetest.com/,下图是极验的登录界面 现在极验验证码已经更新到了 3.0 版本,截至 2017 年 7 月全球已有十六万家企业正在使用极验,每天服务响应超过四亿次,广泛应用于直播视频.金融服务.

95行代码极验滑动验证码?是远远不够的!大牛石锤!

一直以来,极验坚持的理念是:醉心技术,以不变之变以应万变.通过不断地钻研技术,升级产品,每日迭代更新,全网联动联防.在攻防过程中,始终将对手甩在身后,我们团队始终坚守着,因为我们相信行动才是最好的回应. 所以,在我们看来,大家围绕着"行为验证"安全产品而展开的相关技术细节讨论,是对我们最大的推动,极验"行为验证"的成功离不开大家的建言献策. "行为验证"本质上是一个人工智能产品 人工智能决策演示效果 我们还会从多个维度对用户的交互行为进行采集,一

极验滑动验证码

import timefrom io import BytesIOfrom PIL import Imagefrom selenium import webdriverfrom selenium.webdriver import ActionChainsfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.s

极验滑块坐标识别(一)

一:介绍 一些网站为了区分人机行为,在网站的一些操作上添加验证码机制,来实现反爬虫. 目前比较常见的验证码类型有: 1:传统式验证码 主要通过用户输入图片中的字母,数字,汉字等来验证. 特点:简单易操作,人机交互性较好,但安全系数比较低. 目前通过机器学习技术对传统验证码的识别率已经可以达到90%以上. 2:行为式验证码 行为式验证码是一种较为流行的验证码.从字面来理解,就是通过用户的操作行为来完成验证,而无需去读懂扭曲的图片文字.常见的有两种:拖动式与点触式. 特点:操作简单,体验好,但容易被

极验验证码破解之selenium

这一篇写完很久了,因为识别率一直很低,没办法拿出来见大家,所以一直隐藏着,今天终于可以拿出来见见阳光了. 哈喽,大家好,我是星星在线,我又来了,今天给大家带来的是极验验证码的selenium破解之法,是不是有点小激动呢,小伙伴们等不了了,让我们赶紧直入主题吧. 虎嗅网注册 这次我们是拿虎嗅开刀,注册账号的时候需要滑动图片到缺口位置,这种验证码我们现在也经常遇到,这个就不用详细介绍了吧 针对这种验证码我们首先确定了使用selenium模拟滑动破解方式,selenium鼠标移动点击拖动都比较简单,那

极验验证码的破解2-图片还原和滑块位置求解

上一章我们讨论了破解极验验证码的思路和步骤,这一章我将介绍如何还原两张背景图和求解滑块的目标位置. 一.图片还原 我们首先看看页面上给了我们什么参数: 这个是完整的背景图(fullbg)的页面元素,可以看到他们都是来自于同一张原图,只是截取的位置不同.上图红框就是该小图片在原图中的位置,每一张小图片都是10个像素宽,58个像素高,我们再来看看原图: 确实很乱,根本看不出什么东西.如果我们把这个原图下载下来,然后按照页面上的参数截取一个个10像素宽,58像素高的小图片拼接在一起便可以得到完整的背景

极验验证码的破解4-执行破解

经过以上的铺垫,我们就差最后一步了-破解!首选我们来分析一下要做的事情: 1.加载包含验证码的页面,当然是用我们前面讲的phantomaJS来加载啦,因为极验验证码是依赖于js渲染的,我们必须等页面完全渲染完成后再执行拖动 2.收集一些页面的参数发送到java后台服务计算滑块的目标位移并接受结果 3.通过js模拟鼠标事件来实现滑块的移动 4.输出验证结果 好,让我们一步步来讲解如果实现上面的目标. 我们首先新建一个js文件,就叫做geetest_refresh.js好了,我们首先写一些样板代码,

极验验证码 破解

本文主要提供目前极验的识别思路. 极验验证码主要分为4步. 1/ 还原验证图片.通过分析CSS,发现是固定位置,把一张图片分成若干份,按照指定顺序重新排列,所以难度不大. 2/ 还原好图片后,找出2张图片的差异,即bg(验证图)和fullbg(全图).这个难度也不大,按像素或者按块去扫描.设定一个阈值,当2个图片块或像素的差异值高于这个阈值的时候,就横向向右再扫描几个像素,例如10个,如果这10个像素里面有7个都高于这个像素.那个这个像素所在图片的X坐标,就是我们要的坐标点.根据这种方式,识别坐

极验验证码的破解-开篇

    近几年有个拖动解锁的验证码风头很盛,用过12306的人就知道,它有段时间用的就是这个拖动解锁的验证码,据说就是极验验证码,虽然现在12306的验证码变成了看图识画,安全性和趣味性大大提高,但是也还是被万能的大神破了.由此看来天下没有破不了的验证码,只要功夫深,防火墙也能磨成针.     好了,今天我们来探讨一下极验验证码的破解,这也是我最近一段时间的研究成果.首先声明一下:本博客所讨论的内容仅限于技术研究,请勿用于商业用途,否则后果自负.     我打算分成几个章节来讨论极验验证码所采用