爬虫技术-滑块验证码
滑块验证码
1. 滑块简介

注:重点是识别滑块缺口,测出需要拖动的距离
1.1 核心步骤
-
从服务器随机取一张图片,并对图片上的随机
x,y
坐标和宽高一块区域抠图; -
根据步骤一的坐标和宽高,使用二维数组保存原图上抠图区域的像素点坐标;
-
根据步骤二的坐标点,对原图的抠图区域的颜色进行处理。
-
完成以上步骤之后得到两张图(扣下来的方块图,带有抠图区域阴影的原图),将这两张图和抠图区域的y坐标传到前台,前端在移动方块验证时,将移动后的x坐标传递到后台与原来的x坐标作比较,如果在阈值内则验证通过。
-
请求验证的步骤:前台向后台发起请求,后台随机一张图片做处理将处理完的两张图片的
base64
,抠图y坐标和token
(token为后台缓存验证码的唯一token
,可以用缓存和分布式缓存)返回给前台。 -
前台滑动图片将
x
坐标和token
作为参数请求后台验证,服务器根据token
取出x
坐标与参数的x进行比较。
1.2 突破规则
这类验证码可以使用 selenium
操作浏览器拖拽滑块来进行破解,难点两个,一个如何确定拖拽到的位置,另一个是避开人机识别(反爬虫)。
首先我们先看看,确定滑块验证码需要拖拽的位移距离
有三种方式
- 人工智能机器学习,确定滑块位置
- 通过完整图片与缺失滑块的图片进行像素对比,确定滑块位置
- 边缘检测算法,确定位置
各有优缺点。人工智能机器学习,确定滑块位置,需要进行训练比较麻烦,所以我们主要看后面两种。
对比完整图片与缺失滑块的图片
1.3 验证码图片处理
-
使用浏览器技术提取滑块图片,进行处理
# 提取背景图 document.getElementsByClassName('geetest_canvas_bg geetest_absolute')[0].toDataURL('image/png') document.getElementsByClassName('geetest_canvas_fullbg geetest_fade geetest_absolute')[0].toDataURL('image/png') # 保存图片 import base64,io images = q_qt.split(',')[1] images = base64.b64decode(images) images = Image.open(io.BytesIO(images)) images.save('q_qg.png')
1.4 背景滑块识别
- 这里使用开源的技术
ddddocr
进行滑块的识别
import ddddocr def text_dis(): slide = ddddocr.DdddOcr(det=False, ocr=False) with open('bg.png', 'rb') as f: target_bytes = f.read() with open('zg.png', 'rb') as f: background_bytes = f.read() res = slide.slide_comparison(target_bytes, background_bytes) print(res)
2 OPENCV
处理滑块
opencv
是一个跨平台计算机视觉和机器学习软件库,支持Linux、windows操作系统。
一般来说,图像是一个标准的矩形,有着宽度(width)和高度(height)。而矩阵有着行(row)和列(column),矩阵的操作在数学和计算机中的处理都很常见且成熟,于是很自然的就把图像作为一个矩阵,把对图像的操作转换成对矩阵的操作,实际上所有的图像处理工具都是这么做的
2.1 cv
库讲解
2.1.1 环境安装
pip install opencv-python
运行时报错:AttributeError: partially initialized module 'cv2' has no attribute '_registerMatType' (most likely due to a circular import)
解决
原因:版本太高
解决办法:
1、首先卸载:
pip uninstall opencv-python pip uninstall opencv-contrib-python
2、只安装低版本的opencv-contrib-python
pip install opencv_python==3.4.10.37
使用whl
包安装
链接:https://pan.baidu.com/s/1KZd6VX-YsQjwiPoIXF1G5g 提取码:jlh1
2.2 CV
使用
2.2.1 读取图片
- 防止闪退 这个函数是在一个给定的时间内(单位ms)等待用户按键触发;如果用户没有按下 键,则接续等待(循环)
def read_img(): img = cv.imread('op_test.jpg') print(img.shape) cv.imshow('image',img) cv.waitKey()
2.2.2 读取灰度
def read_img1(): img = cv.imread('op_test.jpg') # 图像灰度化 image = cv.cvtColor(img, cv.COLOR_BGR2GRAY) print(image.shape) cv.imshow('gray', image) cv.waitKey() # 防止闪退
2.2.3 摄像头操作
def read_video(): cap = cv.VideoCapture(0) # 如果有一个摄像头就用0,大于一个用1或者其他数字 cap.set(3, 640) # 设置长度,序号是3 cap.set(4, 480) # 设置宽度,序号是4 cap.set(10, 200) # 设置亮度,序号是10q while True: success, img = cap.read() if success: cv.imshow("Video", img) if cv.waitKey(1) & 0xFF == ord('q'): break else: cv.destroyAllWindows() break
2.3 使用cv
处理滑块
地址:https://passport.jd.com/new/login.aspx
2.3.1 处理code
from io import BytesIO import requests import cv2 from PIL import Image import numpy as np def get_dis(): # 京东的滑块 res = requests.get('https://iv.jd.com/slide/g.html?appId=1604ebb2287&scene=login&product=click-bind-suspend&e=PHMXTEAUGERCMBUAY2PXCENHW4KCWFS7AGHE3JYXMA4XXOOS5Z27CTBDBGC7IDQSAPSN5MT7XMVC4R5SYEPW5TJYQI&lang=zh_CN') patch = res.json().get('patch') bg = res.json().get('bg') import base64 bg1 = base64.b64decode(bg) patch1 = base64.b64decode(patch) open('jd-bg1.png','wb').write(bg1) # 读取二进制图片 image = np.array(Image.open(BytesIO(bg1))) gap = np.array(Image.open(BytesIO(patch1))) # 转换颜色通道,这里为什么要BGR转为RGB,因为np.array转换pillow的图像的结果就是BGR格式的 image1 = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) gap1 = cv2.cvtColor(gap, cv2.COLOR_BGR2RGB) # 转为灰度图 image_gray = cv2.cvtColor(image1.copy(), cv2.COLOR_BGR2GRAY) gap_gray = cv2.cvtColor(gap1.copy(), cv2.COLOR_BGR2GRAY) # 模板匹配 result = cv2.matchTemplate(image_gray, gap_gray, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) print(min_val, max_val, min_loc, max_loc) # 获取最大相关的x,y x, y = min_loc print(x, y)
3. 极验滑块实战
import base64 import time from selenium import webdriver from selenium.webdriver import ActionChains from selenium.webdriver.common.by import By from urllib import request import cv2,random import ddddocr def text_dis(bg,fg): slide = ddddocr.DdddOcr(det=False, ocr=False) with open(bg, 'rb') as f: target_bytes = f.read() with open(fg, 'rb') as f: background_bytes = f.read() res = slide.slide_comparison(target_bytes, background_bytes) return res.get('target')[0] def get_slide(): options = webdriver.ChromeOptions() # 对于老版本的浏览器不行 options.add_argument('--disable-blink-features=AutomationControlled') driver = webdriver.Chrome(chrome_options=options) driver.maximize_window() driver.get('https://www.geetest.com/demo/slide-bind.html') # 输入框输入账号和密码 driver.find_element(By.ID,'username').send_keys('13535353535') driver.find_element(By.ID,'password').send_keys('123123123') # driver.find_element(By.ID,'btn').click() time.sleep(2) driver.find_element(By.CSS_SELECTOR,'div.btn').click() time.sleep(2) img_src = driver.execute_script( 'return document.getElementsByClassName("geetest_canvas_bg geetest_absolute")[0].toDataURL("image/png");') im_base64 = img_src.split(',')[1] im_bytes = base64.b64decode(im_base64) with open('./bg.png', 'wb') as f: f.write(im_bytes) temp = driver.execute_script( "return document.getElementsByClassName('geetest_canvas_fullbg geetest_fade geetest_absolute')[0].toDataURL('image/png');") temp_base64 = temp.split(',')[1] temp_bytes = base64.b64decode(temp_base64) with open('./temp.png', 'wb') as f: f.write(temp_bytes) distance = text_dis('bg.png', 'temp.png') # 拖动滑块 slide = driver.find_element(By.CSS_SELECTOR, 'div.geetest_slider_button') action_chains = webdriver.ActionChains(driver) # 点击,准备拖拽 action_chains.click_and_hold(slide) action_chains.pause(0.2) action_chains.move_by_offset(distance - 10, 0) action_chains.pause(0.8) action_chains.move_by_offset(10, 0) action_chains.pause(1.4) action_chains.move_by_offset(-10, 0) action_chains.release() action_chains.perform() time.sleep(20) get_slide() ''' 2、鼠标操作 click --- 鼠标左键点击(可以指定或不指定元素对象) click_and_hold --- 鼠标左键点击但不释放(可以指定或不指定元素对象) release --- 释放鼠标点击动作(可以指定或不指定在目标元素对象上释放) context_click --- 鼠标右键点击(可以指定或不指定元素对象) double_click --- 鼠标左键双击(可以指定或不指定元素对象) drag_and_drop --- 鼠标左键在两个元素之间拖拽 drag_and_drop_by_offset --- 鼠标左键拖拽元素到目标偏移位置 move_by_offset --- 鼠标移动指定偏移 move_to_element --- 鼠标移动到指定元素 move_to_element_with_offset --- 鼠标移动到指定元素的指定偏移位置 1、行为控制 perform --- 执行所有准备好的Action reset_actions --- 清空所有准备好的Action # 该方法在 selenium 3.141.0版本不生效 pause --- 设置Action之间的动作时间间隔 '''
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)