老咸鱼

老咸鱼 查看完整档案

西安编辑  |  填写毕业院校  |  填写所在公司/组织 www.saltedfish.space 编辑
编辑

一条老咸鱼

个人动态

老咸鱼 关注了用户 · 4月7日

nero @neronero

前端工程师

个人网站: https://www.neroht.com

微信公众号: 一口一个前端

关注 1884

老咸鱼 赞了文章 · 2019-10-22

OpenCV识别企鹅滑块验证码

前言

废话
滑块验证码破解是一直都想搞的项目,毕竟多数网站都会采用滑块验证码,于是最近在修改论文的闲暇之余把这事儿给解决了。要搞现在的滑块验证码绕不开图像处理,图像处理当然是首推OpenCV-Python啦!当然我的OpenCV非常菜(P.S.两天速成不敢保证代码质量),发现问题就直接指出嘛,不用走流程啦!

环境
首先需要一个python,然后安装opencv的python库,如下:
pip install opencv-python
然后测试一下是否可用,如下:

import cv2 as cv
import numpy as np

if __name__ == '__main__':
    img = np.ones((200, 200, 3), np.uint8) * 255
    cv.rectangle(img, (50, 50), (150, 150), (0, 0, 255), 2)
    cv.imshow('test', img)
    cv.waitKey(0)
    cv.destroyAllWindows()

正常的话就会如下显示:
图片描述

OpenCV的使用
相关的API我也是边用边查的,用得也是相当生疏!具体的常用方法大家只好自行百度了,我就不献丑了!

实现原理及方法

腾讯滑块验证
这次搞得目标就是腾讯滑块验证码,调用腾讯滑块这个接口的网站还是挺多的,比如非常好用的在线画图网站ProcessOn,其中滑块验证部分类似这样子的:
图片描述

抓个包发现只有滑块图和带缺口的图,如下:
图片描述
破解滑块验证码最为关键的地方在于找到滑块缺口的位置,找到缺口位置后就可以利用Selenium模拟拖动滑块到指定位置实现破解,之前的老办法就是将完整图的像素点和带缺口图的像素点进行比较从而得到缺口位置,但是现在一般不会将完整图暴露给我们,所以只有在带有缺口的图上进行处理。我这里一共有两种方案进行缺口位置识别,一种是基于模板匹配的,另一种是基于轮廓检测的,下面会细讲两种方案的实现方法。

模板匹配识别缺口
具体是实现过程如下:
1.处理滑块的图片

  • 灰度化滑块图片
  • 处理一下滑块图中滑块的外圈
  • 使用inRange二值化滑块图
  • 使用开运算去除白色噪点

运行结果如下所示(左侧为原始滑块,右侧为处理后的滑块):
图片描述

2.处理带缺口的图片

  • 先来个高斯滤波去噪
  • 灰度化带缺口图
  • 使用阈值二值化该图

运行结果如下所示(左侧为原始图,右侧为处理后的图):
图片描述

3.进行模板匹配
调用模板匹配API并圈出匹配上的区域,结果如下所示:
图片描述

警告警告警告
这种方法的缺口识别率在50%左右,很大一部分原因是滑块图的背景为纯白色,这在匹配时会产生很大的干扰,要是能将滑块图的背景变为透明,正确的匹配率可以达到90%以上

如果大家有任何将滑块图的背景变为透明的办法,可以留言到评论区,我真的万分感谢!!!下面是现阶段的实现代码:

# encoding:utf-8
import cv2 as cv
import numpy as np


# 对滑块进行二值化处理
def handle_img1(image):
    kernel = np.ones((8, 8), np.uint8)  # 去滑块的前景噪声内核
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    width, heigth = gray.shape
    for h in range(heigth):
        for w in range(width):
            if gray[w, h] == 0:
                gray[w, h] = 96
    # cv.imshow('gray', gray)
    binary = cv.inRange(gray, 96, 96)
    res = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel)  # 开运算去除白色噪点
    # cv.imshow('res', res)
    return res


