过某开源滑动验证码
今天早上我有一点空闲时间,想着回顾一下前几天在某查询网站遇到的滑动验证码,以免时间久了忘记了。那个网站可能使用的是较早版本的开源滑块验证码系统tianai-captcha
,但我不确定是否正确。
整体思路:
获取背景大图和模板小图,用ddddocr
识别缺口位置,模拟人滑动,从通过了验证的载荷来看,主要是模拟形成这个trackList
。
基本步骤:
1、获取背景图与模板小图,这个容易,试着滑动一下,从图中接口可以得到backgroundImage
和templateImage
。
将获取的图片base64解码保存到本地,保存图片时要注意“固定尺寸”与“渲染大小”之间的关系。
# 将base64编码的图转换为图片
def decode_base64_to_image(base64_string, output_filename, target_size=None):
# 分割base64字符串,去掉前缀(如果有的话)
base64_data = base64_string.split(',')[1] if ',' in base64_string else base64_string
# 解码base64字符串
image_data = base64.b64decode(base64_data)
# 使用BytesIO将字节数据转为图像
image = Image.open(BytesIO(image_data))
# 如果指定了尺寸,调整图像大小
if target_size:
image = image.resize(target_size, Image.LANCZOS)
# 保存图像到本地文件
image.save(output_filename)
def get_image_id():
url = "http://xxx.xxx.xxx/x_xxxx/gen"
params = {
"type": "SLIDER"
}
data = '^^{^}^'.encode('unicode_escape')
response = session.post(url, headers=headers, cookies=cookies, params=params, data=data, verify=False)
json_data = json.loads(response.text)
backgroundImage = json_data['captcha']['backgroundImage'].split(',')[1]
templateImage = json_data['captcha']['templateImage'].split(',')[1]
# # 保存图片到本地文件
decode_base64_to_image(backgroundImage, "backgroundImage.jpg", (300, 180)) #注意这里的尺寸是原图的 1/2
decode_base64_to_image(templateImage, "templateImage.png", (55, 180))
return json_data['id']
2、用ddddocr
识别缺口位置
# 识别偏移量
def get_slider_offset_ddddocr(target, background):
det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
with open(target, 'rb') as f:
target_bytes = f.read()
with open(background, 'rb') as f:
background_bytes = f.read()
res = det.slide_match(target_bytes, background_bytes)
return res
3、得到缺口位置后,模拟滑动(此乃核心部分),程序中随机数区间可以自行调整,以便获得更高的通过率。
def generate_trajectory(x):
trajectory = []
current_x = 0
current_y = 0
current_time = random.randint(824, 3065)
# start with 'down' event
trajectory.append({"x": current_x, "y": current_y, "type": "down", "t": current_time})
# add 'move' events
while current_x < x:
current_time += random.randint(10, 30)
move_x = random.randint(1, int(max(1, (x - current_x) / 20))) # adjust move speed based on distance left
move_y = random.randint(-2, 2) # random minor variance in y
current_x += move_x
current_y = move_y
# ensure current_x does not exceed target x
if current_x > x:
current_x = x
trajectory.append({"x": current_x, "y": current_y, "type": "move", "t": current_time})
# end with 'up' event
current_time += random.randint(100, 1000) # randomly determine time taken to lift finger
trajectory.append({"x": current_x, "y": current_y, "type": "up", "t": current_time})
return trajectory
4、组装数据提交,我就按照载荷数据的形式组装的,没有去校验各个参数能否更简单。
def generate_data(trajectory, id):
import datetime
# 当前时间为滑动开始时间
start_time = datetime.datetime.now()
# 将轨迹时间转换为合适的时间戳,并取毫秒部分
updated_trajectory = []
for event in trajectory:
# 计算事件时间
event_time = start_time + datetime.timedelta(milliseconds=event['t'])
# 获取毫秒部分的最后三位数字,转为三位字符串
milli_str = ('000' + str(event_time.microsecond // 1000))[-3:]
updated_event = {
"x": event['x'],
"y": event['y'],
"type": event['type'],
"t": milli_str # 只保留时间的最后三位
}
updated_trajectory.append(updated_event)
# 设置滑动结束时间
end_time = start_time + datetime.timedelta(milliseconds=trajectory[-1]['t'])
# 将时间格式化
start_sliding_time = start_time.isoformat() + "Z"
end_sliding_time = end_time.isoformat() + "Z"
# 提交的数据对象
from datetime import datetime
data = {
"id": id,
"data": {
"bgImageWidth": 300,
"bgImageHeight": 180,
"startSlidingTime": datetime.fromisoformat(start_sliding_time.replace('Z', '+00:00')).strftime(
'%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z',
"endSlidingTime": datetime.fromisoformat(end_sliding_time.replace('Z', '+00:00')).strftime(
'%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z',
"trackList": updated_trajectory
}
}
return json.dumps(data, separators=(',', ':'))
5、如果通过校验返回如下状态,可以检测中的某一个Key,如果没有通过,重新获取。
{"code":200,"data":{"id":"get_image_id函数所获取的id"},"msg":"OK","success":true}
整个程序通过率90%吧。在生成轨迹时,当时我滑动了大约近二十组数据,将它提供给gpt-4o,让它进行了分析。 以下轨迹分析的程序,你可以根据它分析的结果,来确定generate_trajectory()中随机数。以下是分析程序。
'''
@File : 轨迹
@Author : Bobo
@Blog : https://blog.csdn.net/chinagaobo
@Note : This code is for learning and communication purposes only
'''
import json
guiji1 = [] #校验通过后的轨迹列表
guiji2= []
guiji3 = []
guiji4= []
...
def analyze_trajectories(trajectories):
for i, trajectory in enumerate(trajectories):
print(f"Analysis of track {i + 1}:")
for j in range(1, len(trajectory)):
dx = trajectory[j]['x'] - trajectory[j - 1]['x']
dy = trajectory[j]['y'] - trajectory[j - 1]['y']
dt = trajectory[j]['t'] - trajectory[j - 1]['t']
print(f"Step {j} -> dx: {dx}, dy: {dy}, dt: {dt}")
print()
# 将四组轨迹放入列表
trajectories = [guiji1, guiji2, guiji3, guiji4]
# 分析轨迹
analyze_trajectories(trajectories)
整篇文章给出了解决此种滑动验证的思路及代码,如果您有好的思路,还请不吝赐教。