Python对旋转图片验证码的识别和破解(一)

Python对旋转图片验证码的识别和破解

本文主要使用python + selenium来破解旋转突破的验证码;其中用到numpy和OpenCV(CV2)来进行图片拼接,转换,遮罩,识别等,共分为三个部分:
Python对旋转图片验证码的识别和破解(一)_第1张图片

(一)旋转图片的正确位置

旋转突破最难的在于如何计算旋转角度,我们不可能用人工智能的方式来自动识别图片摆正的位置,那么我们只能遍历可能出现的图片并保存。通常遍历有两种可能:

  1. HTML代码中有所有图片的链接或Base64图片数据
  2. 程序自动运行,抓取图片,分析图片的异同,然后手工调正

第一种方法

图片1的方法很简单,比如51fapiao开出的发票url,当需要下载或浏览发票时,会有一个验证码,这个验证随机出现滑动验证码或者旋转验证码,但检查其出现验证码的html时,发现它保存有所有正确验证码图片的url列表

# 使用正则表达式取出所有的正确图像的url
html = driver.page_source
url_list = re.findall(
    "\'(http[^\']+?\d+?\.(?:jpg|png))\'", html, re.S)
# 旋转图片通常是一个正方形,假设宽高分别为w,h(通常w = h)
# 为了识别的方便,需要将所有图像拼接到一起,形成一行图像(或1列图像)
n = len(url_list)
img_all = np.zeros((h, w*n), dtype=np.uint8)
n = 0
for img_url in url_list:
    try:
        # 下载图像并载入
        r = requests.get(img_url)
        img_tmp = cv2.imdecode(np.asarray(
            bytearray(r.content), dtype=np.uint8), cv2.IMREAD_COLOR)
    except:
        continue
    # 调整大小,并且启用mask,转为灰度图像
    img_tmp = cv2.resize(img_tmp, (w, h))
    # 将图片用圆形遮罩住(这个稍后讲解)
    img_tmp = cv2.add(img_tmp, np.zeros(
            img_tmp.shape, dtype=np.uint8), mask=mask)
    # 转换为灰度图像
    img_tmp = cv2.cvtColor(
        np.asarray(img_tmp), cv2.COLOR_BGR2GRAY)
    # show(img_tmp)
    # 横向拼为大图
    img_all[:, n*w:(n+1)*w] = img_tmp[:, :]
    n += 1

获取得到的所有图片如下(拼接,缩放为正方形,遮罩并转为灰度)

在这里插入图片描述

第二种方法(万能方法)

刷新屏幕,找到验证码图片的那个元素,然后对图片进行处理:

  • 用圆形遮罩图片
  • 变成灰度

来谈一谈遮罩
验证码通常会有一个背景,然后核心的图像在一个圆形中,这是需要将圆周围的背景图片遮罩住,只比较圆形中心的图片,我们使用OpenCV来进行遮罩的操作

def get_chaptcha_image(driver):
    png_data = driver.find_element_by_tag_name(
        'canvas').screenshot_as_png
    img = cv2.imdecode(np.frombuffer(png_data, dtype=np.uint8), 
        cv2.IMREAD_COLOR)
    h, w = img.shape[:2] # 第一种方法的验证码的高,宽就是从这儿来的

    # 制作圆形mask(仅中间圆形部分通过,其它屏蔽)
    mask = np.zeros((h, w), dtype=np.uint8)
    (centerX, centerY) = (mask.shape[1] // 2, mask.shape[0] // 2)
    white = (255, 255, 255)
    cv2.circle(mask, (centerX, centerY), w//2-1, white, -1)
    # 启用mask并转换图像为灰度
    img = cv2.add(img, np.zeros(
        img.shape, dtype=np.uint8), mask=mask)
    img = cv2.cvtColor(np.asarray(img), cv2.COLOR_BGR2GRAY)
    return img

通过上述操作,我们已经找到了一个验证码图片,然后我们进行下列操作,就可以遍历所有的图像

  • img_all(保存所有图片)
  • 刷新图片,取一个验证码图片
  • 将验证码图片从0~360度旋转,在img_all中查找,如果找到相似度在0.95以上,即认为已经存在这个图片,继续刷新(如果刷新了20次没有找到新的图片则认为所有图片已经找到,停止程序)
  • 将不存在的图片加入到img_all中
  • 人工设别每一个图片的正确位置并调整保存到大图(替换原来图片位置)

核心代码如下

def add_to_img_all(img_all, img):
    '''
    将img拼接到img_all中,返回新的img_all
    '''
    h_all, w_all = img_all.shape[:2]
    h, w = img_all.shape[:2]
    w_new = w_all + w
    img_all_new = np.zeros((h, w_new), dtype=np.uint8)
    img_all_new[:,:w_all,:]=img_all[:,:,:]
    img_all_new[:,w_all:w_all+w,:] = img[:,:,:]
    return img_all_new
def is_existed(img_all, img, semilar = 0.95):
    '''
    在img_all中寻找img,当相似度到达semilar时停止
    参数:
        img_all:
        img:
        semilar:相似度阀值
    返回:    (maxValue, maxLoc, Angle)
        maxValue: 相似度- 0:不相识,1:全相似
        maxLoc:最相似的位置(x,y)
        Angle:转换到最相似的旋转角度
    '''

img = get_chaptcha_image(driver)
img_all = img
h, w = img.shape[:2]
while True:
    driver.refresh()
    img = get_chaptcha_image(driver)
    maxValue, maxLoc, Angle = is_existed(img_all, img
    if maxValue>0.9: # 相似度大于0.9认为它已经存在
        times +=1
        if times>=20:
            break
        else:
            continue
    else:
        times = 0
        img_all = add_to_img_all(img_all, img)


你可能感兴趣的:(Python对旋转图片验证码的识别和破解(一))