# 模板匹配(用于寻找缺口有点误差)
def template_match(img_target, img_template):
    tpl = handle_img1(img_template)  # 误差来源就在于滑块的背景图为白色
    blurred = cv.GaussianBlur(img_target, (3, 3), 0)  # 目标图高斯滤波
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
    ret, target = cv.threshold(gray, 127, 255, cv.THRESH_BINARY)  # 目标图二值化
    # cv.imshow("template", tpl)
    # cv.imshow("target", target)
    method = cv.TM_CCOEFF_NORMED
    width, height = tpl.shape[:2]
    result = cv.matchTemplate(target, tpl, method)
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
    left_up = max_loc
    right_down = (left_up[0] + height, left_up[1] + width)
    cv.rectangle(img_target, left_up, right_down, (0, 0, 255), 2)
    cv.imshow('res', img_target)


if __name__ == '__main__':
    img0 = cv.imread('./demo/3/hycdn_3.jpg')
    img1 = cv.imread('./demo/3/hycdn_3_2.png')
    template_match(img0, img1)
    cv.waitKey(0)
    cv.destroyAllWindows()

轮廓检测识别缺口
基于轮廓检测缺口的思路简单很多,加上合理的条件识别率在95%以上,实现过程如下:

  • 带缺口图高斯模糊去噪
  • (200,400)的阈值做Canny边缘检测
  • 寻找轮廓
  • 对已有的轮廓做约束,比如轮廓的面积范围,轮廓的周长范围

多个匹配结果如下:
图片描述
图片描述
图片描述
图片描述

实现代码如下:

# encoding:utf-8
import cv2 as cv


