验证码识别如此简单 - 带带弟弟 OCR

本贴最后更新于 607 天前,其中的信息可能已经物是人非

在做web自动化的时候大家一定碰到过各式各样的验证码,验证码作为一种安全机制,可以有效防止暴力破解密码、发帖、灌水、刷票等,大家在做web自动化的时候应该有碰到验证码这个难题,一般我们可以和开发沟通请求他们的帮助:去掉验证码或者设置一个万能验证码,而如果开发不帮忙我们该如何去解决呢?

ddddocr

ddddocr是由sml2h3开发的专为验证码厂商进行对自家新版本验证码难易强度进行验证的一个python库,其由作者与kerlomz共同合作完成,通过大批量生成随机数据后进行深度网络训练,本身并非针对任何一家验证码厂商而制作,本库使用效果完全靠玄学,可能可以识别,可能不能识别。

项目地址:https://github.com/sml2h3/ddddocr

安装:

pip install ddddocr

如果安装速度比较慢的话可以指定国内镜像服务器:

pip install ddddocr -i https://pypi.tuna.tsinghua.edu.cn/simple/

接下来以几种常见的验证码识别场景来看看ddddocr的能力如何

图文验证码

这里摘取ddddocr官网的样例来测试下:

image.png

代码如下:

import ddddocr

ocr = ddddocr.DdddOcr()
with open('111.png', 'rb') as f:
    image = f.read()
res = ocr.classification(image)
print(res)

image.png

ddddocr对于文字、数字这种验证码识别准确率还是挺高的

滑块验证码

目前非常多项目采用的是滑块验证码方式,此种破解方式的关键点在于如何获取滑块到背景缺口图的距离

111.gif

滑块验证码实战

以https://www.kgcaptcha.com这个网站上面的验证码demo为例,选择滑块验证码,通过F12查看验证码区域元素信息。

1、验证码背景图

可以看到验证码背景图数据是在style属性中,并且直接是base64编码的数据,所以在后面我们需要对其进行base64解码得到原始的图片数据(有些可能是图片url地址,我们需要将其下载下来)。

image.png

2、滑块图片

滑块图片也是base64编码的数据,其背景是透明底色

image.png

接下来看操作(代码):

driver = webdriver.Chrome()
driver.implicitly_wait(5)

driver.get('https://www.kgcaptcha.com/demo/content?t=1')
driver.find_element(By.LINK_TEXT, '弹出式').click()
driver.find_element(By.ID, 'captchaButton').click()
# 获取验证码背景图
bg_pic_style = driver.find_element(By.ID, 'KgBasemap').get_attribute('style')
pattern = re.compile('url\("(.*?)"\)')
# 获取验证码背景图base64编码的数据
bg_src_data = pattern.findall(bg_pic_style)[0]
# base64数据进行解码
bg_src_content = bg_src_data.split(',')[1]
bg_src_data = base64.b64decode(bg_src_content.encode())

# 获取滑块图
slider_pic_data = driver.find_element(By.XPATH, '//*[@id="KgBasemap"]/img[1]').get_attribute('src')
slider_src_content = slider_pic_data.split(',')[1]
# 获取滑块图base64编码的数据
slider_pic_data = base64.b64decode(slider_src_content.encode())

上述代码主要获取验证码背景图和滑块的数据,接下来使用ddddocr来识别验证码背景图中的缺口位置

# 使用ddddocr识别验证码背景图缺口
det = ddddocr.DdddOcr(det=False, ocr=False)
res = det.slide_match(slider_pic_data, bg_src_data, simple_target=True)
print(f'{res}')
distance = res['target'][0]

image.png

target中的四组数据代表的是缺口左上角和右下角的位置信息(X、Y轴),所以我们这里只需要拿到第一个149数据即可

拿到距离信息之后,我们还需要通过距离生成滑动轨迹信息,不能直接从开始点直接滑动到终止点(有些网站会判定为脚本操作)

def get_move_track(distance):
    """
    获取滑动轨迹
    不能直接从开始点直接滑动到终止点(有些网站会判定为脚本操作)
    根据滑动距离生成滑动轨迹,开始慢->中间快->最后慢
    :param distance:滑动距离
    :return:滑动轨迹列表
    """
    remain_distance = distance
    track_list = []
    while remain_distance > 0:
        ratio = (distance - remain_distance) / distance
        if ratio < 0.1:
            span = 4
        elif ratio < 0.9:
            span = 16
        else:
            span = 2
        track_list.append(span)
        remain_distance -= span
    return track_list

最后通过Selenium的ActionChains进行滑动即可:

# 使用selenium Actionchains进行滑动
slide_button_element = driver.find_element(By.XPATH, '//*[@id="KgSlide"]/div[3]')
ActionChains(driver).click_and_hold(slide_button_element).perform()
time.sleep(0.5)

for i in get_move_track(distance):
    time.sleep(0.01)
    ActionChains(driver).move_by_offset(i, 0).perform()
ActionChains(driver).release(on_element=slide_button_element).perform()

time.sleep(5)
driver.quit()

来看看最后的效果:

222.gif

1 操作
shakebabe 在 2023-03-03 15:03:18 更新了该帖
回帖
请输入回帖内容 ...