爬虫技术-滑块验证码_尘世风
滑块验证码
1. 滑块简介

注:重点是识别滑块缺口,测出需要拖动的距离
1.1 核心步骤
从服务器随机取一张图片,并对图片上的随机x,y
坐标和宽高一块区域抠图;
根据步骤一的坐标和宽高,使用二维数组保存原图上抠图区域的像素点坐标;
根据步骤二的坐标点,对原图的抠图区域的颜色进行处理。
完成以上步骤之后得到两张图(扣下来的方块图,带有抠图区域阴影的原图),将这两张图和抠图区域的y坐标传到前台,前端在移动方块验证时,将移动后的x坐标传递到后台与原来的x坐标作比较,如果在阈值内则验证通过。
请求验证的步骤:前台向后台发起请求,后台随机一张图片做处理将处理完的两张图片的base64
,抠图y坐标和token
(token为后台缓存验证码的唯一token
,可以用缓存和分布式缓存)返回给前台。
前台滑动图片将x
坐标和token
作为参数请求后台验证,服务器根据token
取出x
坐标与参数的x进行比较。
1.2 突破规则
这类验证码可以使用 selenium
操作浏览器拖拽滑块来进行破解,难点两个,一个如何确定拖拽到的位置,另一个是避开人机识别(反爬虫)。
首先我们先看看,确定滑块验证码需要拖拽的位移距离
有三种方式
人工智能机器学习,确定滑块位置通过完整图片与缺失滑块的图片进行像素对比,确定滑块位置边缘检测算法,确定位置各有优缺点。人工智能机器学习,确定滑块位置,需要进行训练比较麻烦,所以我们主要看后面两种。
对比完整图片与缺失滑块的图片
1.3 验证码图片处理
站点:https://www.geetest.com/demo/
使用浏览器技术提取滑块图片,进行处理
# 提取背景图
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之间的动作时间间隔
'''
相关文章
- 设计模式之职责链模式(责任链模式)_来自上海的这位朋友
- Vue路由+Vue脚手架(详细教程)幼儿园难度_邢?兵_
- 程序员眼中的Linux操作系统??初识指令_终为?NULL
- JavaWeb笔记(五)后端(Thymeleaf)(Tomcat类加载机制)(编写图书管理系统)_Viktoriae_thymeleaf图书管理系统
- Spring中自动注入的两种方式_白胡子永远
- 【JavaWeb】之JSTL & EL表达式_′Code_Wang
- 大数据计算能力 CPU、GPU 和 DPU 有何不同_AI架构师易筋_gpu大数据
- 【学生管理系统】班级管理_陶然同学
- 注解开发:spring的强项(1)_yyy言者
- 七大排序算法?图文详解(插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序)_渴望力量的土狗
- HTTP协议详解_一只咸鱼。。_http协议
- 使用IDEA创建第一个Web项目(集成本地Tomcat)_白小筠
- vue3 hook自动导入_前端不秃头
- m基于FPGA的半带滤波器verilog设计,对比普通结构以及乘法器复用结构(含FPGA,matlab,文档及操作录像)_我爱C编程_fpga乘法器复用
- Artifact 项目:war exploded: Error during artifact deployment. See server log for details.解决办法(总结三种办法)_
- 面试官灵魂拷问:if语句执行完else语句真的不会再执行吗?_冰 河_if执行了还会执行else吗