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

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

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

  1. private void initWebClient() {
  2. if (webClient != null) {
  3. return;
  4. }
  5. webClient = new WebClient(BrowserVersion.FIREFOX_24);
  6. webClient.getOptions().setProxyConfig(new ProxyConfig("127.0.0.1",8888));
  7. webClient.getOptions().setActiveXNative(true);
  8. webClient.getOptions().setUseInsecureSSL(true); // 配置证书
  9. webClient.getOptions().setJavaScriptEnabled(true);
  10. webClient.getOptions().setCssEnabled(true);
  11. webClient.setCssErrorHandler(new SilentCssErrorHandler());
  12. webClient.getOptions().setThrowExceptionOnScriptError(false);
  13. webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
  14. CookieManager cookieManager = new CookieManager();
  15. List<org.apache.http.cookie.Cookie> httpCookies = client.getCookies();//其方式获取的cookie
  16. for (org.apache.http.cookie.Cookie cookie : httpCookies) {
  17. cookieManager.addCookie(new com.gargoylesoftware.htmlunit.util.Cookie(cookie));
  18. }
  19. webClient.setCookieManager(cookieManager);
  20. }

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

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

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

  1. private void gePageInfor(HtmlPage page) {
  2. String[] img_slice={"div", "class", "gt_cut_fullbg_slice"};
  3. String[] img_bg_slice={"div", "class", "gt_cut_bg_slice"};
  4. HtmlDivision div = (HtmlDivision) page.getElementById("captcha");
  5. int deCAPTCHA = 0;
  6. try {
  7. byte[] img_slice_binary = client.get(getImgUrl(img_slice, div, true)).getBinary();//获取图片byte
  8. byte[] img_bg_slice_binary = client.get(getImgUrl(img_bg_slice, div, false)).getBinary();
  9. //获取还原后的图片
  10. BufferedImage geetestImg = ImgTest.getGeetestImg(img_slice_binary, ImgTest.imgArray);
  11. BufferedImage geetestImg2 = ImgTest.getGeetestImg(img_bg_slice_binary, ImgTest.imgArray);
  12. //获得图片移动位置(目前还有问题,需改用第三方图片识别)
  13. deCAPTCHA =ImgTest.deCAPTCHA(geetestImg,geetestImg2);
  14. System.out.println(deCAPTCHA);
  15. } catch (IOException | FetchException e) {
  16. e.printStackTrace();
  17. }
  18. HtmlDivision div_slider_knob = get_div_slider_knob(page,"gt_slider_knob gt_show");//获取要移动div
  19. HtmlPage mouseOver = (HtmlPage) div_slider_knob.mouseOver();
  20. HtmlPage mouseDownPage = (HtmlPage)div_slider_knob.mouseDown();
  21. div_slider_knob = get_div_slider_knob(mouseDownPage,"gt_slider_knob gt_show moving");
  22. mouseMoveX(deCAPTCHA, div_slider_knob, mouseDownPage);
  23. HtmlPage newPage =(HtmlPage)div_slider_knob.mouseOver();
  24. // newPage =(HtmlPage)div_slider_knob.mouseDown();
  25. System.out.println(newPage.asXml());
  26. div = (HtmlDivision)newPage.getElementById("captcha");
  27. HtmlElement htmlElement = div.getElementsByAttribute("div", "class", "gt_slice gt_show moving").get(0);
  28. System.out.println(htmlElement);
  29. newPage =(HtmlPage)div_slider_knob.mouseUp();//触发js,轨迹没有生成
  30. System.out.println("---------------");
  31. System.out.println(newPage.asXml());
  32. if (newPage.getElementById("captcha")!=null) {//错误重试
  33. //gePageInfor(newPage);
  34. }
  35. }
  36.  
  37. private void mouseMoveX(int deCAPTCHA, HtmlDivision div_slider_knob, HtmlPage mouseDown) {
  38. MouseEvent mouseEvent = new MouseEvent(div_slider_knob, MouseEvent.TYPE_MOUSE_MOVE, false, false, false, MouseEvent.BUTTON_LEFT);
  39. mouseEvent.setClientX( mouseEvent.getClientX()+((deCAPTCHA!=0)?deCAPTCHA:99)); //移动x坐标
  40. ScriptResult scriptResult = mouseDown.getDocumentElement().fireEvent(mouseEvent);
  41. }
  42. private HtmlDivision get_div_slider_knob(HtmlPage page,String classString) {
  43. return (HtmlDivision)(((HtmlDivision) page.getElementById("captcha")).getElementsByAttribute("div", "class", classString).get(0));
  44. }
  45.  
  46. private String getImgUrl(String[] img_slice, HtmlDivision div, boolean isNeedCheckPostion) {
  47. String url ="";
  48. int[] postion = new int[2];
  49. boolean empty = div.getElementsByAttribute(img_slice[0],img_slice[1],img_slice[2]).isEmpty();
  50. if (div.hasChildNodes() && !empty) {
  51. List<HtmlElement> elementsByAttribute = div.getElementsByAttribute(img_slice[0],img_slice[1],img_slice[2]);
  52. for(int i = 0;i<elementsByAttribute.size();i++){
  53. HtmlDivision div_img = (HtmlDivision)elementsByAttribute.get(i);
  54. String style = div_img.getAttribute("style");
  55. String[] imge_url_position = style.split(";");
  56. if(StringUtils.isBlank(url)){//确认url
  57. url = StringUtils.replacePattern(imge_url_position[0], ".*\\(", "").replace(")", "");
  58. }
  59. if (isNeedCheckPostion) {//确认图片切割postion,两张图切割方式一样 background-position: -157px -58px
  60. // String[] positionS = StringUtils.split(StringUtils.remove(imge_url_position[1], "px").replace("-", "").replaceAll(".*:", ""), null);
  61. String[] positionS = StringUtils.split(StringUtils.removePattern(imge_url_position[1], "[^\\d+ \\s]"),null);
  62. postion[0] = Integer.parseInt(positionS[0]);
  63. postion[1] = Integer.parseInt(positionS[1]);
  64. int[] is = ImgTest.imgArray[i];
  65. if (is[0]!=postion[0]||is[1]!=postion[1]) {
  66. logger.debug("更新分割postion");
  67. ImgTest.imgArray[i] = postion;
  68. }
  69. System.out.println(ImgTest.imgArray);
  70. isNeedCheckPostion= false;
  71. }
  72. }
  73. }
  74. return url;
  75. }

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

  1. public static BufferedImage getGeetestImg(byte[] binary, int[][] imgArray) throws IOException {
  2. BufferedImage img = ImageIO.read(new ByteArrayInputStream(binary));
  3. List<BufferedImage> list = new ArrayList<>();
  4. for (int i=0;i< imgArray.length;i++) {
  5. BufferedImage subimage = img.getSubimage(imgArray[i][0], imgArray[i][1], 10, 58);
  6. list.add(subimage);
  7. // ImageIO.write(subimage, "jpg", new File("d:\\image\\imgs"+i+".jpg"));
  8. }
  9. BufferedImage mergeImageUp = null;
  10. BufferedImage mergeImageDown = null;
  11. int mid = list.size()>>>1;
  12. for (int i = 0; i <mid-1 ; i++) {
  13. mergeImageUp = mergeImage(mergeImageUp==null?list.get(i):mergeImageUp, list.get(i+1), true);
  14. }
  15. for(int i = mid;i<list.size()-1;i++){
  16. mergeImageDown = mergeImage(mergeImageDown==null?list.get(i):mergeImageDown,list.get(i+1), true);
  17. }
  18. img = mergeImage(mergeImageUp, mergeImageDown, false);
  19. return img;
  20. }
  21. public static BufferedImage mergeImage(BufferedImage img1,
  22. BufferedImage img2, boolean isHorizontal) throws IOException {
  23. int w1 = img1.getWidth();
  24. int h1 = img1.getHeight();
  25. int w2 = img2.getWidth();
  26. int h2 = img2.getHeight();
  27. // 从图片中读取RGB
  28. int[] ImageArrayOne = new int[w1 * h1];
  29. ImageArrayOne = img1.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 逐行扫描图像中各个像素的RGB到数组中
  30. int[] ImageArrayTwo = new int[w2 * h2];
  31. ImageArrayTwo = img2.getRGB(0, 0, w2, h2, ImageArrayTwo, 0, w2);
  32.  
  33. // 生成新图片
  34. BufferedImage DestImage = null;
  35. if (isHorizontal) { // 水平方向合并
  36. DestImage = new BufferedImage(w1+w2, h1, BufferedImage.TYPE_INT_RGB);
  37. DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
  38. DestImage.setRGB(w1, 0, w2, h2, ImageArrayTwo, 0, w2);
  39. } else { // 垂直方向合并
  40. DestImage = new BufferedImage(w1, h1 + h2,
  41. BufferedImage.TYPE_INT_RGB);
  42. DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
  43. DestImage.setRGB(0, h1, w2, h2, ImageArrayTwo, 0, w2); // 设置下半部分的RGB
  44. }
  45.  
  46. return DestImage;
  47. }