def get_pos(image):
    blurred = cv.GaussianBlur(image, (5, 5), 0)
    canny = cv.Canny(blurred, 200, 400)
    contours, hierarchy = cv.findContours(canny, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    for i, contour in enumerate(contours):
        M = cv.moments(contour)
        if M['m00'] == 0:
            cx = cy = 0
        else:
            cx, cy = M['m10'] / M['m00'], M['m01'] / M['m00']
        if 6000 < cv.contourArea(contour) < 8000 and 370 < cv.arcLength(contour, True) < 390:
            if cx < 400:
                continue
            x, y, w, h = cv.boundingRect(contour)  # 外接矩形
            cv.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
            cv.imshow('image', image)
            return x
    return 0


if __name__ == '__main__':
    img0 = cv.imread('./demo/4/hycdn_4.jpg')
    get_pos(img0)
    cv.waitKey(0)
    cv.destroyAllWindows()

遗留问题

问题1
如何将滑块图的纯白背景变为透明背景?

问题2
使用Selenium和轨迹算法拖动滑块时将滑块拖出左侧的范围之外,轨迹算法是先加速后减速整体是向前移动的,按道理来说不可能往回走,但是模拟拖动的时候会出现滑块向后拖动且拖出范围的现象,这问题如何解决?
图片描述

有知道上述问题如何解决的小伙伴,期待你的留言或评论!!!

END

查看原文

赞 6 收藏 4 评论 0

老咸鱼 赞了回答 · 2018-10-09

解决如何理解animation-fill-mode及其使用?

假设有一个盒子,HTML:

<div class="box"></div>

CSS如下:


.box{
    transform: translateY(0);
}
.box.on{
    animation: move 1s;
}

@keyframes move{
    from{transform: translateY(-50px)}
    to  {transform: translateY( 50px)}
}

使用图片来表示 translateY 的值与 时间 的关系:

  • 横轴为表示 时间,为 0 时表示动画开始的时间,也就是向 box 加上 on 类名的时间,横轴一格表示 0.5s

  • 纵轴表示translateY的值,为 0 时表示 translateY 的值为 0,纵轴一格表示 50px

  1. animation-fill-mode: none
    animation-fill-mode: none

  2. animation-fill-mode: backwards
    animation-fill-mode: before

  3. animation-fill-mode: forwards
    animation-fill-mode: after

  4. animation-fill-mode: both
    animation-fill-mode: both

关注 14 回答 3

老咸鱼 关注了标签 · 2018-09-29

golang

Go语言是谷歌2009发布的第二款开源编程语言。Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。
Go语言是谷歌推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发Go,是因为过去10多年间软件开发的难度令人沮丧。Go是谷歌2009发布的第二款编程语言。

七牛云存储CEO许式伟出版《Go语言编程
go语言翻译项目 http://code.google.com/p/gola...
《go编程导读》 http://code.google.com/p/ac-m...
golang的官方文档 http://golang.org/doc/docs.html
golang windows上安装 http://code.google.com/p/gomi...

关注 26301

老咸鱼 回答了问题 · 2018-09-17

webpack optimization 里的 maxInitialRequests 配置项是啥意思?

如果配置了 runtimeChunk(将webpack runtime单独抽离出来),那么maxInitialRequest就是代码分割以后,除去runtime所能生成的最多脚本数目

否则是就是能生成的最多脚本数目

关注 3 回答 2

老咸鱼 提出了问题 · 2018-08-11

create-react-app如何配置打包代码的目标浏览器browserslist?

之前自己写webpack配置 在package.json配置browserslist字段就可以了
请问create-react-app如何配置?

关注 1 回答 0

老咸鱼 赞了文章 · 2018-02-24

移动web端模拟hover效果

hover在PC端的用户体验中扮演着很重要的角色,那么移动web端我们又该如何增强这方面的用户体验呢?

下面我简单的在移动web端模拟了下hover的效果。

效果预览

请在移动端打开源码

核心代码

//按钮点击效果
$(document).on("touchstart", ".action-btn:not(.disable)", function (e) {
    var $this = $(this);
    var flag = true;
    //遍历子类
    $this.find("*").each(function () {
        //查看有没有子类触发过active动作
        if ($(this).hasClass("active")) flag = false;
    });
    //如果子类已经触发了active动作,父类则取消active触发操作
    if (flag) $this.addClass("active");

});
$(document).on("touchmove", ".action-btn:not(.disable)", function (e) {
    if ($(this).hasClass("active")) $(this).removeClass("active");
});
$(document).on("touchend", ".action-btn:not(.disable)", function (e) {
    if ($(this).hasClass("active")) $(this).removeClass("active");
});

代码是基于jQuery的

实现原理

基于touchstart、touchmove、touchend这三个事件,动态增删class。

默认只对含有action-btn class且不含有disable class的对象生效

使用方法

场景1

普通列表点击

clipboard.png

<ul class="items">
    <li class="action-btn">item1</li>
    <li class="action-btn active">item2</li>
    <li class="action-btn">item3</li>
    <li class="action-btn">item4</li>
    <li class="action-btn">item5</li>
</ul>

只需要给列表添加上action-btn class以及提供相应的active class。

场景2

复杂列表点击

clipboard.png

<ul class="items">
    <li class="action-btn">
        item0
        <span class="action-btn action-delete">X</span>
    </li>
    <li class="action-btn">item1</li>
    <li class="action-btn">item2</li>
    <li class="action-btn">item3</li>
    <li class="action-btn">item4</li>
</ul>

效果:点击列表时,触发列表点击效果,点击小叉时,触发小叉点击效果,小叉所在列不触发点击效果。

注意:无论小叉是否有点击效果(即active class),都需要给小叉添加action-btn class。即:当列和列的子元素都有点击逻辑的时候,都需要给它们添加action-btn class,否则会触发父类元素的点击效果。

其他

上面只是在移动web端对hover进行了简单的模拟,还有很多不足的地方。例如:当用户滑动列表时,滑动开始触点所在的列的点击效果会一闪而过。这个是因为点击效果的触发条件是touchstart。我也有尝试在触发touchstart时,延迟一定时间后判断是否触发过touchmove,没有触发的话才触发点击效果。但是在android上表现不佳,所以没有贴出类。

后续我会结合我的这篇文章10行代码搞定移动web端自定义tap事件中的tap事件进行效果优化。

文章有什么不对的地方,望大家指正。大家有什么好的实现方法,欢迎交流!

查看原文

赞 5 收藏 7 评论 7

老咸鱼 收藏了文章 · 2018-02-24

如何让 H5 体验接近 APP:(一)触摸反馈

触摸反馈

要说互联网发展趋势,必然会提及一个词汇:H5。从H5游戏,H5站点,H5营销等等。H5跨平台的特性极大地降低了开发成本和推广难度,同时也带来了一个问题: 如何让h5的体验能达到app一样呢?让我们先来看一组对比(京东APP对比京东H5):

图片描述图片描述

在h5页中,手指接触到列表项时,列表项没有任何反应。而在app中,手指刚接触到列表项时,列表项则从白色背景变为灰色背景。这种交互反馈几乎可以在所有移动端APP中看见,甚至可以说,交互反馈已经成为一种用户习惯。相较之下,h5页虽然有着跨平台的优势,但在细节处理上就差了很多,并且这种交互反馈h5并没有原生支持。react native官方文档有这么一段介绍:

Tappable Components
Tappable components should provide feedback that show the user what is handling their touch, and what will happen when they lift their finger. The user should also be able to cancel a tap by dragging their finger away.

这段介绍主要是说,原生APP组件中,“可点击组件”就应该对用户的操作做出及时反馈。下面一段话更是直接指出了为什么"web" app doesn't feel 'native'。

TouchableWithoutFeedback
Do not use unless you have a very good reason. All the elements that respond to press should have a visual feedback when touched. This is one of the primary reason a "web" app doesn't feel "native".

综上所述,我们在开发h5页面的时候,很有必要给页面一些可点击元素加上一些触摸反馈,这样可以大幅度提升页面的整体体验,使h5页体验更为接近APP。去哪网的h5首页便是这么做的:

去哪网h5首页截图

那么,如何在页面上加入这样的反馈呢?目前了解到的有三种方案,总结如下:

active 伪类

这种方式大多数前端童鞋都能联想到,因为PC web就是这样定义这种反馈的,那么在移动端,这个方案如何呢?我们先来看看w3c对:active的定义:

the-user-action-pseudo-classes-hover-act
The :active pseudo-class applies while an element is being activated by the user. For example, between the times the user presses the mouse button and releases it. On systems with more than one mouse button, :active applies only to the primary or primary activation button (typically the "left" mouse button), and any aliases thereof.

可以看到,w3c标准里对它的描述都是基于mouse事件的,完全没有说明如何支持touch事件。而正是由于标准对此并没有一个准确定义,浏览器对此的理解和实际支持也是参差不齐。

在实际应用中,active伪类在移动端的表现也不是太好,在ios系统中甚至需要"hack"才能正常使用。若仔细看MDN对active伪类介绍,会发现下面这一段话:

MDN :active
[1] By default, Safari Mobile does not use the :active state unless there is a touchstart event handler on the relevant element or on the <body>.

也就是说,在iOS中,我们需要绑定一个touchstart事件来激活这一行为。代码如下:

document.addEventListener('touchstart', function(){});

经过反复测试,得出结论如下:

  1. 安卓机型上触发反馈会有延迟。和click的300ms延迟一样。

  2. ios上按住反馈元素后再将手指移出元素,反馈效果依然还在。(正常情况,手指移出元素应当取消反馈效果)

测试demo: http://www.dearhaoge.com/touchFeedback/demo/delay-test.html

a 标签包裹

在移动端,有个还在草案中的属性-webkit-tap-highlight-color,定义了点击一个超链接显示的颜色。MDN上描述如下:

-webkit-tap-highlight-color
-webkit-tap-highlight-color is a non-standard CSS property that sets the color of the highlight that appears over a link while it's being tapped. The highlighting indicates to the user that their tap is being successfully recognized, and indicates which element they're tapping on.

所以,我们可以在需要反馈的元素上包裹一层a标签,然后设置这个属性。缺点是只能设置颜色和透明图(rgba)。如果想要设置一些动画效果(比如去哪网首页的缩放效果),这个方案也是不适用的。

自定义添加 class

第三个方法通过自定义touch事件来触发反馈,具体方法如下文所示:

press and hold

在touchstart触发的时候,给元素加上class(比如图中是波纹效果)并且在手指持续放在元素上的时候保持class不被移除。

Moving out or leave

touchmove移出元素或者触发滚动条时移除class。当然,touchend和touchcancel也必须移除反馈class。

总结

如果只是想要简单实现的话,可以选择前两种方案,配置相对简单。追求良好体验的童鞋推荐第三种方案,第三种方案整体思想不是很复杂,但也不能对所有的交互元素都单独配置一次,这样也有失代码的优雅。

经过思考和折腾,本人提出了一个方案-->touchFeedback.js,在用户体验和开发体验之间取了一个平衡,这里是一些使用touchFeedback.js做的反馈效果(PC需要模拟手机查看):一些有趣的反馈效果

项目地址: https://github.com/backToNature/touchFeedback

查看原文

老咸鱼 提出了问题 · 2018-01-15

解决SVG path宽度高度计算问题

我想要做一个半径50的1/4圆弧 用path 发现实际显示和100 100的circle大小一致 尺寸却显示45 45,请问path的宽度高度怎么计算的?

图片描述

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>SVG</title>
  <style>
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    svg {
      width: 100px;
      height: 100px;
    }
    circle, path{
      transition: stroke-dasharray 0.25s linear;
    }
  </style>
</head>

<body>
  <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
      <linearGradient x1="0" y1="0" x2="0" y2="1" id="gradient">
        <stop offset="0%" stop-color="#43ECF8"></stop>
        <stop offset="50%" stop-color="#E8F843"></stop>        
        <stop offset="100%" stop-color="#1CF7E6"></stop>
      </linearGradient>
    </defs>
      <circle cx="50" cy="50" r="50" fill="url(#gradient)"/>
      <path class="circle" d="M50,5  A45,45 0 0,1 95,50"
      stroke="#cccc00"stroke-width="10" fill="none"/>
  </svg>
</body>

</html>

关注 1 回答 1

老咸鱼 提出了问题 · 2017-12-26

如何解决input placeholder和输入内容居中问题?

先看两张图:placeholder 和 输入的内容高度明显不一致,输入的内容往下移了一部分 如何解决?

placeholder

图片描述
页面结构:

<div class="input-container">
   <input type='text' placeholder='最多3个字符 支持汉字 英文数字组合' />
    <span class="taken">被占用了</span>
</div>
.input-container {
      position: relative;
      height: 40px;
      background: #FCFCFC;
      color: #333333;
      border-radius: 6px;
      margin: 0 13% 0 10%;
      margin-top: percent(15px, 325px);
      text-align: left;
      border: 2px solid #FF9D9D;
      display: flex;
      flex-direction: row;
      flex-wrap: nowrap;
      justify-content: space-between;
      align-items: center;
      input {
        background: rgba(230, 176, 176, 0);
        margin-left: 10px;
        flex: 1;
        line-height: normal;
        font-size: 12px;
        color: #333333;
      }
      .taken {
        font-size: 12px;
        padding-left: 5px;
        padding-right: 10px;
        color: #DC5151;
      }
    }

关注 3 回答 2

认证与成就

  • 获得 13 次点赞
  • 获得 50 枚徽章 获得 0 枚金徽章, 获得 16 枚银徽章, 获得 34 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2016-09-19
个人主页被 902 人浏览