不想用selenium处理滑块验证码?教你用cv2解决

cv2解决滑块验证码验证

  • opencv-python安装
  • 案例场景
  • cv2实战

opencv-python安装

虽然cv2是直接通过导入cv2包使用,但是它不是通过import cv2安装,需要通过pip install opencv-python安装,直接pip安装可能会比较慢,可以使用pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple安装

案例场景

不想用selenium处理滑块验证码?教你用cv2解决_第1张图片
不想用selenium处理滑块验证码?教你用cv2解决_第2张图片
当点击滑块时,会显示缺口背景图和方块,将方块移动到背景图缺口处就能实现验证,我们可以看看验证通过整个过程的请求包来判断它的验证逻辑
不想用selenium处理滑块验证码?教你用cv2解决_第3张图片
当我们点击滑块时,会去请求方块和背景图,当我们滑动并停止滑动滑块后,会发起一个验证请求,推测这个请求会把我们的动作传给后端验证,而我们的动作直接产生的就是坐标的变化,一般验证码验证会根据两种方式验证,坐标参数验证滑动轨迹验证码坐标参数验证是传递一个滑块停止后的坐标,而滑动轨迹验证码是传递一个坐标数组,记录滑块整个滑动周期变化的坐标。

我们查看异步请求验证这个包,看看它传递的参数便可以知道属于哪种验证逻辑
不想用selenium处理滑块验证码?教你用cv2解决_第4张图片
观察参数可以确定它传递的是滑块移动停止时的坐标,那怎么拿到这个坐标呢,dragleft我们假定是方块左侧坐标的距离,dragright我们假定是方块右侧坐标的距离,然后模拟一下查看style样式中left的变化。
不想用selenium处理滑块验证码?教你用cv2解决_第5张图片
多次观察可以确定,这个left便是dragleft的值,而dragrightdragleft要大32,这样我们只要知道dragleft的值便能确定dragright了。

cv2实战

使用cv2计算图片差异位置的坐标,我们需要拿到背景图片和方块图片,通过对比背景图片和方块图片之间的联系与差异从而定义差异的坐标。

cv2识别代码

# -*- coding: utf-8 -*-
from PIL import Image
from io import BytesIO
import numpy as np
import cv2


def identify_gap(bg, tp):
    """
    :param bg: 背景图片
    :param tp: 缺口图片
    :return int
    """
    # 读取背景图片和缺口图片
    bg_img = get_cv2_img(bg)  # 背景图片
    tp_img = get_cv2_img(tp)  # 缺口图片
    if type(bg_img) == str or type(tp_img) == str:
        print('图片格式存在问题,无法用cv2读取!')
        return

    # 识别图片边缘
    bg_edge = cv2.Canny(bg_img, 100, 200)
    tp_edge = cv2.Canny(tp_img, 100, 200)

    # 转换图片格式
    bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
    tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)

    # 缺口匹配
    res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

    print(min_val, max_val, min_loc, max_loc)

    # 返回缺口的X坐标
    return max_loc[0]


def get_cv2_img(img_object):
    if type(img_object) == str:
        cv_img = cv2.imread(img_object)
    elif type(img_object) == bytes:
        image_data = BytesIO(img_object)
        img = Image.open(image_data)
        cv_img = np.asarray(img)
    else:
        cv_img = None
    return cv_img


if __name__ == '__main__':
    print(identify_gap('背景图本地路径', '方块本地路径'))
    print(identify_gap('背景图二进制流', '方块二进制流'))

测试识别结果

# -*- coding: utf-8 -*-
import requests

from sxSpider.check_open_cv.cv2_gap import identify_gap

header = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'Accept-Encoding': 'gzip, deflate, br',
    'Cookie': 'lnReGnsFlag=0; tbbysb=N; tbzbsy=N; LESB_SESSION=ZF9tq3-Avn6LnFE80mstxwI3QTwoHZdyPrz_FWuwwpPu_As9a2fy!46501968',
    'Host': 'etax.ningxia.chinatax.gov.cn',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
}

before_img_url = 'https://etax.ningxia.chinatax.gov.cn/download.sword?ctrl=CheckcodeCtrl_initBgPic&0.1601673354750519&bgPicPath=/wsbs/images/bg4_style2.jpg&id=dragCheckCode'
after_img_url = 'https://etax.ningxia.chinatax.gov.cn/download.sword?ctrl=CheckcodeCtrl_initcutPic&0.14661519005791934&bgPicPath=/wsbs/images/bg4_style2.jpg&id=dragCheckCode'

before_img_resp = requests.get(before_img_url, headers=header)
before_img = before_img_resp.content
with open('image/before.png', 'wb') as fb:
    fb.write(before_img_resp.content)
after_img_resp = requests.get(after_img_url, headers=header)
after_img = after_img_resp.content
with open('image/after.png', 'wb') as fb:
    fb.write(after_img_resp.content)

drag_left = identify_gap(before_img, after_img)
drag_right = drag_left + 32
print(drag_left, drag_right)

如果想看看识别的到底对不对,可以圈出识别位置

# 绘制方框
th,tw = tp_pic.shape[:2]
tl = max_loc  # 左上角点的坐标
br = (tl[0] + tw, tl[1] + th)  # 右下角点的坐标
cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2)  # 绘制矩形
cv2.imwrite('存储路径', bg_img)  # 保存在本地

不想用selenium处理滑块验证码?教你用cv2解决_第6张图片
ok,分享就到这里了!

你可能感兴趣的:(爬虫讲解,python,opencv)