2.使用selenium

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

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

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

好吧,于是调用chrome吧

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

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

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

  1. selenium+java破解极验滑动验证码的示例代码

    转自: https://www.jianshu.com/p/1466f1ba3275 selenium+java破解极验滑动验证码 卧颜沉默 关注 2017.08.15 20:07* 字数 3085  ...

  2. Python——破解极验滑动验证码

    极验滑动验证码 以上图片是最典型的要属于极验滑动认证了,极验官网:http://www.geetest.com/. 现在极验验证码已经更新到了 3.0 版本,截至 2017 年 7 月全球已有十六万家 ...

  3. python验证码识别(2)极验滑动验证码识别

    目录 一:极验滑动验证码简介 二:极验滑动验证码识别思路 三:极验验证码识别 一:极验滑动验证码简介   近些年来出现了一些新型验证码,不想旧的验证码对人类不友好,但是这种验证码对于代码来说识别难度上 ...

  4. Python 破解极验滑动验证码

    Python 破解极验滑动验证码 测试开发社区  1周前 阅读目录 极验滑动验证码 实现 位移移动需要的基础知识 对比两张图片,找出缺口 获得图片 按照位移移动 详细代码 回到顶部 极验滑动验证码 以 ...

  5. thinkphp整合系列之极验滑动验证码

    对于建站的筒子们来说:垃圾广告真是让人深恶痛绝:为了清净:搞个难以识别的验证码吧:又被用户各种吐槽:直到后来出现了极验这个滑动的验证码:这真是一个体验好安全高的方案:官网:http://www.gee ...

  6. vue_drf之实现极验滑动验证码

    一.需求 1,场景 我们在很多登录和注册场景里,为了避免某些恶意攻击程序,我们会添加一些验证码,也就是行为验证,让我们相信现在是一个人在交互,而不是一段爬虫程序.现在市面上用的比较多的,比较流行的是极 ...

  7. selenium+java破解极验滑动验证码

    摘要 分析验证码素材图片混淆原理,并采用selenium模拟人拖动滑块过程,进而破解验证码. 人工验证的过程 打开威锋网注册页面(https://passport.feng.com/?r=user/r ...

  8. luffy之多条件登录与极验滑动验证码

    多条件登录 JWT扩展的登录视图,在收到用户名与密码时,也是调用Django的认证系统中提供的authenticate()来检查用户名与密码是否正确. 我们可以通过修改Django认证系统的认证后端( ...

  9. thinkphp整合系列之极验滑动验证码geetest

    给一个央企做官网,登录模块用的thinkphp验证码类.但是2019-6-10到12号,国家要求央企检验官网漏洞,防止黑客攻击,正直贸易战激烈升级时期,所以各事业单位很重视官网安全性,于是乎集团总部就 ...

随机推荐

  1. OGRE的学习资源

    本文介绍从哪儿开始学习OGRE(Object-Oriented Graphics Rendering Engine的简称,又叫做OGRE 3D),如何在网上找寻OGRE的学习资源. 首先是wikipe ...

  2. (实用篇)微信支付扫码支付php版

    本文实例为大家分享了php微信扫码支付源码,供大家参考,具体内容如下 代码中包含四个文件createUrl.php.ArrayToXML.php.returnGoodsUrl.php.notifyUr ...

  3. HTML 列表详解

    1.有序列表    有序列表是编号列表,用于对网页中的某些内容进行编号排列,以便使读者清晰地了解每行的顺序.在HTML中插入有序列表是通过<ol>和<li>标签来实现的.首标签 ...

  4. .lib文件 .h文件 .dll文件

    .lib代表的是静态数据连接库,在windows系统中起到链接程序和函数的作用,存放的是函数的是函数调用的信息,是obj文件的集合.相当于linux中的.a或.0. .so文件.lib文件是不对外公开 ...

  5. MySql分组函数-Group by与having理解

    注意:select 后的字段,必须要么包含在group by中,要么包含在having 后的聚合函数里. 1. GROUP BY 是分组查询, 一般 GROUP BY 是和聚合函数配合使用 group ...

  6. 2016HUAS_ACM暑假集训4D - 计数,排列

    一个错排公式的基础应用. 大致题意:求n个数的错误排列方式.(每个都要错) 在这里先贴一下错排公式:D(1)=0:D(2)=1:D(n)=(n-1)*(D(n-1)+D(n-2)) 它的推导也非常有意 ...

  7. wiseinstall 制做安装包小记

    好久没写博客了..昨天未来的自己给自己托了个梦,说以后你肯定会忘了你今天白天是怎么制做安装包的,所以又来记录了..希望以后可以保持这个好习惯. 程序安装完后,可执行程序是 Wise32.exe 第一步 ...

  8. Windows下面如何建立多个Django虚拟环境

    Linux 安装请见另一篇博客 http://www.cnblogs.com/zhaoyingjie/p/6180758.html 1.安装 virtualenv 2.安装virtualenvwrap ...

  9. (转) Playing FPS games with deep reinforcement learning

    Playing FPS games with deep reinforcement learning 博文转自:https://blog.acolyer.org/2016/11/23/playing- ...

  10. 关于post请求超出最大长度

    这是因为asp.net默认限制最大上传文件大小为4096kb,而我上传了6000kb+所以超出了限制,需要修改项目的web.config文件即可解决,可以将最大文件长度设置为你需要的长度,我这里设置为 ...